feat(ui): warm paper backgrounds + about-modal layout rework
Browse files- Slightly warm background palette (light #fcfbf8, dark #121110) via CSS vars
- About modal: rebalanced 1.5fr/1fr columns, column separator, divided
step list with aligned demos, overline section titles, button-style CTA
- Fix modal body not scrolling when content overflows (flex min-height)
- Fix dark mode never applying to portaled modals (class re-applied on overlay)
- Fix source link in about modal (huggingface/fontmap -> tfrere/fontmap)
Co-authored-by: Cursor <cursoragent@cursor.com>
- build/asset-manifest.json +7 -7
- build/index.html +1 -1
- build/static/css/632.07566e3f.chunk.css +0 -2
- build/static/css/632.07566e3f.chunk.css.map +0 -0
- build/static/css/632.abaca8bf.chunk.css +2 -0
- build/static/css/632.abaca8bf.chunk.css.map +0 -0
- build/static/js/{632.d7330879.chunk.js → 632.2f16deee.chunk.js} +2 -2
- build/static/js/632.2f16deee.chunk.js.map +0 -0
- build/static/js/632.d7330879.chunk.js.map +0 -0
- build/static/js/{main.7e00c86e.js → main.ac7b1f26.js} +0 -0
- build/static/js/{main.7e00c86e.js.LICENSE.txt → main.ac7b1f26.js.LICENSE.txt} +0 -0
- build/static/js/{main.7e00c86e.js.map → main.ac7b1f26.js.map} +0 -0
- src/components/FontMap/components/AboutModal.js +3 -2
- src/components/FontMap/components/IntroModal.js +2 -1
- src/components/FontMap/hooks/useTooltipOptimized.js +4 -4
- src/components/FontMap/styles/about-modal.css +94 -19
- src/components/FontMap/styles/font-details.css +1 -1
- src/components/FontMap/styles/intro-modal.css +4 -0
- src/components/FontMap/styles/tooltip.css +1 -1
- src/components/FontMap/styles/variables.css +10 -10
build/asset-manifest.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
| 1 |
{
|
| 2 |
"files": {
|
| 3 |
"main.css": "./static/css/main.31e68073.css",
|
| 4 |
-
"main.js": "./static/js/main.
|
| 5 |
-
"static/css/632.
|
| 6 |
-
"static/js/632.
|
| 7 |
"static/css/937.4ccdb038.chunk.css": "./static/css/937.4ccdb038.chunk.css",
|
| 8 |
"static/js/937.d1c714a3.chunk.js": "./static/js/937.d1c714a3.chunk.js",
|
| 9 |
"static/js/766.2c07e994.chunk.js": "./static/js/766.2c07e994.chunk.js",
|
| 10 |
"static/js/986.ed3c496b.chunk.js": "./static/js/986.ed3c496b.chunk.js",
|
| 11 |
"index.html": "./index.html",
|
| 12 |
"main.31e68073.css.map": "./static/css/main.31e68073.css.map",
|
| 13 |
-
"main.
|
| 14 |
-
"632.
|
| 15 |
-
"632.
|
| 16 |
"937.4ccdb038.chunk.css.map": "./static/css/937.4ccdb038.chunk.css.map",
|
| 17 |
"937.d1c714a3.chunk.js.map": "./static/js/937.d1c714a3.chunk.js.map",
|
| 18 |
"766.2c07e994.chunk.js.map": "./static/js/766.2c07e994.chunk.js.map",
|
|
@@ -20,6 +20,6 @@
|
|
| 20 |
},
|
| 21 |
"entrypoints": [
|
| 22 |
"static/css/main.31e68073.css",
|
| 23 |
-
"static/js/main.
|
| 24 |
]
|
| 25 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"files": {
|
| 3 |
"main.css": "./static/css/main.31e68073.css",
|
| 4 |
+
"main.js": "./static/js/main.ac7b1f26.js",
|
| 5 |
+
"static/css/632.abaca8bf.chunk.css": "./static/css/632.abaca8bf.chunk.css",
|
| 6 |
+
"static/js/632.2f16deee.chunk.js": "./static/js/632.2f16deee.chunk.js",
|
| 7 |
"static/css/937.4ccdb038.chunk.css": "./static/css/937.4ccdb038.chunk.css",
|
| 8 |
"static/js/937.d1c714a3.chunk.js": "./static/js/937.d1c714a3.chunk.js",
|
| 9 |
"static/js/766.2c07e994.chunk.js": "./static/js/766.2c07e994.chunk.js",
|
| 10 |
"static/js/986.ed3c496b.chunk.js": "./static/js/986.ed3c496b.chunk.js",
|
| 11 |
"index.html": "./index.html",
|
| 12 |
"main.31e68073.css.map": "./static/css/main.31e68073.css.map",
|
| 13 |
+
"main.ac7b1f26.js.map": "./static/js/main.ac7b1f26.js.map",
|
| 14 |
+
"632.abaca8bf.chunk.css.map": "./static/css/632.abaca8bf.chunk.css.map",
|
| 15 |
+
"632.2f16deee.chunk.js.map": "./static/js/632.2f16deee.chunk.js.map",
|
| 16 |
"937.4ccdb038.chunk.css.map": "./static/css/937.4ccdb038.chunk.css.map",
|
| 17 |
"937.d1c714a3.chunk.js.map": "./static/js/937.d1c714a3.chunk.js.map",
|
| 18 |
"766.2c07e994.chunk.js.map": "./static/js/766.2c07e994.chunk.js.map",
|
|
|
|
| 20 |
},
|
| 21 |
"entrypoints": [
|
| 22 |
"static/css/main.31e68073.css",
|
| 23 |
+
"static/js/main.ac7b1f26.js"
|
| 24 |
]
|
| 25 |
}
|
build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Interactive map of 1,100+ Google Fonts organized by visual similarity using FontCLIP + UMAP"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap" rel="stylesheet"><title>FontMap</title><script defer="defer" src="./static/js/main.
|
|
|
|
| 1 |
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Interactive map of 1,100+ Google Fonts organized by visual similarity using FontCLIP + UMAP"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap" rel="stylesheet"><title>FontMap</title><script defer="defer" src="./static/js/main.ac7b1f26.js"></script><link href="./static/css/main.31e68073.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
build/static/css/632.07566e3f.chunk.css
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
:root{--color-bg-primary:#fff;--color-bg-secondary:#f8f9fa;--color-bg-tertiary:#e9ecef;--color-text-primary:#000;--color-text-secondary:#666;--color-text-tertiary:#999;--color-border-primary:#e0e0e0;--color-border-secondary:#d1d5db;--color-accent:#007acc;--color-accent-hover:#005a9e;--color-bg-primary-dark:#000;--color-bg-secondary-dark:#1a1a1a;--color-bg-tertiary-dark:#333;--color-text-primary-dark:#fff;--color-text-secondary-dark:#ccc;--color-text-tertiary-dark:#999;--color-border-primary-dark:#404040;--color-border-secondary-dark:#555;--color-accent-dark:#4fc3f7;--color-accent-hover-dark:#29b6f6;--spacing-xs:4px;--spacing-sm:8px;--spacing-md:12px;--spacing-lg:16px;--spacing-xl:20px;--border-radius-sm:4px;--border-radius-md:6px;--border-radius-lg:8px;--shadow-sm:0 1px 3px #0000001a;--shadow-md:0 2px 6px #0000001a;--shadow-lg:0 4px 12px #0000001a;--transition-fast:0.15s ease;--transition-normal:0.2s ease;--transition-slow:0.3s ease;--overlay-opacity-light:0.6;--overlay-opacity-dark:0.5;--font-logo:"Source Sans Pro","Times New Roman",serif}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fontmap-container{background:var(--color-bg-primary);cursor:default;display:flex;flex-direction:row;height:100vh;margin:0;overflow:hidden;padding:0;position:relative;transition:background-color var(--transition-quick);user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;width:100vw}.fontmap-container.dark-mode{background:var(--color-bg-primary-dark)}.fontmap-container:active{cursor:grabbing}.fontmap-container.zooming{cursor:zoom-in}.sidebar{background:var(--color-bg-secondary);border-right:1px solid var(--color-border-primary);display:flex;flex-direction:column;height:100vh;max-height:100vh;min-width:400px;overflow:hidden;position:relative;width:400px;z-index:2000}.dark-mode .sidebar{background:var(--color-bg-secondary-dark);border-right-color:var(--color-border-primary-dark)}.sidebar-header{border-bottom:1px solid var(--color-border-primary);display:flex;flex-direction:column;flex-shrink:0;gap:var(--spacing-md);min-height:-webkit-fit-content;min-height:fit-content;padding:var(--spacing-lg)}.dark-mode .sidebar-header{border-bottom-color:var(--color-border-primary-dark)}.map-container{height:100%;position:relative;width:100%}.dark-mode .loading-text{color:var(--color-text-secondary-dark)}.map-title{-webkit-text-stroke:16px var(--color-bg-primary);text-stroke:16px var(--color-bg-primary);color:var(--color-text-primary);font-family:var(--font-logo);font-size:32px;font-weight:700;left:20px;letter-spacing:-.02em;margin:0;paint-order:stroke fill;pointer-events:none;position:absolute;position:relative;text-shadow:0 2px 4px #0000001a;top:20px;z-index:100}.map-title:before{-webkit-text-stroke:17px var(--color-border-primary);text-stroke:17px var(--color-border-primary);color:#0000;content:attr(data-text);left:0;position:absolute;top:0;z-index:-1}.dark-mode .map-title{-webkit-text-stroke:16px var(--color-bg-primary-dark);text-stroke:16px var(--color-bg-primary-dark);color:var(--color-text-primary-dark);text-shadow:0 2px 4px #ffffff1a}.dark-mode .map-title:before{-webkit-text-stroke:17px var(--color-border-primary-dark);text-stroke:17px var(--color-border-primary-dark)}.sidebar-content{display:flex;flex:1 1;flex-direction:column;min-height:0;overflow-x:hidden;overflow-y:auto}.sidebar-content .sidebar-header{border-bottom:1px solid var(--color-border-primary);display:flex;flex-direction:column;flex-shrink:0;gap:var(--spacing-md);margin-bottom:var(--spacing-lg);min-height:-webkit-fit-content;min-height:fit-content;padding:var(--spacing-lg)}.dark-mode .sidebar-content .sidebar-header{border-bottom-color:var(--color-border-primary-dark)}.sidebar-footer{align-items:center;background:var(--color-bg-secondary);border-top:1px solid var(--color-border-primary);display:flex;flex-shrink:0;justify-content:space-between;min-height:-webkit-fit-content;min-height:fit-content;padding:var(--spacing-lg)}.dark-mode .sidebar-footer{background:var(--color-bg-secondary-dark);border-top-color:var(--color-border-primary-dark)}.about-link,.source-link{align-items:center;background:none;border:none;border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-md);text-decoration:none;transition:all var(--transition-normal)}.about-link:hover,.source-link:hover{background:var(--color-bg-primary);color:var(--color-text-primary);transform:translateY(-1px)}.dark-mode .about-link,.dark-mode .source-link{color:var(--color-text-secondary-dark)}.dark-mode .about-link:hover,.dark-mode .source-link:hover{background:var(--color-bg-primary-dark);color:var(--color-text-primary-dark)}.main-area{background:var(--color-bg-secondary);display:flex;flex:1 1;flex-direction:column;overflow:hidden;position:relative}.dark-mode .main-area{background:var(--color-bg-secondary-dark)}.fontmap-svg{shape-rendering:geometricPrecision;-webkit-touch-callout:none;cursor:grab;display:block;height:100%;image-rendering:crisp-edges;text-rendering:geometricPrecision;touch-action:none;-webkit-user-select:none;user-select:none;width:100%}.fontmap-svg:active{cursor:grabbing}.font-details-back{display:none}.font-glyph-group,.font-hit-area,.glyph-group{cursor:pointer}.glyph-hitbox{fill:#0000;stroke:none;vector-effect:non-scaling-stroke}.glyph-hitbox:hover,.highlight-group .glyph-hitbox{fill:#00000005;stroke:#00000024;stroke-width:1}.dark-mode .glyph-hitbox:hover,.dark-mode .highlight-group .glyph-hitbox{fill:#ffffff08;stroke:#ffffff2e;stroke-width:1}.font-glyph{shape-rendering:geometricPrecision;image-rendering:crisp-edges;pointer-events:none;text-rendering:geometricPrecision}.viewport-group{will-change:transform}.highlight-group,.viewport-group{shape-rendering:geometricPrecision;image-rendering:crisp-edges;text-rendering:geometricPrecision;transform-origin:0 0}.dark-mode .font-glyph,.dark-mode .font-glyph use{fill:#fff!important;color:#fff!important}.ui-group{pointer-events:none;z-index:100}.loading{color:var(--color-text-secondary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-weight:300;left:50%;letter-spacing:1px;position:absolute;text-transform:uppercase;top:50%;transform:translate(-50%,-50%)}.dark-mode .loading{color:var(--color-text-secondary-dark)}.sidebar-separator{background:var(--color-border-primary);height:1px;margin:var(--spacing-lg) 0}.dark-mode .sidebar-separator{background:var(--color-border-primary-dark)}.category-legend{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;padding:var(--spacing-sm) var(--spacing-md)}.dark-mode .category-legend{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.category-legend-toggle{align-items:center;color:var(--color-text-primary);cursor:pointer;display:flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:10px;font-weight:500;gap:6px;letter-spacing:.3px;line-height:14px;text-transform:uppercase;-webkit-user-select:none;user-select:none;white-space:nowrap}.dark-mode .category-legend-toggle{color:var(--color-text-primary-dark)}.category-legend-toggle input[type=checkbox]{accent-color:var(--color-text-primary);cursor:pointer;height:12px;margin:0;width:12px}.dark-mode .category-legend-toggle input[type=checkbox]{accent-color:var(--color-text-primary-dark)}.category-legend-items{display:flex;flex-wrap:wrap;gap:var(--spacing-xs) var(--spacing-md);margin-top:2px}.category-legend-item{align-items:center;display:flex;gap:6px}.category-legend-dot{border-radius:50%;flex-shrink:0;height:10px;transition:background .2s ease;width:10px}.category-legend-label{color:var(--color-text-secondary);font-size:12px;text-transform:capitalize}.dark-mode .category-legend-label{color:var(--color-text-secondary-dark)}.svg-tooltip{opacity:0;pointer-events:none}.tooltip-html{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;padding:8px}.tooltip-html a:hover{opacity:.7}.font-tooltip{background:var(--color-bg-primary);border:none;border-radius:var(--border-radius-md);box-shadow:var(--shadow-lg);color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:11px;line-height:1.3;max-width:280px;min-width:160px;overflow:hidden;padding:0;pointer-events:none;user-select:none;-webkit-user-select:none}@media (max-width:768px){.font-tooltip-hover{pointer-events:auto}}.tooltip-open-btn{background:var(--color-text-primary);border:1px solid var(--color-text-primary);border-radius:var(--border-radius-sm);color:var(--color-bg-primary);cursor:pointer;display:block;font-family:inherit;font-size:12px;font-weight:600;letter-spacing:.4px;margin:4px 8px 8px;padding:10px 12px;pointer-events:auto;text-transform:uppercase;width:calc(100% - 16px)}.font-tooltip.dark-mode .tooltip-open-btn{background:var(--color-text-primary-dark);border-color:var(--color-text-primary-dark);color:var(--color-bg-primary-dark)}.font-tooltip-selected{border-width:1px;box-shadow:0 8px 32px #0003;z-index:1000!important}.font-tooltip-hover{border:3px solid #fff!important;box-shadow:0 2px 8px #0000001a!important;z-index:1001!important}.dark-mode .font-tooltip-hover{border:3px solid #fff!important;box-shadow:0 2px 8px #0003!important}.simple-tooltip{margin-bottom:0!important;padding:12px 8px;padding-bottom:0!important;text-align:center}.tooltip-font-name{color:var(--color-text-primary);font-size:12px;font-weight:600;text-align:center}.tooltip-sentence-preview{align-items:center;display:flex;justify-content:center}.dark-mode .font-tooltip,.sentence-image,.tooltip-sentence-preview{margin-bottom:0!important;padding-bottom:0!important}.dark-mode .font-tooltip{background:var(--color-bg-primary-dark)!important;border:none!important;color:var(--color-text-primary-dark)!important}.font-tooltip.dark-mode{background:#000!important;border:none!important;color:#fff!important}.dark-mode .tooltip-font-name{color:var(--color-text-primary-dark)!important}.dark-mode .font-tooltip .tooltip-font-name,.font-tooltip.dark-mode .tooltip-font-name{color:#fff!important}.sentence-image{border-radius:var(--border-radius-sm);height:auto;max-width:100%;min-height:40px!important}.dark-mode .font-tooltip-selected .sentence-image,.font-tooltip-hover .sentence-image,.font-tooltip-selected .sentence-image{box-shadow:none}.tooltip-preview-large{background:var(--color-bg-secondary);border-bottom:1px solid var(--color-border-primary);padding:var(--spacing-xl);text-align:center}.dark-mode .tooltip-preview-large{background:var(--color-bg-secondary-dark);border-bottom-color:var(--color-border-primary-dark)}.preview-glyph-large{align-items:center;display:flex;height:80px;justify-content:center}.preview-glyph-large svg{filter:drop-shadow(0 2px 4px rgba(0,0,0,.1))}.dark-mode .preview-glyph-large svg{filter:drop-shadow(0 2px 4px rgba(255,255,255,.1))}.tooltip-content{padding:16px}.tooltip-header{margin-bottom:12px}.font-name{font-size:16px;margin-bottom:4px}.font-category{color:var(--color-text-secondary);font-size:12px;letter-spacing:.5px;text-transform:uppercase}.dark-mode .font-category{color:var(--color-text-secondary-dark)}.tooltip-info{margin-bottom:12px}.info-item{display:flex;font-size:11px;justify-content:space-between;margin-bottom:6px}.info-label{color:var(--color-text-secondary);font-weight:500}.dark-mode .info-label{color:var(--color-text-secondary-dark)}.info-value{color:var(--color-text-primary);font-weight:400}.dark-mode .info-value{color:var(--color-text-primary-dark)}.tooltip-footer{border-top:1px solid var(--color-border-primary);padding-top:var(--spacing-sm)}.dark-mode .tooltip-footer{border-top-color:var(--color-border-primary-dark)}.tooltip-hint{color:var(--color-text-tertiary);font-size:10px;font-style:italic;text-align:center}.dark-mode .tooltip-hint{color:var(--color-text-tertiary-dark)}.font-tooltip{transform:translateY(0)}.dark-mode .tooltip-sentence img,.font-tooltip.dark-mode .sentence-image{filter:invert(1)!important}.font-tooltip .tooltip-spinner{color:var(--color-text-secondary)!important}.font-tooltip.dark-mode .tooltip-spinner{color:var(--color-text-secondary-dark)!important}.dark-mode .font-tooltip svg use,.dark-mode .tooltip-fallback svg use,.font-tooltip.dark-mode svg use{fill:#fff!important;color:#fff!important}.top-controls{align-items:flex-start;display:flex;gap:8px;position:absolute;right:16px;top:16px;z-index:200}.dark-mode-toggle{flex-shrink:0}.toggle-btn{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:500;letter-spacing:.3px;outline:none;padding:var(--spacing-sm) var(--spacing-md);text-transform:uppercase;transition:all var(--transition-normal);-webkit-user-select:none;user-select:none}.toggle-btn:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md);transform:translateY(-1px)}.toggle-btn:active{box-shadow:var(--shadow-sm);transform:translateY(0)}.toggle-btn:focus{border-color:var(--color-accent);box-shadow:0 0 0 2px #007acc33}.dark-mode .toggle-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.dark-mode .toggle-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a}.dark-mode .toggle-btn:focus{border-color:var(--color-accent-dark);box-shadow:0 0 0 2px #4fc3f733}.dataset-selector{flex-shrink:0}.dataset-select{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:500;letter-spacing:.3px;min-width:200px;outline:none;padding:var(--spacing-sm) var(--spacing-md);text-transform:uppercase;transition:all var(--transition-normal)}.dataset-select:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md)}.dataset-select:focus{border-color:var(--color-accent);box-shadow:0 0 0 2px #007acc33}.dark-mode .dataset-select{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.dark-mode .dataset-select:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a}.dark-mode .dataset-select:focus{border-color:var(--color-accent-dark);box-shadow:0 0 0 2px #4fc3f733}.search-section{margin-bottom:0}.search-bar-big .search-input{border-radius:var(--border-radius-lg);font-size:16px;padding:var(--spacing-md) var(--spacing-lg)}.filters-container{align-items:flex-start;background:#0000;border:none;border-radius:0;box-shadow:none;display:flex;flex-direction:column;gap:var(--spacing-xs);margin:var(--spacing-sm) 0 0 0;padding:var(--spacing-sm);width:100%}.filters-label{color:var(--color-text-tertiary);font-size:11px;font-weight:500;letter-spacing:.5px;margin-bottom:2px;text-transform:uppercase}.dark-mode .filters-label{color:var(--color-text-tertiary-dark)}.filters-inline{grid-gap:var(--spacing-xs);color:var(--color-text-secondary);display:grid;font-size:11px;gap:var(--spacing-xs);grid-template-columns:repeat(3,1fr);width:100%}.dark-mode .filters-inline{color:var(--color-text-secondary-dark)}.filter-link{align-items:center;background:var(--color-bg-secondary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-sm);cursor:pointer;display:flex;font-weight:500;gap:3px;justify-content:space-between;min-height:28px;padding:var(--spacing-xs) var(--spacing-sm);text-align:left;transition:all var(--transition-fast)}.filter-link:hover{background:var(--color-bg-tertiary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-sm);color:var(--color-text-primary);transform:translateY(-1px)}.dark-mode .filter-link{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.dark-mode .filter-link:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.filter-link.active{background:var(--color-bg-primary);border-color:var(--color-text-primary);box-shadow:var(--shadow-sm);color:var(--color-text-primary);font-weight:600}.dark-mode .filter-link.active{background:var(--color-bg-primary-dark);border-color:var(--color-text-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.filter-count{background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);color:var(--color-text-secondary);font-size:10px;font-weight:500;min-width:20px;opacity:.7;padding:2px 6px;text-align:center;transition:all var(--transition-fast)}.dark-mode .filter-count{background:var(--color-bg-tertiary-dark);color:var(--color-text-secondary-dark);opacity:.8}.filter-link.active .filter-count{background:var(--color-text-primary);color:var(--color-text-primary);color:var(--color-bg-primary);opacity:1}.dark-mode .filter-link.active .filter-count{background:var(--color-text-primary-dark);color:var(--color-text-primary-dark);color:var(--color-bg-primary-dark)}.search-bar{align-items:center;display:flex;min-width:200px;position:relative}.search-input{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:500;outline:none;padding:var(--spacing-sm) var(--spacing-md);padding-right:10px;transition:all var(--transition-normal);width:100%}.search-input:focus{border-color:var(--color-accent);box-shadow:0 0 0 2px #007acc33}.search-input::placeholder{color:var(--color-text-tertiary)}.search-input.dark{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.search-input.dark:focus{border-color:var(--color-accent-dark);box-shadow:0 0 0 2px #4fc3f733}.search-input.dark::placeholder{color:var(--color-text-tertiary-dark)}.search-controls{align-items:center;display:flex;gap:var(--spacing-xs);position:absolute;right:var(--spacing-sm);top:50%;transform:translateY(-50%);z-index:1}.search-counter{background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);color:var(--color-text-secondary);font-size:10px;font-weight:500;padding:2px 6px;pointer-events:none;transition:all var(--transition-normal)}.search-counter.filtered{background:var(--color-bg-secondary);border:1px solid var(--color-text-secondary);color:var(--color-text-primary)}.search-counter.dark{background:var(--color-bg-tertiary-dark);color:var(--color-text-secondary-dark)}.search-counter.dark.filtered{background:var(--color-bg-secondary-dark);border:1px solid var(--color-text-secondary-dark);color:var(--color-text-primary-dark)}.search-clear{align-items:center;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-tertiary);cursor:pointer;display:flex;justify-content:center;padding:var(--spacing-xs);transition:all var(--transition-fast)}.search-clear:hover{background:var(--color-bg-tertiary);color:var(--color-text-secondary)}.dark-mode .search-clear:hover{background:var(--color-bg-tertiary-dark);color:var(--color-text-secondary-dark)}.bottom-controls{align-items:flex-end;gap:8px;right:16px}.bottom-controls,.focus-hint{bottom:16px;display:flex;position:absolute;z-index:200}.focus-hint{align-items:center;background:#0000;gap:12px;height:36px;left:16px;pointer-events:none;-webkit-user-select:none;user-select:none}.focus-hint-keys{align-items:center;display:flex;gap:4px}.focus-hint kbd{align-items:center;background:#fff;border:1px solid #fff;border-radius:4px;color:#000;display:inline-flex;font-family:inherit;font-size:14px;height:32px;justify-content:center;line-height:1;width:32px}.dark-mode .focus-hint kbd{background:#000;border-color:#fff;color:#fff}.focus-hint-label{color:#000;font-size:12px;letter-spacing:.3px;line-height:36px;text-shadow:0 0 3px #fff,0 0 3px #fff,0 0 3px #fff}.dark-mode .focus-hint-label{color:#fff;text-shadow:0 0 3px #000,0 0 3px #000,0 0 3px #000}.bottom-controls .dark-mode-toggle{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;display:flex;flex-shrink:0;font-family:inherit;justify-content:center;line-height:1;padding:var(--spacing-sm) var(--spacing-md)}.dark-mode .bottom-controls .dark-mode-toggle{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.dark-mode-toggle-icon{align-items:center;display:inline-flex;justify-content:center;transition:transform .5s cubic-bezier(.4,0,.2,1)}.zoom-controls{display:flex;flex-direction:column;gap:var(--spacing-xs)}.zoom-btn{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:10px;font-weight:500;letter-spacing:.3px;min-width:24px;outline:none;padding:var(--spacing-sm) var(--spacing-md);text-align:center;text-transform:uppercase;transition:all var(--transition-normal)}.dark-mode .zoom-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.zoom-btn:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md);transform:translateY(-1px)}.dark-mode .zoom-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a;transform:translateY(-1px)}.zoom-btn.zoom-reset{background:var(--color-text-primary);border-color:var(--color-text-primary);box-shadow:var(--shadow-md);color:var(--color-bg-primary)}.dark-mode .zoom-btn.zoom-reset{background:var(--color-text-primary-dark);border-color:var(--color-text-primary-dark);box-shadow:0 2px 6px #ffffff1a;color:var(--color-bg-primary-dark)}.zoom-btn.zoom-reset:hover{background:var(--color-text-secondary);box-shadow:var(--shadow-lg);color:var(--color-bg-primary);transform:translateY(-1px)}.dark-mode .zoom-btn.zoom-reset:hover{background:var(--color-text-secondary-dark);box-shadow:0 4px 12px #ffffff1a;color:var(--color-bg-primary-dark);transform:translateY(-1px)}.dilation-control{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:var(--spacing-sm);min-width:200px;padding:var(--spacing-md)}.dark-mode .dilation-control{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.dilation-label{align-items:center;display:flex;font-size:12px;font-weight:500;justify-content:space-between;letter-spacing:.3px;text-transform:uppercase}.cache-indicator{font-size:14px;margin-left:var(--spacing-sm);opacity:.7;transition:opacity var(--transition-fast)}.cache-indicator.ready{color:#22c55e;opacity:1}.cache-indicator.loading{animation:pulse 1.5s ease-in-out infinite;color:#f59e0b;opacity:.8}.cache-indicator.not-ready{color:var(--color-text-tertiary);opacity:.5}@keyframes pulse{0%,to{opacity:.8}50%{opacity:.4}}.dark-mode .cache-indicator.ready{color:#4ade80}.dark-mode .cache-indicator.loading{color:#fbbf24}.dark-mode .cache-indicator.not-ready{color:var(--color-text-tertiary-dark)}.label-text{color:var(--color-text-primary)}.dark-mode .label-text{color:var(--color-text-primary-dark)}.label-value{color:var(--color-text-secondary);font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-weight:600}.dark-mode .label-value{color:var(--color-text-secondary-dark)}.dilation-slider-container{display:flex;flex-direction:column;gap:var(--spacing-xs)}.dilation-slider{-webkit-appearance:none;appearance:none;background:var(--color-border-primary);border-radius:2px;cursor:pointer;height:4px;outline:none;transition:all var(--transition-normal);width:100%}.dilation-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-webkit-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.dilation-slider::-webkit-slider-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.dilation-slider::-moz-range-thumb{background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-moz-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.dilation-slider::-moz-range-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.dilation-slider.dark{background:var(--color-border-primary-dark)}.dilation-slider.dark::-webkit-slider-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.dilation-slider.dark::-moz-range-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.slider-labels{color:var(--color-text-secondary);display:flex;font-size:10px;font-weight:500;justify-content:space-between;letter-spacing:.5px;text-transform:uppercase}.dark-mode .slider-labels{color:var(--color-text-secondary-dark)}.slider-label{font-size:10px}.size-control{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:var(--spacing-sm);min-width:200px;padding:var(--spacing-md)}.dark-mode .size-control{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.size-label{align-items:center;display:flex;font-size:12px;font-weight:500;justify-content:space-between;letter-spacing:.3px;text-transform:uppercase}.size-slider-container{display:flex;flex-direction:column;gap:var(--spacing-xs)}.size-slider{-webkit-appearance:none;appearance:none;background:var(--color-border-primary);border-radius:2px;cursor:pointer;height:4px;outline:none;transition:all var(--transition-normal);width:100%}.size-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-webkit-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.size-slider::-webkit-slider-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.size-slider::-moz-range-thumb{background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-moz-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.size-slider::-moz-range-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.size-slider.dark{background:var(--color-border-primary-dark)}.size-slider.dark::-webkit-slider-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.size-slider.dark::-moz-range-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.font-details{display:flex;flex:1 1;flex-direction:column}.font-details-placeholder{align-items:center;color:var(--color-text-secondary);display:flex;flex-direction:column;justify-content:center;min-height:400px;padding:var(--spacing-xl);position:relative;text-align:center}.dark-mode .font-details-placeholder{color:var(--color-text-secondary-dark)}.placeholder-icon{align-items:center;display:flex;justify-content:center;margin-bottom:var(--spacing-xl);opacity:.7;position:relative;transition:all .3s ease;z-index:2}.placeholder-icon svg{color:var(--color-text-tertiary);filter:drop-shadow(0 2px 8px rgba(0,0,0,.1))}.dark-mode .placeholder-icon svg{color:var(--color-text-tertiary-dark);filter:drop-shadow(0 2px 8px rgba(255,255,255,.1))}.placeholder-content{align-items:center;display:flex;flex-direction:column;gap:var(--spacing-md);max-width:320px}.placeholder-content h3{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:24px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0}.dark-mode .placeholder-content h3{color:var(--color-text-primary-dark)}.placeholder-content p{color:var(--color-text-secondary);font-size:16px;font-weight:400;line-height:1.5;margin:0}.dark-mode .placeholder-content p{color:var(--color-text-secondary-dark)}.font-details-header{display:flex;justify-content:flex-end;margin-bottom:var(--spacing-md)}.close-btn{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;display:flex;justify-content:center;padding:var(--spacing-sm);transition:all var(--transition-normal)}.close-btn:hover{background:var(--color-bg-tertiary);border-color:var(--color-border-secondary);color:var(--color-text-primary)}.dark-mode .close-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-secondary-dark)}.dark-mode .close-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);color:var(--color-text-primary-dark)}.font-details-content{display:flex;flex:1 1;flex-direction:column;gap:var(--spacing-lg);padding:0 var(--spacing-lg) var(--spacing-lg) var(--spacing-lg)}.font-preview{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:center;padding:var(--spacing-xl)}.dark-mode .font-preview{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.font-preview-large{align-items:center;background:#0000;border:none;border-radius:0;display:flex;height:100px;justify-content:center;position:relative;transition:all .3s ease;width:100px}.font-preview-large:hover{transform:translateY(-2px)}.dark-mode .font-preview-large{background:#0000;border:none}.dark-mode .font-preview-large:hover{transform:translateY(-2px)}.font-preview-large svg{filter:drop-shadow(0 4px 12px rgba(0,0,0,.15));transition:all .3s ease}.dark-mode .font-preview-large svg{filter:drop-shadow(0 4px 12px rgba(255,255,255,.15))}.dark-mode .font-preview-large svg use{fill:#fff!important;color:#fff!important}.font-sentence-preview{align-items:center;border-radius:0;display:flex;justify-content:center;max-width:100%;padding:16px 20px;position:relative}.dark-mode .font-sentence-preview,.font-sentence-preview{background:#0000;border:none}.font-info{text-align:center}.font-info .font-name{color:var(--color-text-primary);font-size:24px;font-weight:700;line-height:1.2;margin-bottom:var(--spacing-xs)}.dark-mode .font-info .font-name{color:var(--color-text-primary-dark)}.font-info .font-category{color:var(--color-text-secondary);font-size:14px;font-weight:500;letter-spacing:.5px}.dark-mode .font-info .font-category{color:var(--color-text-secondary-dark)}.active-font-label{color:var(--color-text-tertiary);font-size:12px;font-weight:500;letter-spacing:.5px;margin-bottom:0!important}.dark-mode .active-font-label{color:var(--color-text-tertiary-dark)}.font-details-section{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-sm);padding:var(--spacing-lg)}.dark-mode .font-details-section{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.font-details-section h3{color:var(--color-text-primary);font-size:16px;font-weight:600;margin-bottom:var(--spacing-md)}.dark-mode .font-details-section h3{color:var(--color-text-primary-dark)}.details-grid{display:flex;flex-direction:column;gap:var(--spacing-sm)}.detail-item{align-items:center;border-bottom:1px solid var(--color-border-primary);display:flex;justify-content:space-between;padding:var(--spacing-sm) 0}.detail-item:last-child{border-bottom:none}.dark-mode .detail-item{border-bottom-color:var(--color-border-primary-dark)}.detail-label{color:var(--color-text-secondary);font-size:12px;font-weight:500;letter-spacing:.3px}.dark-mode .detail-label{color:var(--color-text-secondary-dark)}.detail-value{color:var(--color-text-primary);font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:12px;font-weight:600}.dark-mode .detail-value{color:var(--color-text-primary-dark)}.text-preview{display:flex;flex-direction:column;gap:var(--spacing-md)}.preview-text{background:#0000;border:none;border-radius:0;color:var(--color-text-primary);font-size:16px;font-weight:400;letter-spacing:.01em;line-height:1.4;margin:0;max-width:280px;padding:0;text-align:center}.dark-mode .preview-text{background:#0000;border:none;color:var(--color-text-primary-dark)}.font-actions{flex-direction:column}.action-btn,.font-actions{display:flex;gap:var(--spacing-sm)}.action-btn{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);color:var(--color-text-primary);cursor:pointer;font-size:14px;font-weight:500;justify-content:center;letter-spacing:.3px;padding:var(--spacing-md) var(--spacing-lg);text-decoration:none;text-transform:uppercase;transition:all var(--transition-normal)}.action-btn:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md);transform:translateY(-1px)}.dark-mode .action-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.dark-mode .action-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a}.action-btn.primary{background:var(--color-accent);border-color:var(--color-accent);color:#fff}.action-btn.primary:hover{background:var(--color-accent-hover);border-color:var(--color-accent-hover);box-shadow:0 2px 8px #007acc4d}.dark-mode .action-btn.primary{background:var(--color-accent-dark);border-color:var(--color-accent-dark)}.dark-mode .action-btn.primary:hover{background:var(--color-accent-hover-dark);border-color:var(--color-accent-hover-dark);box-shadow:0 2px 8px #4fc3f74d}.action-btn.ghost{background:#fff;border:1px solid var(--color-text-secondary);color:var(--color-text-primary);margin-top:var(--spacing-md)}.action-btn.ghost:hover{background:var(--color-bg-secondary);border-color:var(--color-text-primary);color:var(--color-text-primary);transform:translateY(-1px)}.dark-mode .action-btn.ghost{background:var(--color-bg-primary-dark);border-color:var(--color-text-secondary-dark);color:var(--color-text-primary-dark)}.dark-mode .action-btn.ghost:hover{background:var(--color-bg-secondary-dark);border-color:var(--color-text-primary-dark);color:var(--color-text-primary-dark)}.font-action-section .google-fonts-link.ghost{background:var(--color-bg-secondary)!important;border-color:var(--color-text-tertiary)!important;border:1px solid var(--color-text-tertiary)!important;border-radius:0 0 var(--border-radius-md) var(--border-radius-md)!important;color:var(--color-text-primary)!important;margin-top:0!important;width:100%}.font-action-section .google-fonts-link.ghost:hover{background:var(--color-bg-tertiary)!important;border-color:var(--color-text-tertiary)!important;box-shadow:none!important;color:var(--color-text-primary)!important;transform:none!important}.dark-mode .font-action-section .google-fonts-link.ghost{background:var(--color-bg-secondary-dark)!important;border-color:var(--color-text-tertiary-dark)!important;color:var(--color-text-primary-dark)!important}.dark-mode .font-action-section .google-fonts-link.ghost:hover{background:var(--color-bg-tertiary-dark)!important;border-color:var(--color-text-tertiary-dark)!important;box-shadow:none!important;color:var(--color-text-primary-dark)!important;transform:none!important}.google-fonts-link svg{margin-left:8px}.active-font-card{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);margin-bottom:var(--spacing-md);overflow:hidden;position:relative;transition:all .3s ease}.dark-mode .active-font-card{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.active-font-content{align-items:center;background:var(--color-bg-secondary);border-bottom:1px solid var(--color-border-primary);display:flex;gap:var(--spacing-md);padding:var(--spacing-md)}.dark-mode .active-font-content{background:var(--color-bg-secondary-dark);border-bottom-color:var(--color-border-primary-dark)}.font-letter-preview{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-sm);display:flex;flex-shrink:0;height:120px;justify-content:center;width:120px}.dark-mode .font-letter-preview{background:var(--color-bg-primary-dark);border:1px solid var(--color-border-primary-dark)}.font-letter-preview svg{filter:drop-shadow(0 2px 4px rgba(0,0,0,.1))}.dark-mode .font-letter-preview svg{filter:drop-shadow(0 2px 4px rgba(255,255,255,.1))}.font-info-compact{display:flex;flex:1 1;flex-direction:column;gap:2px}.font-name-compact{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:18px;font-weight:600;line-height:1.2;margin:0}.dark-mode .font-name-compact{color:var(--color-text-primary-dark)}.font-category-compact{color:var(--color-text-secondary);font-size:12px;font-weight:500;letter-spacing:.05em;margin:0;text-transform:uppercase}.dark-mode .font-category-compact{color:var(--color-text-secondary-dark)}.font-metadata{display:flex;flex-direction:column;gap:2px;margin-top:4px}.font-styles,.font-weights{color:var(--color-text-tertiary);font-size:10px;font-weight:400;letter-spacing:.02em;opacity:.8}.dark-mode .font-styles,.dark-mode .font-weights{color:var(--color-text-tertiary-dark)}.font-sentence-compact{align-items:center;background:var(--color-bg-primary);display:flex;height:100px;justify-content:center;padding:var(--spacing-sm) var(--spacing-md) 0 var(--spacing-md);position:relative}.dark-mode .font-sentence-compact{background:var(--color-bg-primary-dark)}.font-action-section{background:var(--color-bg-primary);display:flex;justify-content:center;padding:0}.dark-mode .font-action-section{background:var(--color-bg-primary-dark)}.active-font-label{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-weight:600;margin:0 0 var(--spacing-md) 0}.dark-mode .active-font-label{color:var(--color-text-primary-dark)}.active-font-header{background:linear-gradient(135deg,var(--color-bg-secondary) 0,var(--color-bg-primary) 100%);border-bottom:1px solid var(--color-border-primary);padding:24px 28px 20px;position:relative}.dark-mode .active-font-header{background:linear-gradient(135deg,var(--color-bg-secondary-dark) 0,var(--color-bg-primary-dark) 100%);border-bottom-color:var(--color-border-primary-dark)}.active-font-header .font-name{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:28px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0 0 8px}.dark-mode .active-font-header .font-name{color:var(--color-text-primary-dark)}.active-font-header .font-category{color:var(--color-text-secondary);font-size:14px;font-weight:500;letter-spacing:.1em;margin:0;opacity:.8}.dark-mode .active-font-header .font-category{color:var(--color-text-secondary-dark)}.active-font-preview{align-items:center;background:var(--color-bg-primary);display:flex;flex-direction:column;gap:20px;padding:24px 28px 28px;position:relative}.dark-mode .active-font-preview{background:var(--color-bg-primary-dark)}.similar-fonts{margin-top:var(--spacing-lg)}.similar-fonts-title{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-weight:600;margin:0 0 var(--spacing-md) 0}.dark-mode .similar-fonts-title{color:var(--color-text-primary-dark)}.similar-fonts-list{display:flex;flex-direction:column;gap:var(--spacing-sm)}.similar-font-item{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);cursor:pointer;display:flex;gap:var(--spacing-md);height:60px;padding:var(--spacing-md);transition:all var(--transition-normal)}.similar-font-item:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-sm);transform:translateY(-1px)}.dark-mode .similar-font-item{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.dark-mode .similar-font-item:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 1px 3px #ffffff1a}.similar-font-preview{align-items:center;background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);display:flex;flex-shrink:0;height:32px;justify-content:center;overflow:hidden;width:80px}.dark-mode .similar-font-preview{background:var(--color-bg-tertiary-dark)}.font-sprite{height:100%;object-fit:cover;width:100%}.dark-mode .font-glyph-small use,.dark-mode .font-letter-preview svg use,.dark-mode .font-sprite,.dark-mode .font-sprite use,.dark-mode .similar-font-glyph svg use{fill:#fff!important;color:#fff!important}.font-fallback{color:var(--color-text-secondary);font-size:14px;font-weight:600}.dark-mode .font-fallback{color:var(--color-text-secondary-dark)}.similar-font-glyph{align-items:center;display:flex;flex:0 0 auto;height:48px;justify-content:center;margin-left:-12px;margin-right:-8px;width:48px}.similar-font-glyph .font-glyph-small{height:32px;width:32px}.similar-font-info{display:flex;flex:0 0 auto;flex-direction:column;gap:2px;min-width:120px}.similar-font-sentence{align-items:center;display:flex;flex:1 1;justify-content:flex-end;min-height:49px;min-width:0;position:relative}.font-name{color:var(--color-text-primary);font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dark-mode .font-name{color:var(--color-text-primary-dark)}.font-family{color:var(--color-text-secondary);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dark-mode .font-family{color:var(--color-text-secondary-dark)}.similarity-score{background:#007acc1a;border-radius:10px;color:var(--color-accent);flex-shrink:0;font-size:10px;font-weight:600;padding:2px 6px}.dark-mode .similarity-score{background:#4fc3f71a;color:var(--color-accent-dark)}.no-similar{color:var(--color-text-secondary);font-size:12px;font-style:italic;padding:var(--spacing-md);text-align:center}.dark-mode .no-similar{color:var(--color-text-secondary-dark)}@media (max-width:1200px){.sidebar{min-width:350px;width:350px}}@media (max-width:768px){.fontmap-container{flex-direction:column}.sidebar{border-bottom:1px solid var(--color-border-primary);border-right:none;height:auto;left:0;max-height:none;min-width:0;overflow:visible;position:fixed;right:0;top:0;width:100%;z-index:2000}.dark-mode .sidebar{border-bottom-color:var(--color-border-primary-dark)}.sidebar-content{overflow:visible;padding:0}.sidebar-footer{display:none}.bottom-controls,.focus-hint{display:none!important}.font-details{background:var(--color-bg-primary);bottom:0;height:100vh;overflow-y:auto;padding-top:48px;position:fixed;right:0;top:0;transform:translateX(100%);transition:transform .28s ease;width:100%;z-index:3000}.dark-mode .font-details{background:var(--color-bg-primary-dark)}.fontmap-container.has-focus .font-details{transform:translateX(0)}.font-details-back{align-items:center;background:#0000;border:none;color:var(--color-text-primary);cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;gap:4px;left:12px;padding:6px 10px 6px 6px;position:absolute;top:12px;z-index:1}.dark-mode .font-details-back{color:var(--color-text-primary-dark)}.main-area{height:100vh;width:100%}.sidebar-content .sidebar-header,.sidebar-header{align-items:center;border-bottom:none;flex-direction:row;justify-content:space-between;margin-bottom:0;padding:var(--spacing-md)}.map-title{-webkit-text-stroke:12px var(--color-bg-primary);text-stroke:12px var(--color-bg-primary);font-size:24px;left:15px;top:15px}.dark-mode .map-title{-webkit-text-stroke:12px var(--color-bg-primary-dark);text-stroke:12px var(--color-bg-primary-dark)}.map-title:before{-webkit-text-stroke:13px var(--color-border-primary);text-stroke:13px var(--color-border-primary)}.dark-mode .map-title:before{-webkit-text-stroke:13px var(--color-border-primary-dark);text-stroke:13px var(--color-border-primary-dark)}.sidebar-content{gap:var(--spacing-md);padding:var(--spacing-md)}.sidebar-separator{margin:var(--spacing-md) 0}.top-controls{gap:6px;right:12px;top:12px}.bottom-controls{bottom:12px;gap:6px;right:12px}.filters-inline{font-size:11px}.toggle-btn{font-size:12px;padding:4px 8px}.dataset-select{font-size:10px;min-width:150px;padding:4px 8px}.zoom-btn{font-size:9px;padding:3px 6px}.font-details-section{padding:var(--spacing-md)}.font-preview{padding:var(--spacing-lg)}.font-preview-large{height:80px;width:80px}.font-info .font-name{font-size:20px}}@media (max-width:480px){.sidebar-header{flex-direction:column;gap:var(--spacing-sm);padding:var(--spacing-sm)}.map-title{-webkit-text-stroke:8px var(--color-bg-primary);text-stroke:8px var(--color-bg-primary);font-size:20px;left:10px;top:10px}.dark-mode .map-title{-webkit-text-stroke:8px var(--color-bg-primary-dark);text-stroke:8px var(--color-bg-primary-dark)}.map-title:before{-webkit-text-stroke:9px var(--color-border-primary);text-stroke:9px var(--color-border-primary)}.dark-mode .map-title:before{-webkit-text-stroke:9px var(--color-border-primary-dark);text-stroke:9px var(--color-border-primary-dark)}.sidebar-content{gap:var(--spacing-sm);padding:var(--spacing-sm)}.sidebar-separator{margin:var(--spacing-sm) 0}.top-controls{gap:4px;right:8px;top:8px}.bottom-controls{bottom:8px;gap:4px;right:8px}.filters-inline{font-size:10px}.toggle-btn{font-size:11px;padding:3px 6px}.dataset-select{font-size:9px;min-width:120px;padding:3px 6px}.zoom-btn{font-size:8px;padding:2px 4px}.font-details-section{padding:var(--spacing-sm)}.font-preview{padding:var(--spacing-md)}.font-preview-large{height:60px;width:60px}.font-info .font-name{font-size:18px}.preview-text{font-size:14px}}@media (max-width:768px){.dilation-control,.size-control{min-width:150px}.dilation-label,.size-label{font-size:10px}.slider-labels{font-size:9px}}@media (max-width:480px){.dilation-control,.size-control{min-width:120px}.dilation-label,.size-label{font-size:9px}.slider-labels{font-size:8px}}.unified-overlay{align-items:center;background:rgba(0,0,0,var(--overlay-opacity-dark));bottom:0;display:flex;justify-content:center;left:0;opacity:1;position:fixed;right:0;top:0;z-index:99999}.unified-overlay .loading{color:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:18px;font-weight:500;left:auto;line-height:1.2;margin:0;padding:0;position:static;text-align:center;top:auto;transform:none}.unified-overlay .overlay-spinner{animation:spin .8s linear infinite;border:3px solid #fff3;border-radius:50%;border-top-color:#fff;height:32px;width:32px}.dark-mode .unified-overlay .loading{color:#fff}.intro-modal{animation:introModalSlideIn .6s cubic-bezier(.16,1,.3,1);background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);max-height:80vh;max-width:420px;overflow:hidden;width:90%}.dark-mode .intro-modal{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}@keyframes introModalSlideIn{0%{opacity:0;transform:translateY(30px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.intro-modal-content{padding:var(--spacing-xl);text-align:center}.intro-title{color:var(--color-text-primary);font-family:var(--font-logo);font-size:36px;font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0 0 var(--spacing-sm) 0}.dark-mode .intro-title{color:var(--color-text-primary-dark)}.intro-subtitle{color:var(--color-text-secondary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:16px;font-weight:400;line-height:1.4;margin:0 0 var(--spacing-md) 0}.dark-mode .intro-subtitle{color:var(--color-text-secondary-dark)}.intro-description{color:var(--color-text-tertiary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;font-weight:400;line-height:1.5;margin:0 0 var(--spacing-lg) 0}.dark-mode .intro-description{color:var(--color-text-tertiary-dark)}.intro-modal .google-fonts-link,.intro-modal .google-fonts-link:hover{background:none!important;border:none!important;color:var(--text-color)!important;font-weight:700}.intro-features{flex-direction:column;gap:var(--spacing-md);margin-bottom:var(--spacing-lg)}.intro-feature,.intro-features{align-items:center;display:flex}.intro-feature{color:var(--color-text-secondary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;font-weight:400;gap:var(--spacing-sm)}.dark-mode .intro-feature{color:var(--color-text-secondary-dark)}.intro-feature-icon{align-items:center;background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);color:var(--color-text-tertiary);display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.dark-mode .intro-feature-icon{background:var(--color-bg-tertiary-dark);color:var(--color-text-tertiary-dark)}.intro-feature-icon svg{height:16px;width:16px}.intro-start-button{align-items:center;background:#000;border:1px solid #000;border-radius:var(--border-radius-md);color:#fff;cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:var(--spacing-sm);justify-content:center;letter-spacing:.3px;padding:var(--spacing-md) var(--spacing-lg);text-decoration:none;text-transform:uppercase;transition:all var(--transition-normal);width:100%}.intro-start-button:hover{background:#333;border-color:#333;box-shadow:var(--shadow-md);transform:translateY(-1px)}.dark-mode .intro-start-button{background:#fff;border-color:#fff;color:#000}.dark-mode .intro-start-button:hover{background:#e0e0e0;border-color:#e0e0e0;box-shadow:0 2px 6px #ffffff1a}@media (max-width:600px){.intro-modal{margin:var(--spacing-lg);width:95%}.intro-modal-content{padding:var(--spacing-lg)}.intro-title{font-size:28px}.intro-subtitle{font-size:14px}.intro-description{font-size:12px}.intro-features{gap:var(--spacing-sm)}.intro-feature{font-size:12px}}.about-modal{animation:modalSlideIn .4s cubic-bezier(.16,1,.3,1);background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);max-height:85vh;max-width:900px;overflow:hidden;width:95%}.dark-mode .about-modal{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 8px 32px #0006}.about-modal-content{display:flex;flex-direction:column;height:100%}.about-modal-header{align-items:center;background:linear-gradient(135deg,var(--color-bg-secondary) 0,var(--color-bg-primary) 100%);border-bottom:1px solid var(--color-border-primary);display:flex;justify-content:space-between;padding:20px 24px 16px}.dark-mode .about-modal-header{background:linear-gradient(135deg,var(--color-bg-secondary-dark) 0,var(--color-bg-primary-dark) 100%);border-bottom-color:var(--color-border-primary-dark)}.about-title{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:24px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0}.dark-mode .about-title{color:var(--color-text-primary-dark)}.about-close-button{align-items:center;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-secondary);cursor:pointer;display:flex;justify-content:center;padding:8px;transition:all var(--transition-normal)}.about-close-button:hover{background:var(--color-bg-secondary);color:var(--color-text-primary)}.dark-mode .about-close-button{color:var(--color-text-secondary-dark)}.dark-mode .about-close-button:hover{background:var(--color-bg-secondary-dark);color:var(--color-text-primary-dark)}.about-modal-body{flex:1 1;overflow-y:auto;padding:20px 24px}.about-hero{margin-bottom:24px;text-align:center}.about-description{color:var(--color-text-primary);font-size:16px;line-height:1.6;margin:0 0 24px;text-align:left}.dark-mode .about-description{color:var(--color-text-primary-dark)}.about-section{margin-bottom:24px}.about-section:last-child{margin-bottom:0}.about-section-title{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:18px;font-weight:600;margin:0 0 12px}.dark-mode .about-section-title{color:var(--color-text-primary-dark)}.about-section-text{color:var(--color-text-secondary);font-size:14px;line-height:1.5;margin:0}.dark-mode .about-section-text{color:var(--color-text-secondary-dark)}.about-content-grid{grid-gap:40px;align-items:start;display:grid;gap:40px;grid-template-columns:1fr 1fr;margin-top:24px}.about-column{display:flex;flex-direction:column;gap:16px}.pipeline-demo{align-items:center;background:var(--color-bg-secondary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:16px 0;padding:20px}.dark-mode .pipeline-demo{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.pipeline-steps{display:flex;flex-direction:column;gap:16px}.step-item{align-items:center;display:flex;gap:16px;padding:0}.step-content{flex:1 1}.step-header{gap:8px;margin-bottom:4px}.step-header,.step-number{align-items:center;display:flex}.step-number{background:var(--color-bg-primary);border:1px solid var(--color-text-secondary);border-radius:50%;color:var(--color-text-primary);font-size:12px;font-weight:700;height:20px;justify-content:center;width:20px}.dark-mode .step-number{background:var(--color-bg-primary-dark);border-color:var(--color-text-secondary-dark);color:var(--color-text-primary-dark)}.step-description{color:var(--color-text-secondary);font-size:13px;line-height:1.4;margin:0}.dark-mode .step-description{color:var(--color-text-secondary-dark)}.step-example{flex-shrink:0}.mini-matrix{background:#fff;border:1px solid var(--color-border-primary);border-radius:2px;font-family:Courier New,monospace;font-size:6px;line-height:1;padding:4px}.dark-mode .mini-matrix{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.mini-row{line-height:1.1;margin:0 0 1px;padding:0}.zero-value{opacity:.5}.vector-preview{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;color:var(--color-text-primary);font-family:Courier New,monospace;font-size:8px;font-weight:600;letter-spacing:-.3px;line-height:1.2;max-width:120px;padding:6px;word-break:break-all}.dark-mode .vector-preview{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.coordinates{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;flex-direction:column;font-family:Courier New,monospace;font-size:9px;gap:2px;padding:6px}.dark-mode .coordinates{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.coord{color:var(--color-accent);font-weight:600}.dark-mode .coord{color:var(--color-accent-dark)}.font-cluster-demo{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;gap:6px;padding:6px}.dark-mode .font-cluster-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.font-sample{color:var(--color-text-primary);font-size:12px;font-weight:600;line-height:1}.dark-mode .font-sample{color:var(--color-text-primary-dark)}.about-subtitle{color:var(--color-text-primary);font-size:16px;font-weight:600;margin:20px 0 8px}.dark-mode .about-subtitle{color:var(--color-text-primary-dark)}.code-link{color:var(--color-text-primary);display:inline-block;font-size:14px;font-weight:500;margin-bottom:24px;margin-top:8px;text-decoration:underline;transition:color var(--transition-normal)}.code-link:hover{color:var(--color-text-secondary)}.dark-mode .code-link{color:var(--color-text-primary-dark)}.dark-mode .code-link:hover{color:var(--color-text-secondary-dark)}.inline-link{color:var(--color-text-primary);font-size:12px;font-weight:500;text-decoration:underline;transition:color var(--transition-normal)}.inline-link:hover{color:var(--color-text-secondary)}.dark-mode .inline-link{color:var(--color-text-primary-dark)}.dark-mode .inline-link:hover{color:var(--color-text-secondary-dark)}.multi-glyph-demo{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;flex-direction:column;gap:4px;padding:8px 10px}.dark-mode .multi-glyph-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.glyph-grid{color:var(--color-text-primary);display:flex;gap:8px}.dark-mode .glyph-grid{color:var(--color-text-primary-dark)}.glyph-grid-label{color:var(--color-text-secondary);font-family:Courier New,monospace;font-size:9px;opacity:.6}.dark-mode .glyph-grid-label{color:var(--color-text-secondary-dark)}.pipeline-flow{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;font-family:Courier New,monospace;font-size:10px;gap:4px;padding:6px 8px}.dark-mode .pipeline-flow{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.pipeline-node{color:var(--color-text-primary);font-weight:500;white-space:nowrap}.dark-mode .pipeline-node{color:var(--color-text-primary-dark)}.pipeline-arrow{color:var(--color-text-secondary);opacity:.5}.dark-mode .pipeline-arrow{color:var(--color-text-secondary-dark)}@keyframes modalSlideIn{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}.about-modal .google-fonts-link{color:var(--color-text-primary);font-weight:500;text-decoration:underline;transition:color var(--transition-normal)}.about-modal .google-fonts-link:hover{color:var(--color-text-secondary)}.dark-mode .about-modal .google-fonts-link{color:var(--color-text-primary-dark)}.dark-mode .about-modal .google-fonts-link:hover{color:var(--color-text-secondary-dark)}.about-tech-list{list-style:none;margin:12px 0 16px;padding-left:0}.about-tech-list li{color:var(--color-text-secondary);font-size:14px;line-height:1.5;margin-bottom:8px;padding-left:20px;position:relative}.about-tech-list li:before{color:var(--color-accent);content:"→";font-weight:700;left:0;position:absolute}.about-tech-list li:last-child{margin-bottom:0}.dark-mode .about-tech-list li{color:var(--color-text-secondary-dark)}.dark-mode .about-tech-list li:before{color:var(--color-accent-dark)}.about-tech-list strong{color:var(--color-text-primary);font-weight:600}.dark-mode .about-tech-list strong{color:var(--color-text-primary-dark)}.pixel-matrix-demo{align-items:center;background:var(--color-bg-secondary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:20px 0;padding:20px}.dark-mode .pixel-matrix-demo{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.demo-step{align-items:center;display:flex;flex-direction:column;gap:8px;min-width:120px}.demo-label{color:var(--color-accent);font-size:12px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.dark-mode .demo-label{color:var(--color-accent-dark)}.pixel-matrix{background:#fff;border:1px solid var(--color-border-primary);border-radius:2px;font-family:Courier New,monospace;font-size:8px;line-height:1;padding:4px}.dark-mode .pixel-matrix{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.pixel-row{line-height:1.2;margin:0 0 1px;padding:0}.vector-demo{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;color:var(--color-text-secondary);font-family:Courier New,monospace;font-size:8px;line-height:1.2;max-width:200px;padding:6px;word-break:break-all}.dark-mode .vector-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-secondary-dark)}.umap-demo{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;flex-direction:column;font-family:Courier New,monospace;font-size:10px;gap:2px;padding:8px}.dark-mode .umap-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.coordinate{color:var(--color-accent);font-weight:600}.dark-mode .coordinate{color:var(--color-accent-dark)}.demo-caption{color:var(--color-text-secondary);font-size:10px;font-style:italic;text-align:center}.dark-mode .demo-caption{color:var(--color-text-secondary-dark)}.demo-arrow{color:var(--color-accent);font-size:16px;font-weight:700}.dark-mode .demo-arrow{color:var(--color-accent-dark)}@media (max-width:768px){.about-modal{max-width:95%;width:95%}.about-content-grid{gap:24px;grid-template-columns:1fr}.step-item{align-items:flex-start;flex-direction:column;gap:12px}.step-example{align-self:center}.mini-matrix{font-size:5px}.vector-preview{font-size:7px;max-width:100px}.coordinates{font-size:8px}}@media (max-width:480px){.about-modal-header{padding:16px 20px 12px}.about-modal-body{padding:16px 20px}.about-title{font-size:20px}.info-card,.pipeline-demo{padding:12px}}
|
| 2 |
-
/*# sourceMappingURL=632.07566e3f.chunk.css.map*/
|
|
|
|
|
|
|
|
|
build/static/css/632.07566e3f.chunk.css.map
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/static/css/632.abaca8bf.chunk.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root{--color-bg-primary:#fcfbf8;--color-bg-secondary:#f7f5f1;--color-bg-tertiary:#ece9e3;--color-text-primary:#000;--color-text-secondary:#666;--color-text-tertiary:#999;--color-border-primary:#e3e0da;--color-border-secondary:#d5d2cb;--color-accent:#007acc;--color-accent-hover:#005a9e;--color-bg-primary-dark:#121110;--color-bg-secondary-dark:#1c1a18;--color-bg-tertiary-dark:#363330;--color-text-primary-dark:#fff;--color-text-secondary-dark:#ccc;--color-text-tertiary-dark:#999;--color-border-primary-dark:#404040;--color-border-secondary-dark:#555;--color-accent-dark:#4fc3f7;--color-accent-hover-dark:#29b6f6;--spacing-xs:4px;--spacing-sm:8px;--spacing-md:12px;--spacing-lg:16px;--spacing-xl:20px;--border-radius-sm:4px;--border-radius-md:6px;--border-radius-lg:8px;--shadow-sm:0 1px 3px #0000001a;--shadow-md:0 2px 6px #0000001a;--shadow-lg:0 4px 12px #0000001a;--transition-fast:0.15s ease;--transition-normal:0.2s ease;--transition-slow:0.3s ease;--overlay-opacity-light:0.6;--overlay-opacity-dark:0.5;--font-logo:"Source Sans Pro","Times New Roman",serif}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fontmap-container{background:var(--color-bg-primary);cursor:default;display:flex;flex-direction:row;height:100vh;margin:0;overflow:hidden;padding:0;position:relative;transition:background-color var(--transition-quick);user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;width:100vw}.fontmap-container.dark-mode{background:var(--color-bg-primary-dark)}.fontmap-container:active{cursor:grabbing}.fontmap-container.zooming{cursor:zoom-in}.sidebar{background:var(--color-bg-secondary);border-right:1px solid var(--color-border-primary);display:flex;flex-direction:column;height:100vh;max-height:100vh;min-width:400px;overflow:hidden;position:relative;width:400px;z-index:2000}.dark-mode .sidebar{background:var(--color-bg-secondary-dark);border-right-color:var(--color-border-primary-dark)}.sidebar-header{border-bottom:1px solid var(--color-border-primary);display:flex;flex-direction:column;flex-shrink:0;gap:var(--spacing-md);min-height:-webkit-fit-content;min-height:fit-content;padding:var(--spacing-lg)}.dark-mode .sidebar-header{border-bottom-color:var(--color-border-primary-dark)}.map-container{height:100%;position:relative;width:100%}.dark-mode .loading-text{color:var(--color-text-secondary-dark)}.map-title{-webkit-text-stroke:16px var(--color-bg-primary);text-stroke:16px var(--color-bg-primary);color:var(--color-text-primary);font-family:var(--font-logo);font-size:32px;font-weight:700;left:20px;letter-spacing:-.02em;margin:0;paint-order:stroke fill;pointer-events:none;position:absolute;position:relative;text-shadow:0 2px 4px #0000001a;top:20px;z-index:100}.map-title:before{-webkit-text-stroke:17px var(--color-border-primary);text-stroke:17px var(--color-border-primary);color:#0000;content:attr(data-text);left:0;position:absolute;top:0;z-index:-1}.dark-mode .map-title{-webkit-text-stroke:16px var(--color-bg-primary-dark);text-stroke:16px var(--color-bg-primary-dark);color:var(--color-text-primary-dark);text-shadow:0 2px 4px #ffffff1a}.dark-mode .map-title:before{-webkit-text-stroke:17px var(--color-border-primary-dark);text-stroke:17px var(--color-border-primary-dark)}.sidebar-content{display:flex;flex:1 1;flex-direction:column;min-height:0;overflow-x:hidden;overflow-y:auto}.sidebar-content .sidebar-header{border-bottom:1px solid var(--color-border-primary);display:flex;flex-direction:column;flex-shrink:0;gap:var(--spacing-md);margin-bottom:var(--spacing-lg);min-height:-webkit-fit-content;min-height:fit-content;padding:var(--spacing-lg)}.dark-mode .sidebar-content .sidebar-header{border-bottom-color:var(--color-border-primary-dark)}.sidebar-footer{align-items:center;background:var(--color-bg-secondary);border-top:1px solid var(--color-border-primary);display:flex;flex-shrink:0;justify-content:space-between;min-height:-webkit-fit-content;min-height:fit-content;padding:var(--spacing-lg)}.dark-mode .sidebar-footer{background:var(--color-bg-secondary-dark);border-top-color:var(--color-border-primary-dark)}.about-link,.source-link{align-items:center;background:none;border:none;border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-md);text-decoration:none;transition:all var(--transition-normal)}.about-link:hover,.source-link:hover{background:var(--color-bg-primary);color:var(--color-text-primary);transform:translateY(-1px)}.dark-mode .about-link,.dark-mode .source-link{color:var(--color-text-secondary-dark)}.dark-mode .about-link:hover,.dark-mode .source-link:hover{background:var(--color-bg-primary-dark);color:var(--color-text-primary-dark)}.main-area{background:var(--color-bg-secondary);display:flex;flex:1 1;flex-direction:column;overflow:hidden;position:relative}.dark-mode .main-area{background:var(--color-bg-secondary-dark)}.fontmap-svg{shape-rendering:geometricPrecision;-webkit-touch-callout:none;cursor:grab;display:block;height:100%;image-rendering:crisp-edges;text-rendering:geometricPrecision;touch-action:none;-webkit-user-select:none;user-select:none;width:100%}.fontmap-svg:active{cursor:grabbing}.font-details-back{display:none}.font-glyph-group,.font-hit-area,.glyph-group{cursor:pointer}.glyph-hitbox{fill:#0000;stroke:none;vector-effect:non-scaling-stroke}.glyph-hitbox:hover,.highlight-group .glyph-hitbox{fill:#00000005;stroke:#00000024;stroke-width:1}.dark-mode .glyph-hitbox:hover,.dark-mode .highlight-group .glyph-hitbox{fill:#ffffff08;stroke:#ffffff2e;stroke-width:1}.font-glyph{shape-rendering:geometricPrecision;image-rendering:crisp-edges;pointer-events:none;text-rendering:geometricPrecision}.viewport-group{will-change:transform}.highlight-group,.viewport-group{shape-rendering:geometricPrecision;image-rendering:crisp-edges;text-rendering:geometricPrecision;transform-origin:0 0}.dark-mode .font-glyph,.dark-mode .font-glyph use{fill:#fff!important;color:#fff!important}.ui-group{pointer-events:none;z-index:100}.loading{color:var(--color-text-secondary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-weight:300;left:50%;letter-spacing:1px;position:absolute;text-transform:uppercase;top:50%;transform:translate(-50%,-50%)}.dark-mode .loading{color:var(--color-text-secondary-dark)}.sidebar-separator{background:var(--color-border-primary);height:1px;margin:var(--spacing-lg) 0}.dark-mode .sidebar-separator{background:var(--color-border-primary-dark)}.category-legend{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;padding:var(--spacing-sm) var(--spacing-md)}.dark-mode .category-legend{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.category-legend-toggle{align-items:center;color:var(--color-text-primary);cursor:pointer;display:flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:10px;font-weight:500;gap:6px;letter-spacing:.3px;line-height:14px;text-transform:uppercase;-webkit-user-select:none;user-select:none;white-space:nowrap}.dark-mode .category-legend-toggle{color:var(--color-text-primary-dark)}.category-legend-toggle input[type=checkbox]{accent-color:var(--color-text-primary);cursor:pointer;height:12px;margin:0;width:12px}.dark-mode .category-legend-toggle input[type=checkbox]{accent-color:var(--color-text-primary-dark)}.category-legend-items{display:flex;flex-wrap:wrap;gap:var(--spacing-xs) var(--spacing-md);margin-top:2px}.category-legend-item{align-items:center;display:flex;gap:6px}.category-legend-dot{border-radius:50%;flex-shrink:0;height:10px;transition:background .2s ease;width:10px}.category-legend-label{color:var(--color-text-secondary);font-size:12px;text-transform:capitalize}.dark-mode .category-legend-label{color:var(--color-text-secondary-dark)}.svg-tooltip{opacity:0;pointer-events:none}.tooltip-html{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;padding:8px}.tooltip-html a:hover{opacity:.7}.font-tooltip{background:var(--color-bg-primary);border:none;border-radius:var(--border-radius-md);box-shadow:var(--shadow-lg);color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:11px;line-height:1.3;max-width:280px;min-width:160px;overflow:hidden;padding:0;pointer-events:none;user-select:none;-webkit-user-select:none}@media (max-width:768px){.font-tooltip-hover{pointer-events:auto}}.tooltip-open-btn{background:var(--color-text-primary);border:1px solid var(--color-text-primary);border-radius:var(--border-radius-sm);color:var(--color-bg-primary);cursor:pointer;display:block;font-family:inherit;font-size:12px;font-weight:600;letter-spacing:.4px;margin:4px 8px 8px;padding:10px 12px;pointer-events:auto;text-transform:uppercase;width:calc(100% - 16px)}.font-tooltip.dark-mode .tooltip-open-btn{background:var(--color-text-primary-dark);border-color:var(--color-text-primary-dark);color:var(--color-bg-primary-dark)}.font-tooltip-selected{border-width:1px;box-shadow:0 8px 32px #0003;z-index:1000!important}.font-tooltip-hover{border:3px solid #fff!important;box-shadow:0 2px 8px #0000001a!important;z-index:1001!important}.dark-mode .font-tooltip-hover{border:3px solid #fff!important;box-shadow:0 2px 8px #0003!important}.simple-tooltip{margin-bottom:0!important;padding:12px 8px;padding-bottom:0!important;text-align:center}.tooltip-font-name{color:var(--color-text-primary);font-size:12px;font-weight:600;text-align:center}.tooltip-sentence-preview{align-items:center;display:flex;justify-content:center}.dark-mode .font-tooltip,.sentence-image,.tooltip-sentence-preview{margin-bottom:0!important;padding-bottom:0!important}.dark-mode .font-tooltip{color:var(--color-text-primary-dark)!important}.dark-mode .font-tooltip,.font-tooltip.dark-mode{background:var(--color-bg-primary-dark)!important;border:none!important}.font-tooltip.dark-mode{color:#fff!important}.dark-mode .tooltip-font-name{color:var(--color-text-primary-dark)!important}.dark-mode .font-tooltip .tooltip-font-name,.font-tooltip.dark-mode .tooltip-font-name{color:#fff!important}.sentence-image{border-radius:var(--border-radius-sm);height:auto;max-width:100%;min-height:40px!important}.dark-mode .font-tooltip-selected .sentence-image,.font-tooltip-hover .sentence-image,.font-tooltip-selected .sentence-image{box-shadow:none}.tooltip-preview-large{background:var(--color-bg-secondary);border-bottom:1px solid var(--color-border-primary);padding:var(--spacing-xl);text-align:center}.dark-mode .tooltip-preview-large{background:var(--color-bg-secondary-dark);border-bottom-color:var(--color-border-primary-dark)}.preview-glyph-large{align-items:center;display:flex;height:80px;justify-content:center}.preview-glyph-large svg{filter:drop-shadow(0 2px 4px rgba(0,0,0,.1))}.dark-mode .preview-glyph-large svg{filter:drop-shadow(0 2px 4px rgba(255,255,255,.1))}.tooltip-content{padding:16px}.tooltip-header{margin-bottom:12px}.font-name{font-size:16px;margin-bottom:4px}.font-category{color:var(--color-text-secondary);font-size:12px;letter-spacing:.5px;text-transform:uppercase}.dark-mode .font-category{color:var(--color-text-secondary-dark)}.tooltip-info{margin-bottom:12px}.info-item{display:flex;font-size:11px;justify-content:space-between;margin-bottom:6px}.info-label{color:var(--color-text-secondary);font-weight:500}.dark-mode .info-label{color:var(--color-text-secondary-dark)}.info-value{color:var(--color-text-primary);font-weight:400}.dark-mode .info-value{color:var(--color-text-primary-dark)}.tooltip-footer{border-top:1px solid var(--color-border-primary);padding-top:var(--spacing-sm)}.dark-mode .tooltip-footer{border-top-color:var(--color-border-primary-dark)}.tooltip-hint{color:var(--color-text-tertiary);font-size:10px;font-style:italic;text-align:center}.dark-mode .tooltip-hint{color:var(--color-text-tertiary-dark)}.font-tooltip{transform:translateY(0)}.dark-mode .tooltip-sentence img,.font-tooltip.dark-mode .sentence-image{filter:invert(1)!important}.font-tooltip .tooltip-spinner{color:var(--color-text-secondary)!important}.font-tooltip.dark-mode .tooltip-spinner{color:var(--color-text-secondary-dark)!important}.dark-mode .font-tooltip svg use,.dark-mode .tooltip-fallback svg use,.font-tooltip.dark-mode svg use{fill:#fff!important;color:#fff!important}.top-controls{align-items:flex-start;display:flex;gap:8px;position:absolute;right:16px;top:16px;z-index:200}.dark-mode-toggle{flex-shrink:0}.toggle-btn{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:500;letter-spacing:.3px;outline:none;padding:var(--spacing-sm) var(--spacing-md);text-transform:uppercase;transition:all var(--transition-normal);-webkit-user-select:none;user-select:none}.toggle-btn:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md);transform:translateY(-1px)}.toggle-btn:active{box-shadow:var(--shadow-sm);transform:translateY(0)}.toggle-btn:focus{border-color:var(--color-accent);box-shadow:0 0 0 2px #007acc33}.dark-mode .toggle-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.dark-mode .toggle-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a}.dark-mode .toggle-btn:focus{border-color:var(--color-accent-dark);box-shadow:0 0 0 2px #4fc3f733}.dataset-selector{flex-shrink:0}.dataset-select{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:500;letter-spacing:.3px;min-width:200px;outline:none;padding:var(--spacing-sm) var(--spacing-md);text-transform:uppercase;transition:all var(--transition-normal)}.dataset-select:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md)}.dataset-select:focus{border-color:var(--color-accent);box-shadow:0 0 0 2px #007acc33}.dark-mode .dataset-select{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.dark-mode .dataset-select:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a}.dark-mode .dataset-select:focus{border-color:var(--color-accent-dark);box-shadow:0 0 0 2px #4fc3f733}.search-section{margin-bottom:0}.search-bar-big .search-input{border-radius:var(--border-radius-lg);font-size:16px;padding:var(--spacing-md) var(--spacing-lg)}.filters-container{align-items:flex-start;background:#0000;border:none;border-radius:0;box-shadow:none;display:flex;flex-direction:column;gap:var(--spacing-xs);margin:var(--spacing-sm) 0 0 0;padding:var(--spacing-sm);width:100%}.filters-label{color:var(--color-text-tertiary);font-size:11px;font-weight:500;letter-spacing:.5px;margin-bottom:2px;text-transform:uppercase}.dark-mode .filters-label{color:var(--color-text-tertiary-dark)}.filters-inline{grid-gap:var(--spacing-xs);color:var(--color-text-secondary);display:grid;font-size:11px;gap:var(--spacing-xs);grid-template-columns:repeat(3,1fr);width:100%}.dark-mode .filters-inline{color:var(--color-text-secondary-dark)}.filter-link{align-items:center;background:var(--color-bg-secondary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-sm);cursor:pointer;display:flex;font-weight:500;gap:3px;justify-content:space-between;min-height:28px;padding:var(--spacing-xs) var(--spacing-sm);text-align:left;transition:all var(--transition-fast)}.filter-link:hover{background:var(--color-bg-tertiary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-sm);color:var(--color-text-primary);transform:translateY(-1px)}.dark-mode .filter-link{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.dark-mode .filter-link:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.filter-link.active{background:var(--color-bg-primary);border-color:var(--color-text-primary);box-shadow:var(--shadow-sm);color:var(--color-text-primary);font-weight:600}.dark-mode .filter-link.active{background:var(--color-bg-primary-dark);border-color:var(--color-text-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.filter-count{background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);color:var(--color-text-secondary);font-size:10px;font-weight:500;min-width:20px;opacity:.7;padding:2px 6px;text-align:center;transition:all var(--transition-fast)}.dark-mode .filter-count{background:var(--color-bg-tertiary-dark);color:var(--color-text-secondary-dark);opacity:.8}.filter-link.active .filter-count{background:var(--color-text-primary);color:var(--color-text-primary);color:var(--color-bg-primary);opacity:1}.dark-mode .filter-link.active .filter-count{background:var(--color-text-primary-dark);color:var(--color-text-primary-dark);color:var(--color-bg-primary-dark)}.search-bar{align-items:center;display:flex;min-width:200px;position:relative}.search-input{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:500;outline:none;padding:var(--spacing-sm) var(--spacing-md);padding-right:10px;transition:all var(--transition-normal);width:100%}.search-input:focus{border-color:var(--color-accent);box-shadow:0 0 0 2px #007acc33}.search-input::placeholder{color:var(--color-text-tertiary)}.search-input.dark{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.search-input.dark:focus{border-color:var(--color-accent-dark);box-shadow:0 0 0 2px #4fc3f733}.search-input.dark::placeholder{color:var(--color-text-tertiary-dark)}.search-controls{align-items:center;display:flex;gap:var(--spacing-xs);position:absolute;right:var(--spacing-sm);top:50%;transform:translateY(-50%);z-index:1}.search-counter{background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);color:var(--color-text-secondary);font-size:10px;font-weight:500;padding:2px 6px;pointer-events:none;transition:all var(--transition-normal)}.search-counter.filtered{background:var(--color-bg-secondary);border:1px solid var(--color-text-secondary);color:var(--color-text-primary)}.search-counter.dark{background:var(--color-bg-tertiary-dark);color:var(--color-text-secondary-dark)}.search-counter.dark.filtered{background:var(--color-bg-secondary-dark);border:1px solid var(--color-text-secondary-dark);color:var(--color-text-primary-dark)}.search-clear{align-items:center;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-tertiary);cursor:pointer;display:flex;justify-content:center;padding:var(--spacing-xs);transition:all var(--transition-fast)}.search-clear:hover{background:var(--color-bg-tertiary);color:var(--color-text-secondary)}.dark-mode .search-clear:hover{background:var(--color-bg-tertiary-dark);color:var(--color-text-secondary-dark)}.bottom-controls{align-items:flex-end;gap:8px;right:16px}.bottom-controls,.focus-hint{bottom:16px;display:flex;position:absolute;z-index:200}.focus-hint{align-items:center;background:#0000;gap:12px;height:36px;left:16px;pointer-events:none;-webkit-user-select:none;user-select:none}.focus-hint-keys{align-items:center;display:flex;gap:4px}.focus-hint kbd{align-items:center;background:#fff;border:1px solid #fff;border-radius:4px;color:#000;display:inline-flex;font-family:inherit;font-size:14px;height:32px;justify-content:center;line-height:1;width:32px}.dark-mode .focus-hint kbd{background:#000;border-color:#fff;color:#fff}.focus-hint-label{color:#000;font-size:12px;letter-spacing:.3px;line-height:36px;text-shadow:0 0 3px #fff,0 0 3px #fff,0 0 3px #fff}.dark-mode .focus-hint-label{color:#fff;text-shadow:0 0 3px #000,0 0 3px #000,0 0 3px #000}.bottom-controls .dark-mode-toggle{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;display:flex;flex-shrink:0;font-family:inherit;justify-content:center;line-height:1;padding:var(--spacing-sm) var(--spacing-md)}.dark-mode .bottom-controls .dark-mode-toggle{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.dark-mode-toggle-icon{align-items:center;display:inline-flex;justify-content:center;transition:transform .5s cubic-bezier(.4,0,.2,1)}.zoom-controls{display:flex;flex-direction:column;gap:var(--spacing-xs)}.zoom-btn{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);color:var(--color-text-primary);cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:10px;font-weight:500;letter-spacing:.3px;min-width:24px;outline:none;padding:var(--spacing-sm) var(--spacing-md);text-align:center;text-transform:uppercase;transition:all var(--transition-normal)}.dark-mode .zoom-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a;color:var(--color-text-primary-dark)}.zoom-btn:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md);transform:translateY(-1px)}.dark-mode .zoom-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a;transform:translateY(-1px)}.zoom-btn.zoom-reset{background:var(--color-text-primary);border-color:var(--color-text-primary);box-shadow:var(--shadow-md);color:var(--color-bg-primary)}.dark-mode .zoom-btn.zoom-reset{background:var(--color-text-primary-dark);border-color:var(--color-text-primary-dark);box-shadow:0 2px 6px #ffffff1a;color:var(--color-bg-primary-dark)}.zoom-btn.zoom-reset:hover{background:var(--color-text-secondary);box-shadow:var(--shadow-lg);color:var(--color-bg-primary);transform:translateY(-1px)}.dark-mode .zoom-btn.zoom-reset:hover{background:var(--color-text-secondary-dark);box-shadow:0 4px 12px #ffffff1a;color:var(--color-bg-primary-dark);transform:translateY(-1px)}.dilation-control{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:var(--spacing-sm);min-width:200px;padding:var(--spacing-md)}.dark-mode .dilation-control{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.dilation-label{align-items:center;display:flex;font-size:12px;font-weight:500;justify-content:space-between;letter-spacing:.3px;text-transform:uppercase}.cache-indicator{font-size:14px;margin-left:var(--spacing-sm);opacity:.7;transition:opacity var(--transition-fast)}.cache-indicator.ready{color:#22c55e;opacity:1}.cache-indicator.loading{animation:pulse 1.5s ease-in-out infinite;color:#f59e0b;opacity:.8}.cache-indicator.not-ready{color:var(--color-text-tertiary);opacity:.5}@keyframes pulse{0%,to{opacity:.8}50%{opacity:.4}}.dark-mode .cache-indicator.ready{color:#4ade80}.dark-mode .cache-indicator.loading{color:#fbbf24}.dark-mode .cache-indicator.not-ready{color:var(--color-text-tertiary-dark)}.label-text{color:var(--color-text-primary)}.dark-mode .label-text{color:var(--color-text-primary-dark)}.label-value{color:var(--color-text-secondary);font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-weight:600}.dark-mode .label-value{color:var(--color-text-secondary-dark)}.dilation-slider-container{display:flex;flex-direction:column;gap:var(--spacing-xs)}.dilation-slider{-webkit-appearance:none;appearance:none;background:var(--color-border-primary);border-radius:2px;cursor:pointer;height:4px;outline:none;transition:all var(--transition-normal);width:100%}.dilation-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-webkit-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.dilation-slider::-webkit-slider-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.dilation-slider::-moz-range-thumb{background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-moz-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.dilation-slider::-moz-range-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.dilation-slider.dark{background:var(--color-border-primary-dark)}.dilation-slider.dark::-webkit-slider-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.dilation-slider.dark::-moz-range-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.slider-labels{color:var(--color-text-secondary);display:flex;font-size:10px;font-weight:500;justify-content:space-between;letter-spacing:.5px;text-transform:uppercase}.dark-mode .slider-labels{color:var(--color-text-secondary-dark)}.slider-label{font-size:10px}.size-control{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:var(--spacing-sm);min-width:200px;padding:var(--spacing-md)}.dark-mode .size-control{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.size-label{align-items:center;display:flex;font-size:12px;font-weight:500;justify-content:space-between;letter-spacing:.3px;text-transform:uppercase}.size-slider-container{display:flex;flex-direction:column;gap:var(--spacing-xs)}.size-slider{-webkit-appearance:none;appearance:none;background:var(--color-border-primary);border-radius:2px;cursor:pointer;height:4px;outline:none;transition:all var(--transition-normal);width:100%}.size-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-webkit-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.size-slider::-webkit-slider-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.size-slider::-moz-range-thumb{background:var(--color-text-primary);border:2px solid var(--color-bg-primary);border-radius:50%;box-shadow:var(--shadow-sm);cursor:pointer;height:16px;-moz-transition:all var(--transition-normal);transition:all var(--transition-normal);width:16px}.size-slider::-moz-range-thumb:hover{box-shadow:var(--shadow-md);transform:scale(1.1)}.size-slider.dark{background:var(--color-border-primary-dark)}.size-slider.dark::-webkit-slider-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.size-slider.dark::-moz-range-thumb{background:var(--color-text-primary-dark);border-color:var(--color-bg-primary-dark);box-shadow:0 1px 3px #ffffff1a}.font-details{display:flex;flex:1 1;flex-direction:column}.font-details-placeholder{align-items:center;color:var(--color-text-secondary);display:flex;flex-direction:column;justify-content:center;min-height:400px;padding:var(--spacing-xl);position:relative;text-align:center}.dark-mode .font-details-placeholder{color:var(--color-text-secondary-dark)}.placeholder-icon{align-items:center;display:flex;justify-content:center;margin-bottom:var(--spacing-xl);opacity:.7;position:relative;transition:all .3s ease;z-index:2}.placeholder-icon svg{color:var(--color-text-tertiary);filter:drop-shadow(0 2px 8px rgba(0,0,0,.1))}.dark-mode .placeholder-icon svg{color:var(--color-text-tertiary-dark);filter:drop-shadow(0 2px 8px rgba(255,255,255,.1))}.placeholder-content{align-items:center;display:flex;flex-direction:column;gap:var(--spacing-md);max-width:320px}.placeholder-content h3{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:24px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0}.dark-mode .placeholder-content h3{color:var(--color-text-primary-dark)}.placeholder-content p{color:var(--color-text-secondary);font-size:16px;font-weight:400;line-height:1.5;margin:0}.dark-mode .placeholder-content p{color:var(--color-text-secondary-dark)}.font-details-header{display:flex;justify-content:flex-end;margin-bottom:var(--spacing-md)}.close-btn{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;display:flex;justify-content:center;padding:var(--spacing-sm);transition:all var(--transition-normal)}.close-btn:hover{background:var(--color-bg-tertiary);border-color:var(--color-border-secondary);color:var(--color-text-primary)}.dark-mode .close-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-secondary-dark)}.dark-mode .close-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);color:var(--color-text-primary-dark)}.font-details-content{display:flex;flex:1 1;flex-direction:column;gap:var(--spacing-lg);padding:0 var(--spacing-lg) var(--spacing-lg) var(--spacing-lg)}.font-preview{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:center;padding:var(--spacing-xl)}.dark-mode .font-preview{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.font-preview-large{align-items:center;background:#0000;border:none;border-radius:0;display:flex;height:100px;justify-content:center;position:relative;transition:all .3s ease;width:100px}.font-preview-large:hover{transform:translateY(-2px)}.dark-mode .font-preview-large{background:#0000;border:none}.dark-mode .font-preview-large:hover{transform:translateY(-2px)}.font-preview-large svg{filter:drop-shadow(0 4px 12px rgba(0,0,0,.15));transition:all .3s ease}.dark-mode .font-preview-large svg{filter:drop-shadow(0 4px 12px rgba(255,255,255,.15))}.dark-mode .font-preview-large svg use{fill:#fff!important;color:#fff!important}.font-sentence-preview{align-items:center;border-radius:0;display:flex;justify-content:center;max-width:100%;padding:16px 20px;position:relative}.dark-mode .font-sentence-preview,.font-sentence-preview{background:#0000;border:none}.font-info{text-align:center}.font-info .font-name{color:var(--color-text-primary);font-size:24px;font-weight:700;line-height:1.2;margin-bottom:var(--spacing-xs)}.dark-mode .font-info .font-name{color:var(--color-text-primary-dark)}.font-info .font-category{color:var(--color-text-secondary);font-size:14px;font-weight:500;letter-spacing:.5px}.dark-mode .font-info .font-category{color:var(--color-text-secondary-dark)}.active-font-label{color:var(--color-text-tertiary);font-size:12px;font-weight:500;letter-spacing:.5px;margin-bottom:0!important}.dark-mode .active-font-label{color:var(--color-text-tertiary-dark)}.font-details-section{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-sm);padding:var(--spacing-lg)}.dark-mode .font-details-section{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.font-details-section h3{color:var(--color-text-primary);font-size:16px;font-weight:600;margin-bottom:var(--spacing-md)}.dark-mode .font-details-section h3{color:var(--color-text-primary-dark)}.details-grid{display:flex;flex-direction:column;gap:var(--spacing-sm)}.detail-item{align-items:center;border-bottom:1px solid var(--color-border-primary);display:flex;justify-content:space-between;padding:var(--spacing-sm) 0}.detail-item:last-child{border-bottom:none}.dark-mode .detail-item{border-bottom-color:var(--color-border-primary-dark)}.detail-label{color:var(--color-text-secondary);font-size:12px;font-weight:500;letter-spacing:.3px}.dark-mode .detail-label{color:var(--color-text-secondary-dark)}.detail-value{color:var(--color-text-primary);font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:12px;font-weight:600}.dark-mode .detail-value{color:var(--color-text-primary-dark)}.text-preview{display:flex;flex-direction:column;gap:var(--spacing-md)}.preview-text{background:#0000;border:none;border-radius:0;color:var(--color-text-primary);font-size:16px;font-weight:400;letter-spacing:.01em;line-height:1.4;margin:0;max-width:280px;padding:0;text-align:center}.dark-mode .preview-text{background:#0000;border:none;color:var(--color-text-primary-dark)}.font-actions{flex-direction:column}.action-btn,.font-actions{display:flex;gap:var(--spacing-sm)}.action-btn{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);color:var(--color-text-primary);cursor:pointer;font-size:14px;font-weight:500;justify-content:center;letter-spacing:.3px;padding:var(--spacing-md) var(--spacing-lg);text-decoration:none;text-transform:uppercase;transition:all var(--transition-normal)}.action-btn:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-md);transform:translateY(-1px)}.dark-mode .action-btn{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.dark-mode .action-btn:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 2px 6px #ffffff1a}.action-btn.primary{background:var(--color-accent);border-color:var(--color-accent);color:#fff}.action-btn.primary:hover{background:var(--color-accent-hover);border-color:var(--color-accent-hover);box-shadow:0 2px 8px #007acc4d}.dark-mode .action-btn.primary{background:var(--color-accent-dark);border-color:var(--color-accent-dark)}.dark-mode .action-btn.primary:hover{background:var(--color-accent-hover-dark);border-color:var(--color-accent-hover-dark);box-shadow:0 2px 8px #4fc3f74d}.action-btn.ghost{background:var(--color-bg-primary);border:1px solid var(--color-text-secondary);color:var(--color-text-primary);margin-top:var(--spacing-md)}.action-btn.ghost:hover{background:var(--color-bg-secondary);border-color:var(--color-text-primary);color:var(--color-text-primary);transform:translateY(-1px)}.dark-mode .action-btn.ghost{background:var(--color-bg-primary-dark);border-color:var(--color-text-secondary-dark);color:var(--color-text-primary-dark)}.dark-mode .action-btn.ghost:hover{background:var(--color-bg-secondary-dark);border-color:var(--color-text-primary-dark);color:var(--color-text-primary-dark)}.font-action-section .google-fonts-link.ghost{background:var(--color-bg-secondary)!important;border-color:var(--color-text-tertiary)!important;border:1px solid var(--color-text-tertiary)!important;border-radius:0 0 var(--border-radius-md) var(--border-radius-md)!important;color:var(--color-text-primary)!important;margin-top:0!important;width:100%}.font-action-section .google-fonts-link.ghost:hover{background:var(--color-bg-tertiary)!important;border-color:var(--color-text-tertiary)!important;box-shadow:none!important;color:var(--color-text-primary)!important;transform:none!important}.dark-mode .font-action-section .google-fonts-link.ghost{background:var(--color-bg-secondary-dark)!important;border-color:var(--color-text-tertiary-dark)!important;color:var(--color-text-primary-dark)!important}.dark-mode .font-action-section .google-fonts-link.ghost:hover{background:var(--color-bg-tertiary-dark)!important;border-color:var(--color-text-tertiary-dark)!important;box-shadow:none!important;color:var(--color-text-primary-dark)!important;transform:none!important}.google-fonts-link svg{margin-left:8px}.active-font-card{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);box-shadow:var(--shadow-sm);margin-bottom:var(--spacing-md);overflow:hidden;position:relative;transition:all .3s ease}.dark-mode .active-font-card{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 1px 3px #ffffff1a}.active-font-content{align-items:center;background:var(--color-bg-secondary);border-bottom:1px solid var(--color-border-primary);display:flex;gap:var(--spacing-md);padding:var(--spacing-md)}.dark-mode .active-font-content{background:var(--color-bg-secondary-dark);border-bottom-color:var(--color-border-primary-dark)}.font-letter-preview{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-sm);display:flex;flex-shrink:0;height:120px;justify-content:center;width:120px}.dark-mode .font-letter-preview{background:var(--color-bg-primary-dark);border:1px solid var(--color-border-primary-dark)}.font-letter-preview svg{filter:drop-shadow(0 2px 4px rgba(0,0,0,.1))}.dark-mode .font-letter-preview svg{filter:drop-shadow(0 2px 4px rgba(255,255,255,.1))}.font-info-compact{display:flex;flex:1 1;flex-direction:column;gap:2px}.font-name-compact{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:18px;font-weight:600;line-height:1.2;margin:0}.dark-mode .font-name-compact{color:var(--color-text-primary-dark)}.font-category-compact{color:var(--color-text-secondary);font-size:12px;font-weight:500;letter-spacing:.05em;margin:0;text-transform:uppercase}.dark-mode .font-category-compact{color:var(--color-text-secondary-dark)}.font-metadata{display:flex;flex-direction:column;gap:2px;margin-top:4px}.font-styles,.font-weights{color:var(--color-text-tertiary);font-size:10px;font-weight:400;letter-spacing:.02em;opacity:.8}.dark-mode .font-styles,.dark-mode .font-weights{color:var(--color-text-tertiary-dark)}.font-sentence-compact{align-items:center;background:var(--color-bg-primary);display:flex;height:100px;justify-content:center;padding:var(--spacing-sm) var(--spacing-md) 0 var(--spacing-md);position:relative}.dark-mode .font-sentence-compact{background:var(--color-bg-primary-dark)}.font-action-section{background:var(--color-bg-primary);display:flex;justify-content:center;padding:0}.dark-mode .font-action-section{background:var(--color-bg-primary-dark)}.active-font-label{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-weight:600;margin:0 0 var(--spacing-md) 0}.dark-mode .active-font-label{color:var(--color-text-primary-dark)}.active-font-header{background:linear-gradient(135deg,var(--color-bg-secondary) 0,var(--color-bg-primary) 100%);border-bottom:1px solid var(--color-border-primary);padding:24px 28px 20px;position:relative}.dark-mode .active-font-header{background:linear-gradient(135deg,var(--color-bg-secondary-dark) 0,var(--color-bg-primary-dark) 100%);border-bottom-color:var(--color-border-primary-dark)}.active-font-header .font-name{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:28px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0 0 8px}.dark-mode .active-font-header .font-name{color:var(--color-text-primary-dark)}.active-font-header .font-category{color:var(--color-text-secondary);font-size:14px;font-weight:500;letter-spacing:.1em;margin:0;opacity:.8}.dark-mode .active-font-header .font-category{color:var(--color-text-secondary-dark)}.active-font-preview{align-items:center;background:var(--color-bg-primary);display:flex;flex-direction:column;gap:20px;padding:24px 28px 28px;position:relative}.dark-mode .active-font-preview{background:var(--color-bg-primary-dark)}.similar-fonts{margin-top:var(--spacing-lg)}.similar-fonts-title{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-weight:600;margin:0 0 var(--spacing-md) 0}.dark-mode .similar-fonts-title{color:var(--color-text-primary-dark)}.similar-fonts-list{display:flex;flex-direction:column;gap:var(--spacing-sm)}.similar-font-item{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);cursor:pointer;display:flex;gap:var(--spacing-md);height:60px;padding:var(--spacing-md);transition:all var(--transition-normal)}.similar-font-item:hover{background:var(--color-bg-secondary);border-color:var(--color-border-secondary);box-shadow:var(--shadow-sm);transform:translateY(-1px)}.dark-mode .similar-font-item{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.dark-mode .similar-font-item:hover{background:var(--color-bg-tertiary-dark);border-color:var(--color-border-secondary-dark);box-shadow:0 1px 3px #ffffff1a}.similar-font-preview{align-items:center;background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);display:flex;flex-shrink:0;height:32px;justify-content:center;overflow:hidden;width:80px}.dark-mode .similar-font-preview{background:var(--color-bg-tertiary-dark)}.font-sprite{height:100%;object-fit:cover;width:100%}.dark-mode .font-glyph-small use,.dark-mode .font-letter-preview svg use,.dark-mode .font-sprite,.dark-mode .font-sprite use,.dark-mode .similar-font-glyph svg use{fill:#fff!important;color:#fff!important}.font-fallback{color:var(--color-text-secondary);font-size:14px;font-weight:600}.dark-mode .font-fallback{color:var(--color-text-secondary-dark)}.similar-font-glyph{align-items:center;display:flex;flex:0 0 auto;height:48px;justify-content:center;margin-left:-12px;margin-right:-8px;width:48px}.similar-font-glyph .font-glyph-small{height:32px;width:32px}.similar-font-info{display:flex;flex:0 0 auto;flex-direction:column;gap:2px;min-width:120px}.similar-font-sentence{align-items:center;display:flex;flex:1 1;justify-content:flex-end;min-height:49px;min-width:0;position:relative}.font-name{color:var(--color-text-primary);font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dark-mode .font-name{color:var(--color-text-primary-dark)}.font-family{color:var(--color-text-secondary);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dark-mode .font-family{color:var(--color-text-secondary-dark)}.similarity-score{background:#007acc1a;border-radius:10px;color:var(--color-accent);flex-shrink:0;font-size:10px;font-weight:600;padding:2px 6px}.dark-mode .similarity-score{background:#4fc3f71a;color:var(--color-accent-dark)}.no-similar{color:var(--color-text-secondary);font-size:12px;font-style:italic;padding:var(--spacing-md);text-align:center}.dark-mode .no-similar{color:var(--color-text-secondary-dark)}@media (max-width:1200px){.sidebar{min-width:350px;width:350px}}@media (max-width:768px){.fontmap-container{flex-direction:column}.sidebar{border-bottom:1px solid var(--color-border-primary);border-right:none;height:auto;left:0;max-height:none;min-width:0;overflow:visible;position:fixed;right:0;top:0;width:100%;z-index:2000}.dark-mode .sidebar{border-bottom-color:var(--color-border-primary-dark)}.sidebar-content{overflow:visible;padding:0}.sidebar-footer{display:none}.bottom-controls,.focus-hint{display:none!important}.font-details{background:var(--color-bg-primary);bottom:0;height:100vh;overflow-y:auto;padding-top:48px;position:fixed;right:0;top:0;transform:translateX(100%);transition:transform .28s ease;width:100%;z-index:3000}.dark-mode .font-details{background:var(--color-bg-primary-dark)}.fontmap-container.has-focus .font-details{transform:translateX(0)}.font-details-back{align-items:center;background:#0000;border:none;color:var(--color-text-primary);cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;gap:4px;left:12px;padding:6px 10px 6px 6px;position:absolute;top:12px;z-index:1}.dark-mode .font-details-back{color:var(--color-text-primary-dark)}.main-area{height:100vh;width:100%}.sidebar-content .sidebar-header,.sidebar-header{align-items:center;border-bottom:none;flex-direction:row;justify-content:space-between;margin-bottom:0;padding:var(--spacing-md)}.map-title{-webkit-text-stroke:12px var(--color-bg-primary);text-stroke:12px var(--color-bg-primary);font-size:24px;left:15px;top:15px}.dark-mode .map-title{-webkit-text-stroke:12px var(--color-bg-primary-dark);text-stroke:12px var(--color-bg-primary-dark)}.map-title:before{-webkit-text-stroke:13px var(--color-border-primary);text-stroke:13px var(--color-border-primary)}.dark-mode .map-title:before{-webkit-text-stroke:13px var(--color-border-primary-dark);text-stroke:13px var(--color-border-primary-dark)}.sidebar-content{gap:var(--spacing-md);padding:var(--spacing-md)}.sidebar-separator{margin:var(--spacing-md) 0}.top-controls{gap:6px;right:12px;top:12px}.bottom-controls{bottom:12px;gap:6px;right:12px}.filters-inline{font-size:11px}.toggle-btn{font-size:12px;padding:4px 8px}.dataset-select{font-size:10px;min-width:150px;padding:4px 8px}.zoom-btn{font-size:9px;padding:3px 6px}.font-details-section{padding:var(--spacing-md)}.font-preview{padding:var(--spacing-lg)}.font-preview-large{height:80px;width:80px}.font-info .font-name{font-size:20px}}@media (max-width:480px){.sidebar-header{flex-direction:column;gap:var(--spacing-sm);padding:var(--spacing-sm)}.map-title{-webkit-text-stroke:8px var(--color-bg-primary);text-stroke:8px var(--color-bg-primary);font-size:20px;left:10px;top:10px}.dark-mode .map-title{-webkit-text-stroke:8px var(--color-bg-primary-dark);text-stroke:8px var(--color-bg-primary-dark)}.map-title:before{-webkit-text-stroke:9px var(--color-border-primary);text-stroke:9px var(--color-border-primary)}.dark-mode .map-title:before{-webkit-text-stroke:9px var(--color-border-primary-dark);text-stroke:9px var(--color-border-primary-dark)}.sidebar-content{gap:var(--spacing-sm);padding:var(--spacing-sm)}.sidebar-separator{margin:var(--spacing-sm) 0}.top-controls{gap:4px;right:8px;top:8px}.bottom-controls{bottom:8px;gap:4px;right:8px}.filters-inline{font-size:10px}.toggle-btn{font-size:11px;padding:3px 6px}.dataset-select{font-size:9px;min-width:120px;padding:3px 6px}.zoom-btn{font-size:8px;padding:2px 4px}.font-details-section{padding:var(--spacing-sm)}.font-preview{padding:var(--spacing-md)}.font-preview-large{height:60px;width:60px}.font-info .font-name{font-size:18px}.preview-text{font-size:14px}}@media (max-width:768px){.dilation-control,.size-control{min-width:150px}.dilation-label,.size-label{font-size:10px}.slider-labels{font-size:9px}}@media (max-width:480px){.dilation-control,.size-control{min-width:120px}.dilation-label,.size-label{font-size:9px}.slider-labels{font-size:8px}}.unified-overlay{align-items:center;background:rgba(0,0,0,var(--overlay-opacity-dark));bottom:0;display:flex;justify-content:center;left:0;opacity:1;position:fixed;right:0;top:0;z-index:99999}.unified-overlay .loading{color:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:18px;font-weight:500;left:auto;line-height:1.2;margin:0;padding:0;position:static;text-align:center;top:auto;transform:none}.unified-overlay .overlay-spinner{animation:spin .8s linear infinite;border:3px solid #fff3;border-radius:50%;border-top-color:#fff;height:32px;width:32px}.dark-mode .unified-overlay .loading{color:#fff}.intro-modal{animation:introModalSlideIn .6s cubic-bezier(.16,1,.3,1);background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;max-height:80vh;max-width:420px;overflow:hidden;width:90%}.dark-mode .intro-modal{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}@keyframes introModalSlideIn{0%{opacity:0;transform:translateY(30px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.intro-modal-content{min-height:0;overflow-y:auto;padding:var(--spacing-xl);text-align:center}.intro-title{color:var(--color-text-primary);font-family:var(--font-logo);font-size:36px;font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0 0 var(--spacing-sm) 0}.dark-mode .intro-title{color:var(--color-text-primary-dark)}.intro-subtitle{color:var(--color-text-secondary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:16px;font-weight:400;line-height:1.4;margin:0 0 var(--spacing-md) 0}.dark-mode .intro-subtitle{color:var(--color-text-secondary-dark)}.intro-description{color:var(--color-text-tertiary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;font-weight:400;line-height:1.5;margin:0 0 var(--spacing-lg) 0}.dark-mode .intro-description{color:var(--color-text-tertiary-dark)}.intro-modal .google-fonts-link,.intro-modal .google-fonts-link:hover{background:none!important;border:none!important;color:var(--text-color)!important;font-weight:700}.intro-features{flex-direction:column;gap:var(--spacing-md);margin-bottom:var(--spacing-lg)}.intro-feature,.intro-features{align-items:center;display:flex}.intro-feature{color:var(--color-text-secondary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;font-weight:400;gap:var(--spacing-sm)}.dark-mode .intro-feature{color:var(--color-text-secondary-dark)}.intro-feature-icon{align-items:center;background:var(--color-bg-tertiary);border-radius:var(--border-radius-sm);color:var(--color-text-tertiary);display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.dark-mode .intro-feature-icon{background:var(--color-bg-tertiary-dark);color:var(--color-text-tertiary-dark)}.intro-feature-icon svg{height:16px;width:16px}.intro-start-button{align-items:center;background:#000;border:1px solid #000;border-radius:var(--border-radius-md);color:#fff;cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:var(--spacing-sm);justify-content:center;letter-spacing:.3px;padding:var(--spacing-md) var(--spacing-lg);text-decoration:none;text-transform:uppercase;transition:all var(--transition-normal);width:100%}.intro-start-button:hover{background:#333;border-color:#333;box-shadow:var(--shadow-md);transform:translateY(-1px)}.dark-mode .intro-start-button{background:#fff;border-color:#fff;color:#000}.dark-mode .intro-start-button:hover{background:#e0e0e0;border-color:#e0e0e0;box-shadow:0 2px 6px #ffffff1a}@media (max-width:600px){.intro-modal{margin:var(--spacing-lg);width:95%}.intro-modal-content{padding:var(--spacing-lg)}.intro-title{font-size:28px}.intro-subtitle{font-size:14px}.intro-description{font-size:12px}.intro-features{gap:var(--spacing-sm)}.intro-feature{font-size:12px}}.about-modal{animation:modalSlideIn .4s cubic-bezier(.16,1,.3,1);background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;max-height:85vh;max-width:900px;overflow:hidden;width:95%}.dark-mode .about-modal{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);box-shadow:0 8px 32px #0006}.about-modal-content{display:flex;flex:1 1;flex-direction:column;min-height:0}.about-modal-header{align-items:center;background:linear-gradient(135deg,var(--color-bg-secondary) 0,var(--color-bg-primary) 100%);border-bottom:1px solid var(--color-border-primary);display:flex;justify-content:space-between;padding:20px 24px 16px}.dark-mode .about-modal-header{background:linear-gradient(135deg,var(--color-bg-secondary-dark) 0,var(--color-bg-primary-dark) 100%);border-bottom-color:var(--color-border-primary-dark)}.about-title{color:var(--color-text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:24px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0}.dark-mode .about-title{color:var(--color-text-primary-dark)}.about-close-button{align-items:center;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-secondary);cursor:pointer;display:flex;justify-content:center;padding:8px;transition:all var(--transition-normal)}.about-close-button:hover{background:var(--color-bg-secondary);color:var(--color-text-primary)}.dark-mode .about-close-button{color:var(--color-text-secondary-dark)}.dark-mode .about-close-button:hover{background:var(--color-bg-secondary-dark);color:var(--color-text-primary-dark)}.about-modal-body{flex:1 1;min-height:0;overflow-y:auto;padding:20px 24px}.about-hero{margin-bottom:24px;text-align:center}.about-description{color:var(--color-text-primary);font-size:16px;line-height:1.6;margin:0 0 24px;text-align:left}.dark-mode .about-description{color:var(--color-text-primary-dark)}.about-section{margin-bottom:24px}.about-section:last-child{margin-bottom:0}.about-section-title{color:var(--color-text-tertiary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:12px;font-weight:600;letter-spacing:.08em;margin:0;text-transform:uppercase}.dark-mode .about-section-title{color:var(--color-text-tertiary-dark)}.about-column .about-section-title+.about-section-title,.about-column .code-link+.about-section-title{margin-top:16px}.about-section-text{color:var(--color-text-secondary);font-size:14px;line-height:1.5;margin:0}.dark-mode .about-section-text{color:var(--color-text-secondary-dark)}.about-content-grid{grid-gap:0;align-items:start;display:grid;gap:0;grid-template-columns:1.5fr 1fr;margin-top:24px}.about-column{display:flex;flex-direction:column;gap:16px}.about-column:first-child{padding-right:32px}.about-column:last-child{border-left:1px solid var(--color-border-primary);padding-left:32px}.dark-mode .about-column:last-child{border-left-color:var(--color-border-primary-dark)}.pipeline-demo{align-items:center;background:var(--color-bg-secondary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:16px 0;padding:20px}.dark-mode .pipeline-demo{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.pipeline-steps{display:flex;flex-direction:column;gap:0}.step-item{align-items:center;display:flex;gap:20px;padding:16px 0}.step-item:first-child{padding-top:8px}.step-item+.step-item{border-top:1px solid var(--color-border-primary)}.dark-mode .step-item+.step-item{border-top-color:var(--color-border-primary-dark)}.step-content{flex:1 1}.step-header{align-items:center;color:var(--color-text-primary);display:flex;gap:8px;margin-bottom:4px}.dark-mode .step-header{color:var(--color-text-primary-dark)}.step-number{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-text-secondary);border-radius:50%;color:var(--color-text-primary);display:flex;font-size:12px;font-weight:700;height:20px;justify-content:center;width:20px}.dark-mode .step-number{background:var(--color-bg-primary-dark);border-color:var(--color-text-secondary-dark);color:var(--color-text-primary-dark)}.step-description{color:var(--color-text-secondary);font-size:13px;line-height:1.4;margin:0}.dark-mode .step-description{color:var(--color-text-secondary-dark)}.step-example{align-items:center;display:flex;flex-direction:column;flex-shrink:0;justify-content:center;width:150px}.mini-matrix{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;color:var(--color-text-primary);font-family:Courier New,monospace;font-size:6px;line-height:1;padding:4px}.dark-mode .mini-matrix{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.mini-row{line-height:1.1;margin:0 0 1px;padding:0}.zero-value{opacity:.5}.vector-preview{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;color:var(--color-text-primary);font-family:Courier New,monospace;font-size:8px;font-weight:600;letter-spacing:-.3px;line-height:1.2;max-width:120px;padding:6px;word-break:break-all}.dark-mode .vector-preview{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-primary-dark)}.coordinates{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;flex-direction:column;font-family:Courier New,monospace;font-size:9px;gap:2px;padding:6px}.dark-mode .coordinates{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.coord{color:var(--color-accent);font-weight:600}.dark-mode .coord{color:var(--color-accent-dark)}.font-cluster-demo{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;gap:6px;padding:6px}.dark-mode .font-cluster-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.font-sample{color:var(--color-text-primary);font-size:12px;font-weight:600;line-height:1}.dark-mode .font-sample{color:var(--color-text-primary-dark)}.about-subtitle{color:var(--color-text-primary);font-size:16px;font-weight:600;margin:20px 0 8px}.dark-mode .about-subtitle{color:var(--color-text-primary-dark)}.code-link{align-self:flex-start;border:1px solid var(--color-border-secondary);border-radius:var(--border-radius-md);color:var(--color-text-primary);display:inline-block;font-size:13px;font-weight:600;padding:8px 14px;text-decoration:none;transition:all var(--transition-normal)}.code-link:hover{border-color:var(--color-text-primary);box-shadow:var(--shadow-sm)}.dark-mode .code-link{border-color:var(--color-border-secondary-dark);color:var(--color-text-primary-dark)}.dark-mode .code-link:hover{border-color:var(--color-text-primary-dark)}.inline-link{color:var(--color-text-primary);font-size:12px;font-weight:500;text-decoration:underline;transition:color var(--transition-normal)}.inline-link:hover{color:var(--color-text-secondary)}.dark-mode .inline-link{color:var(--color-text-primary-dark)}.dark-mode .inline-link:hover{color:var(--color-text-secondary-dark)}.multi-glyph-demo{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;flex-direction:column;gap:4px;padding:8px 10px}.dark-mode .multi-glyph-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.glyph-grid{color:var(--color-text-primary);display:flex;gap:8px}.dark-mode .glyph-grid{color:var(--color-text-primary-dark)}.glyph-grid-label{color:var(--color-text-secondary);font-family:Courier New,monospace;font-size:9px;opacity:.6}.dark-mode .glyph-grid-label{color:var(--color-text-secondary-dark)}.pipeline-flow{align-items:center;background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;font-family:Courier New,monospace;font-size:10px;gap:4px;padding:6px 8px}.dark-mode .pipeline-flow{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.pipeline-node{color:var(--color-text-primary);font-weight:500;white-space:nowrap}.dark-mode .pipeline-node{color:var(--color-text-primary-dark)}.pipeline-arrow{color:var(--color-text-secondary);opacity:.5}.dark-mode .pipeline-arrow{color:var(--color-text-secondary-dark)}@keyframes modalSlideIn{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}.about-modal .google-fonts-link{color:var(--color-text-primary);font-weight:500;text-decoration:underline;transition:color var(--transition-normal)}.about-modal .google-fonts-link:hover{color:var(--color-text-secondary)}.dark-mode .about-modal .google-fonts-link{color:var(--color-text-primary-dark)}.dark-mode .about-modal .google-fonts-link:hover{color:var(--color-text-secondary-dark)}.about-tech-list{list-style:none;margin:12px 0 16px;padding-left:0}.about-tech-list li{color:var(--color-text-secondary);font-size:14px;line-height:1.5;margin-bottom:8px;padding-left:20px;position:relative}.about-tech-list li:before{color:var(--color-accent);content:"→";font-weight:700;left:0;position:absolute}.about-tech-list li:last-child{margin-bottom:0}.dark-mode .about-tech-list li{color:var(--color-text-secondary-dark)}.dark-mode .about-tech-list li:before{color:var(--color-accent-dark)}.about-tech-list strong{color:var(--color-text-primary);font-weight:600}.dark-mode .about-tech-list strong{color:var(--color-text-primary-dark)}.pixel-matrix-demo{align-items:center;background:var(--color-bg-secondary);border:1px solid var(--color-border-primary);border-radius:var(--border-radius-md);display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:20px 0;padding:20px}.dark-mode .pixel-matrix-demo{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.demo-step{align-items:center;display:flex;flex-direction:column;gap:8px;min-width:120px}.demo-label{color:var(--color-accent);font-size:12px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.dark-mode .demo-label{color:var(--color-accent-dark)}.pixel-matrix{background:#fff;border:1px solid var(--color-border-primary);border-radius:2px;font-family:Courier New,monospace;font-size:8px;line-height:1;padding:4px}.dark-mode .pixel-matrix{background:var(--color-bg-secondary-dark);border-color:var(--color-border-primary-dark)}.pixel-row{line-height:1.2;margin:0 0 1px;padding:0}.vector-demo{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;color:var(--color-text-secondary);font-family:Courier New,monospace;font-size:8px;line-height:1.2;max-width:200px;padding:6px;word-break:break-all}.dark-mode .vector-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark);color:var(--color-text-secondary-dark)}.umap-demo{background:var(--color-bg-primary);border:1px solid var(--color-border-primary);border-radius:2px;display:flex;flex-direction:column;font-family:Courier New,monospace;font-size:10px;gap:2px;padding:8px}.dark-mode .umap-demo{background:var(--color-bg-primary-dark);border-color:var(--color-border-primary-dark)}.coordinate{color:var(--color-accent);font-weight:600}.dark-mode .coordinate{color:var(--color-accent-dark)}.demo-caption{color:var(--color-text-secondary);font-size:10px;font-style:italic;text-align:center}.dark-mode .demo-caption{color:var(--color-text-secondary-dark)}.demo-arrow{color:var(--color-accent);font-size:16px;font-weight:700}.dark-mode .demo-arrow{color:var(--color-accent-dark)}@media (max-width:768px){.about-modal{max-width:95%;width:95%}.about-content-grid{gap:24px;grid-template-columns:1fr}.about-column:first-child{padding-right:0}.about-column:last-child{border-left:none;border-top:1px solid var(--color-border-primary);padding-left:0;padding-top:24px}.dark-mode .about-column:last-child{border-top-color:var(--color-border-primary-dark)}.step-item{align-items:flex-start;flex-direction:column;gap:12px}.step-example{align-self:center;width:100%}.mini-matrix{font-size:5px}.vector-preview{font-size:7px;max-width:100px}.coordinates{font-size:8px}}@media (max-width:480px){.about-modal-header{padding:16px 20px 12px}.about-modal-body{padding:16px 20px}.about-title{font-size:20px}.info-card,.pipeline-demo{padding:12px}}
|
| 2 |
+
/*# sourceMappingURL=632.abaca8bf.chunk.css.map*/
|
build/static/css/632.abaca8bf.chunk.css.map
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/static/js/{632.d7330879.chunk.js → 632.2f16deee.chunk.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
| 1 |
-
(self.webpackChunkfontmap=self.webpackChunkfontmap||[]).push([[632],{632:(e,t,n)=>{"use strict";n.r(t),n.d(t,{FontMap:()=>R});var s=n(5043),o=n(5439),r=n(6907);var a=n(2491);const i=(0,n(4131).v)((e,t)=>({selectedFont:null,hoveredFont:null,characterSize:1.5,variantSizeImpact:!1,useCategoryColors:!1,isTransitioning:!1,debugMode:!1,setSelectedFont:t=>e({selectedFont:t}),setHoveredFont:t=>e({hoveredFont:t}),setCharacterSize:t=>e({characterSize:t}),setVariantSizeImpact:t=>e({variantSizeImpact:t}),setUseCategoryColors:t=>e({useCategoryColors:t}),setIsTransitioning:t=>e({isTransitioning:t}),setDebugMode:t=>e({debugMode:t}),resetState:()=>{e({selectedFont:null,hoveredFont:null,isTransitioning:!1,characterSize:1.5,variantSizeImpact:!1,useCategoryColors:!1,debugMode:!1})}})),l=1600,c=900,d={"sans-serif":"#3498db",serif:"#e74c3c",display:"#f39c12",handwriting:"#9b59b6",monospace:"#2ecc71"};function u(e,t,n){return t?d[e]||"#95a5a6":n?"#ffffff":"#333333"}function h(e){let{svgRef:t,fonts:n,glyphPaths:o,filter:r,searchTerm:h,darkMode:f,loading:m,enabled:p=!0,isMobile:g=!1}=e;const x=(0,s.useRef)({mapX:null,mapY:null}),v=(0,s.useRef)({width:l,height:c}),j=(0,s.useRef)(!1),y=(0,s.useRef)(null),w=i(e=>e.selectedFont),b=i(e=>e.setSelectedFont),k=i(e=>e.setHoveredFont),N=i(e=>e.useCategoryColors);return y.current=w,(0,s.useEffect)(()=>{if(!p||!n||0===n.length||!t.current)return;const e=a.Ltv(t.current);e.attr("width","100%").attr("height","100%").attr("viewBox","0 0 ".concat(l," ").concat(c));const s=function(e){let t=e.select(".viewport-group");return t.empty()&&(t=e.append("g").attr("class","viewport-group")),t}(e);s.selectAll("g.glyph-group").remove();const{mapX:r,mapY:i}=function(e,t,n){let s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:40;const o=e.map(e=>e.x),r=e.map(e=>e.y),a=Math.min(...o),i=Math.max(...o),l=Math.min(...r),c=Math.max(...r),d=i-a,u=c-l,h=Math.max(1,t-2*s),f=Math.max(1,n-2*s),m=Math.min(h/d,f/u),p=(t-d*m)/2,g=(n-u*m)/2;return{mapX:e=>(e-a)*m+p,mapY:e=>(c-e)*m+g}}(n,l,c);x.current={mapX:r,mapY:i};const d=o&&Object.keys(o).length>0,h=s.node(),m="http://www.w3.org/2000/svg";n.forEach(e=>{const t=(e.imageName||e.name||"").toLowerCase(),n=d?o["".concat(e.id,"_a")]||o[e.id]||o["".concat(t,"_a")]||o[t]:null;if(!n)return;const s=r(e.x),a=i(e.y),l=u(e.family,N,f),c=document.createElementNS(m,"g");c.setAttribute("transform","translate(".concat(s,", ").concat(a,") scale(").concat(.25,")")),c.setAttribute("data-original-transform","translate(".concat(s,", ").concat(a,")")),c.setAttribute("data-font",e.name),c.setAttribute("data-font-id",e.id),c.setAttribute("data-font-name",e.name),c.setAttribute("data-category",e.family),c.setAttribute("class","glyph-group"),c.style.cursor="pointer";const p=document.createElementNS(m,"circle");p.setAttribute("class","glyph-hitbox"),p.setAttribute("cx","40"),p.setAttribute("cy","40"),p.setAttribute("r","44"),p.setAttribute("fill","transparent"),p.setAttribute("pointer-events","all"),c.appendChild(p);const g=document.createElementNS(m,"path");g.setAttribute("d",n),g.setAttribute("fill",l),g.setAttribute("pointer-events","none"),c.appendChild(g),h.appendChild(c)}),j.current=!0},[p,n,o,f,N,t]),(0,s.useEffect)(()=>{t.current&&t.current.querySelectorAll("g.glyph-group").forEach(e=>{const t=u(e.getAttribute("data-category"),N,f);e.querySelectorAll("path").forEach(e=>{e.setAttribute("fill",t)})})},[f,N,t]),(0,s.useEffect)(()=>{if(!t.current||!n||0===n.length)return;const e=a.Ltv(t.current),s=e.select(".viewport-group");if(s.empty())return;e.selectAll(".centroids-group").remove();const{mapX:o,mapY:r}=x.current;if(!o||!r)return;const i={};n.forEach(e=>{const t=e.family;i[t]||(i[t]={x:0,y:0,n:0}),i[t].x+=e.x,i[t].y+=e.y,i[t].n+=1});const u=s.attr("transform")||"",h=e.append("g").attr("class","centroids-group").attr("transform",u).style("pointer-events","none").style("user-select","none"),m=N?null:f?"#ffffff":"#000000",p=f?"#000000":"#ffffff";Object.entries(i).forEach(e=>{let[t,n]=e;const s=o(n.x/n.n),a=r(n.y/n.n),i=m||d[t]||"#95a5a6";h.append("text").attr("x",s).attr("y",a).attr("text-anchor","middle").attr("font-weight","bold").attr("fill",i).attr("stroke",p).attr("paint-order","stroke fill").attr("class","centroid-label").text(t)});const g=t.current,v=()=>{const e=g.getBoundingClientRect();if(!e.width||!e.height)return;const t=Math.min(e.width/l,e.height/c),n=a._V(g).k||1,s=13/(n*t);let o=1;n>=3.2?o=0:n>2.2&&(o=1-(n-2.2)/1),h.selectAll(".centroid-label").attr("font-size",s).attr("stroke-width",.5*s).attr("opacity",o)};v(),window.updateCentroidLabels=v;let j=null;return"undefined"!==typeof ResizeObserver&&(j=new ResizeObserver(v),j.observe(g)),()=>{j&&j.disconnect(),delete window.updateCentroidLabels}},[n,N,f,t]),(0,s.useEffect)(()=>{if(!t.current)return;const e=a.Ltv(t.current),n=e.select(".viewport-group");if(!n.empty())if(e.selectAll(".highlight-group").remove(),w){n.attr("opacity",.1);const t=n.select('g.glyph-group[data-font-id="'.concat(w.id,'"]'));if(!t.empty()){const s=n.attr("transform")||"",o=e.append("g").attr("class","highlight-group").attr("transform",s).style("pointer-events","none"),r=t.node().cloneNode(!0);r.setAttribute("opacity","1"),o.node().appendChild(r)}n.selectAll("g.glyph-group").style("pointer-events","all")}else{n.attr("opacity",1);if("all"!==r||h){const e=h?h.toLowerCase():"";n.selectAll("g.glyph-group").each(function(){const t=this,n=t.getAttribute("data-category"),s=t.getAttribute("data-font-name"),o="all"===r||n===r,a=!e||s&&s.toLowerCase().includes(e)||n&&n.toLowerCase().includes(e),i=o&&a;t.setAttribute("opacity",i?"1":"0.06"),t.style.pointerEvents=i?"all":"none"})}else n.selectAll("g.glyph-group").each(function(){this.removeAttribute("opacity"),this.style.pointerEvents="all"})}},[r,h,w,t]),(0,s.useEffect)(()=>{if(!t.current||!n||0===n.length)return;const e=t.current,s=t=>{let n=t;for(;n&&n!==e;){if(n.classList&&n.classList.contains("glyph-group"))return n;n=n.parentElement}return null},o=e=>{const t=e.getAttribute("data-font-id");return n.find(e=>e.id===t)||null};let r=null;const a=e=>{if(i.getState().isTransitioning)return;if(g)return;const t=s(e.target);if(!t)return;const n=o(t);n&&(clearTimeout(r),r=setTimeout(()=>k(n),80))},l=e=>{if(g)return;if(i.getState().isTransitioning)return;s(e.target)&&(clearTimeout(r),k(null))},c=e=>{clearTimeout(r);const t=s(e.target);if(g){const e=i.getState().hoveredFont;if(!t)return void(e&&k(null));const n=o(t);if(!n)return;return void k(e&&e.id===n.id?null:n)}if(!t)return void(y.current&&b(null));const n=o(t);if(!n)return;k(null);const a=y.current;b(a&&a.id===n.id?null:n)};return e.addEventListener("mouseover",a),e.addEventListener("mouseout",l),e.addEventListener("click",c),()=>{clearTimeout(r),e.removeEventListener("mouseover",a),e.removeEventListener("mouseout",l),e.removeEventListener("click",c)}},[n,b,k,t,g]),{mappingRef:x,dimensionsRef:v}}const f=.8,m=[f,10],p=a.GSI.translate(159.99999999999997,89.99999999999999).scale(f);var g=n(579);const x=e=>{let{fonts:t,filter:n,onFilterChange:s}=e;const o=[...new Set(t.map(e=>e.family))];return(0,g.jsxs)("div",{className:"filters-container",children:[(0,g.jsx)("div",{className:"filters-label",children:"Families"}),(0,g.jsx)("div",{className:"filters-inline",children:o.map(e=>(0,g.jsxs)("span",{className:"filter-link ".concat(n===e?"active":""),onClick:()=>s(n===e?"all":e),children:[e," ",(0,g.jsx)("span",{className:"filter-count",children:t.filter(t=>t.family===e).length})]},e))})]})},v=e=>{let{searchTerm:t,onSearchChange:n,darkMode:s,big:o=!1,filteredCount:r=null,totalCount:a=null,filter:i="all"}=e;const l=null!==r&&null!==a,c=l&&(r!==a||"all"!==i);return(0,g.jsxs)("div",{className:"search-bar ".concat(o?"search-bar-big":""),children:[(0,g.jsx)("input",{type:"text",placeholder:"Search fonts...",value:t,onChange:e=>n(e.target.value),className:"search-input ".concat(s?"dark":"")}),(0,g.jsxs)("div",{className:"search-controls",children:[t&&(0,g.jsx)("button",{className:"search-clear",onClick:()=>n(""),title:"Clear search",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),(0,g.jsx)("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}),l&&(0,g.jsx)("div",{className:"search-counter ".concat(s?"dark":""," ").concat(c?"filtered":""),children:c?(0,g.jsxs)("span",{className:"counter-text",children:[r," of ",a]}):(0,g.jsxs)("span",{className:"counter-text",children:[a," fonts"]})})]})]})},j=()=>(0,g.jsxs)("div",{className:"zoom-controls",children:[(0,g.jsx)("button",{className:"zoom-btn zoom-in",onClick:()=>window.zoomIn&&window.zoomIn(),title:"Zoom In",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"M21 21l-4.35-4.35"}),(0,g.jsx)("line",{x1:"11",y1:"8",x2:"11",y2:"14"}),(0,g.jsx)("line",{x1:"8",y1:"11",x2:"14",y2:"11"})]})}),(0,g.jsx)("button",{className:"zoom-btn zoom-out",onClick:()=>window.zoomOut&&window.zoomOut(),title:"Zoom Out",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"M21 21l-4.35-4.35"}),(0,g.jsx)("line",{x1:"8",y1:"11",x2:"14",y2:"11"})]})}),(0,g.jsx)("button",{className:"zoom-btn zoom-reset",onClick:()=>window.resetZoom&&window.resetZoom(),title:"Reset Zoom",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"}),(0,g.jsx)("path",{d:"M3 3v5h5"})]})})]}),y=()=>{const e=i(e=>e.useCategoryColors),t=i(e=>e.setUseCategoryColors);return(0,g.jsx)("div",{className:"category-legend",children:(0,g.jsxs)("label",{className:"category-legend-toggle",children:[(0,g.jsx)("input",{type:"checkbox",checked:e,onChange:e=>t(e.target.checked)}),(0,g.jsx)("span",{children:"Category colors"})]})})};var w=n(2555);const b=e=>e?e.toLowerCase()+"_a":"fallback_a",k=e=>{let{size:t="16px",color:n="currentColor",className:s="",minHeight:o=null,centered:r=!0}=e;const a=(0,g.jsx)("div",{className:"spinner ".concat(s),style:{width:t,height:t,border:"2px solid transparent",borderTop:"2px solid ".concat(n),borderRadius:"50%",animation:"spin 1s linear infinite",display:"inline-block"}});return o?(0,g.jsx)("div",{style:{minHeight:o,display:r?"flex":"block",justifyContent:r?"center":"flex-start",alignItems:r?"center":"flex-start",width:"100%",boxSizing:"border-box"},children:a}):a},N=["Arial, sans-serif","Times New Roman, serif","Georgia, serif","Helvetica, sans-serif","Courier New, monospace","Verdana, sans-serif","Trebuchet MS, sans-serif","Tahoma, sans-serif"],C=e=>{let{selectedFont:t,fonts:n,darkMode:o,onClose:r,onFontSelect:a}=e;const[i,l]=(0,s.useState)(!1),[c,d]=(0,s.useState)(!1),[u,h]=(0,s.useState)({}),f=(0,s.useRef)({}),m=(0,s.useRef)(null),[p,x]=(0,s.useState)(0);(0,s.useEffect)(()=>{l(!1),d(!1),h({}),Object.values(f.current).forEach(e=>clearTimeout(e)),f.current={},m.current&&(clearTimeout(m.current),m.current=null);const e=setTimeout(()=>l(!0),100);return m.current=setTimeout(()=>d(!0),500),()=>{clearTimeout(e),m.current&&clearTimeout(m.current)}},[t]),(0,s.useEffect)(()=>{if(t)return;const e=setInterval(()=>{x(e=>(e+1)%N.length)},200);return()=>clearInterval(e)},[t]);const v=(0,s.useCallback)(e=>{f.current[e]&&(clearTimeout(f.current[e]),delete f.current[e]),h(t=>(0,w.A)((0,w.A)({},t),{},{[e]:!0}))},[]),j=(0,s.useMemo)(()=>{if(!t||!n||0===n.length)return[];const e=n.find(e=>e.name===t.name);if(!e)return[];if(e.neighbors&&e.neighbors.length>0){const t=new Map(n.map(e=>[e.id,e]));return e.neighbors.map((e,n)=>{const s=t.get(e);return s?{font:s,distance:n+1}:null}).filter(Boolean).slice(0,4)}return n.filter(e=>e.name!==t.name).map(t=>{const n=t.x-e.x,s=t.y-e.y;return{font:t,distance:Math.sqrt(n*n+s*s)}}).sort((e,t)=>e.distance-t.distance).slice(0,4)},[t,n]);if((0,s.useEffect)(()=>{if(0===j.length)return;const e={};return j.forEach(t=>{let{font:n}=t;if(!u[n.name]&&!f.current[n.name]){const t=setTimeout(()=>{v(n.name)},1e3);f.current[n.name]=t,e[n.name]=t}}),()=>{Object.values(e).forEach(e=>clearTimeout(e))}},[j,u,v]),!t)return(0,g.jsx)("div",{className:"font-details",children:(0,g.jsxs)("div",{className:"font-details-placeholder",children:[(0,g.jsx)("div",{className:"placeholder-icon",children:(0,g.jsxs)("svg",{width:"64",height:"64",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"m21 21-4.35-4.35"}),(0,g.jsx)("text",{x:"11",y:"14",textAnchor:"middle",fontSize:"10",fill:"currentColor",fontWeight:"100",opacity:.65,style:{fontFamily:N[p],fontStyle:"normal",fontVariant:"normal"},children:"A"})]})}),(0,g.jsxs)("div",{className:"placeholder-content",children:[(0,g.jsx)("h3",{children:"Explore fonts"}),(0,g.jsx)("p",{children:"Click any font on the map to discover its details and find similar typefaces."})]})]})});const y=b(t.imageName||t.name),C=t.family||"sans-serif",S=t.google_fonts_url||(e=>{if(!e)return null;const t=e.trim().replace(/\s+/g,"+").replace(/[^\w\s+]/g,"").replace(/\s+/g,"+");return"https://fonts.google.com/specimen/".concat(t)})(t.name),L=t.fusionInfo&&t.fusionInfo.merged,M=t.variantCount||1;return(0,g.jsxs)("div",{className:"font-details",children:[(0,g.jsxs)("button",{type:"button",className:"font-details-back",onClick:r,"aria-label":"Back to map",children:[(0,g.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:(0,g.jsx)("polyline",{points:"15 18 9 12 15 6"})}),(0,g.jsx)("span",{children:"Back"})]}),(0,g.jsxs)("div",{className:"font-details-content",children:[(0,g.jsx)("div",{className:"active-font-label",children:"Active Font"}),(0,g.jsxs)("div",{className:"active-font-card",children:[(0,g.jsxs)("div",{className:"active-font-content",children:[(0,g.jsxs)("div",{className:"font-letter-preview",children:[!i&&(0,g.jsx)(k,{size:"20px",color:o?"#ffffff":"#000000",minHeight:"120px",centered:!0}),(0,g.jsx)("svg",{width:"120",height:"120",viewBox:"0 0 120 120",style:{display:i?"block":"none",transition:"opacity 0.15s ease-in-out"},children:y&&(0,g.jsx)("use",{href:"#".concat(y),fill:o?"#ffffff":"#000000",style:{fill:o?"#ffffff":"#000000"}})})]}),(0,g.jsxs)("div",{className:"font-info-compact",children:[(0,g.jsx)("h2",{className:"font-name-compact",children:t.name}),L&&(0,g.jsx)("div",{className:"font-fusion-badge",style:{display:"inline-flex",alignItems:"center",gap:"4px",color:o?"#ffffff":"#000000"},children:(0,g.jsxs)("span",{className:"fusion-text",children:[M," variants"]})}),(0,g.jsx)("p",{className:"font-category-compact",children:C}),(0,g.jsxs)("div",{className:"font-metadata",children:[t.weights&&t.weights.length>0&&(0,g.jsx)("span",{className:"font-weights",children:t.weights.join(", ")}),t.styles&&t.styles.length>0&&(0,g.jsx)("span",{className:"font-styles",children:t.styles.join(", ")})]})]})]}),(0,g.jsxs)("div",{className:"font-sentence-compact",children:[!c&&(0,g.jsx)(k,{size:"16px",color:o?"#ffffff":"#000000",minHeight:"49px",centered:!0,className:"sentence-preview-spinner"}),(0,g.jsx)("img",{src:"/data/sentences/".concat((t.imageName||t.name).toLowerCase().replace(/\s+/g,"_"),"_sentence.svg"),alt:"".concat(t.name," sentence preview"),style:{width:"100%",height:"auto",maxWidth:"100%",minHeight:"49px",filter:o?"invert(1)":"none",display:c?"block":"none",transition:"opacity 0.15s ease-in-out"},onLoad:()=>d(!0),onError:e=>{e.target.style.display="none",d(!0)}})]}),(0,g.jsx)("div",{className:"font-action-section",children:(0,g.jsxs)("a",{href:S||"#",target:"_blank",rel:"noopener noreferrer",className:"action-btn ghost google-fonts-link",title:"View ".concat(t.name," on Google Fonts"),style:{display:S?"flex":"none"},children:["Find on Google Fonts",(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"}),(0,g.jsx)("polyline",{points:"15,3 21,3 21,9"}),(0,g.jsx)("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})]})})]}),(0,g.jsxs)("div",{className:"similar-fonts",children:[(0,g.jsx)("h4",{className:"similar-fonts-title",children:"Similar Fonts"}),0===j.length?(0,g.jsx)("p",{className:"no-similar",children:"No similar fonts found"}):(0,g.jsx)("div",{className:"similar-fonts-list",children:j.map(e=>{let{font:t,distance:n}=e;const s=t.imageName||t.name,r="/data/sentences/".concat(s.toLowerCase().replace(/\s+/g,"_"),"_sentence.svg");return(0,g.jsxs)("div",{className:"similar-font-item",title:"".concat(t.name," (distance: ").concat(n.toFixed(2),")"),onClick:()=>a&&a(t),children:[(0,g.jsx)("div",{className:"similar-font-glyph",children:(0,g.jsx)("svg",{width:"32",height:"32",viewBox:"0 0 24 24",className:"font-glyph-small",children:(0,g.jsx)("use",{href:"#".concat(b(t.imageName||t.name)),fill:o?"#ffffff":"#000000",style:{fill:o?"#ffffff":"#000000"}})})}),(0,g.jsxs)("div",{className:"similar-font-info",children:[(0,g.jsx)("span",{className:"font-name",children:t.name}),(0,g.jsx)("span",{className:"font-family",children:t.family})]}),(0,g.jsxs)("div",{className:"similar-font-sentence",children:[!u[t.name]&&(0,g.jsx)(k,{size:"16px",color:o?"#ffffff":"#000000",minHeight:"49px",centered:!0,className:"similar-font-spinner"}),(0,g.jsx)("img",{src:r,alt:"".concat(t.name," sentence preview"),style:{height:"auto",minHeight:"49px",maxHeight:"49px",maxWidth:"100%",objectFit:"contain",filter:o?"invert(1)":"none",display:u[t.name]?"block":"none",transition:"opacity 0.15s ease-in-out"},onLoad:()=>{v(t.name)},onError:e=>{e.target.style.display="none",v(t.name)}})]})]},t.name)})})]})]})]})},S=e=>{let{darkMode:t,isMobile:n,onOpenFont:o}=e;const r=i(e=>e.selectedFont),l=i(e=>e.hoveredFont),{handleFontSelect:c,handleFontHover:d,handleFontUnhover:u,updateTransform:h,updatePositions:f}=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const o=(0,s.useRef)(null),r=(0,s.useRef)(null),i=(0,s.useRef)(a.GSI),l=(0,s.useRef)(new Map),c=(0,s.useRef)(null),d=(0,s.useRef)(n);(0,s.useEffect)(()=>{d.current=n},[n]);const u=(0,s.useMemo)(()=>({dark:{backgroundColor:"#000000",borderColor:"#404040",color:"#ffffff"},light:{backgroundColor:"#ffffff",borderColor:"#e0e0e0",color:"#000000"}}),[]);(0,s.useEffect)(()=>{o.current=a.Ltv("body").append("div").attr("class","font-tooltip font-tooltip-selected").style("opacity",0).style("position","absolute").style("pointer-events","none").style("z-index",1001).style("transition","opacity 0.2s ease"),r.current=a.Ltv("body").append("div").attr("class","font-tooltip font-tooltip-hover").style("opacity",0).style("position","absolute").style("pointer-events","none").style("z-index",1e3).style("transition","opacity 0.2s ease");const e=e=>{if(!e.target.closest(".tooltip-open-btn"))return;const t=c.current,n=d.current;t&&n&&n(t)},t=r.current.node();return t&&t.addEventListener("click",e),()=>{t&&t.removeEventListener("click",e),a.Ubm(".font-tooltip").remove();const n=l.current;n.forEach(e=>clearTimeout(e)),n.clear()}},[]),(0,s.useEffect)(()=>{const t=t=>{if(!t)return;t.classed("dark-mode",e);const n=e?u.dark:u.light;t.style("background-color",n.backgroundColor).style("border-color",n.borderColor).style("color",n.color)};t(o.current),t(r.current)},[e,u]);const h=(0,s.useCallback)(e=>{const n=e.imageName||e.name,s="/data/sentences/".concat(n.toLowerCase().replace(/\s+/g,"_"),"_sentence.svg"),o=t?'<button type="button" class="tooltip-open-btn">Open</button>':"";return'\n <div class="simple-tooltip">\n <div class="tooltip-font-name">'.concat(e.name,'</div>\n <div class="tooltip-sentence-preview">\n <div class="tooltip-image-container" style="position: relative; min-height: 44px; display: flex; align-items: center; justify-content: center;">\n <img src="').concat(s,'"\n alt=""\n class="sentence-image"\n style="max-width: 200px; height: auto; opacity: 0; transition: opacity 0.2s ease;"\n onload="this.style.opacity=\'1\'; this.parentElement.querySelector(\'.tooltip-spinner\').style.display=\'none\';"\n onerror="this.style.display=\'none\'; this.parentElement.querySelector(\'.tooltip-spinner\').style.display=\'flex\'; this.parentElement.querySelector(\'.tooltip-spinner\').innerHTML=\'\u26a0\ufe0f Loading error\';"\n />\n <div class="tooltip-spinner" style="display: flex; align-items: center; justify-content: center; font-size: 12px; position: absolute; top: 0; left: 0; right: 0; bottom: 0;">\n <div style="width: 16px; height: 16px; border: 2px solid transparent; border-top: 2px solid currentColor; border-radius: 50%; animation: spin 1s linear infinite; margin-right: 8px;"></div>\n Loading...\n </div>\n </div>\n </div>\n ').concat(o,"\n </div>\n ")},[t]),f=(0,s.useCallback)((e,t)=>{if(!e||!t)return;const n=e.node().getBoundingClientRect(),s=t.getBoundingClientRect();let o=s.left+s.width/2-n.width/2,r=s.top-n.height-6;o<10&&(o=10),o+n.width>window.innerWidth-10&&(o=window.innerWidth-n.width-10),r<10&&(r=s.bottom+6),e.style("left","".concat(o,"px")).style("top","".concat(r,"px"))},[]),m=(0,s.useCallback)((e,t,n)=>{e&&t&&(e===r.current&&(c.current=t),e.html(h(t)),f(e,n),e.style("opacity",1))},[h,f]),p=(0,s.useCallback)(e=>{e&&e.style("opacity",0)},[]),g=(0,s.useCallback)(()=>{const e=a.Ltv(".fontmap-svg");if(e.empty())return;const t=e.select(".viewport-group");if(!t.empty()){if(o.current&&"0"!==o.current.style("opacity")){var n;const e=null===(n=window.currentSelectedFont)||void 0===n?void 0:n.name;if(e){const n=t.node().querySelector('[data-font="'.concat(CSS.escape(e),'"]'));n&&f(o.current,n)}}if(r.current&&"0"!==r.current.style("opacity")){var s;const e=null===(s=window.currentHoveredFont)||void 0===s?void 0:s.name;if(e){const n=t.node().querySelector('[data-font="'.concat(CSS.escape(e),'"]'));n&&f(r.current,n)}}}},[f]),x=(0,s.useCallback)(e=>{i.current=e,setTimeout(()=>{g()},0)},[g]);return{handleFontSelect:(0,s.useCallback)((e,t)=>{e?(p(r.current),m(o.current,e,t)):p(o.current)},[m,p]),handleFontHover:(0,s.useCallback)((e,t)=>{e?m(r.current,e,t):p(r.current)},[m,p]),handleFontUnhover:(0,s.useCallback)(()=>{p(r.current)},[p]),updateTransform:x,updatePositions:g}}(t,n,o);return(0,s.useEffect)(()=>{if(r){const e=document.querySelector(".fontmap-svg");if(e){const t=e.querySelector(".viewport-group");if(t){const e=t.querySelector('[data-font="'.concat(CSS.escape(r.name),'"]'));e&&c(r,e)}}}else c(null)},[r,c]),(0,s.useEffect)(()=>{if(!l||r&&r.name===l.name)l||u();else{const e=document.querySelector(".fontmap-svg");if(e){const t=e.querySelector(".viewport-group");if(t){const e=t.querySelector('[data-font="'.concat(CSS.escape(l.name),'"]'));e&&d(l,e)}}}},[l,r,d,u]),(0,s.useEffect)(()=>(window.updateTooltipPositions=f,window.updateTooltipTransform=h,window.currentSelectedFont=r,window.currentHoveredFont=l,()=>{delete window.updateTooltipPositions,delete window.updateTooltipTransform,delete window.currentSelectedFont,delete window.currentHoveredFont}),[f,h,r,l]),null};var L=n(7950);const M=e=>{let{children:t,isOpen:n}=e;return n?(0,L.createPortal)(t,document.body):null},F=e=>{let{onStartExploring:t,darkMode:n}=e;return(0,g.jsx)(M,{isOpen:!0,children:(0,g.jsx)("div",{className:"unified-overlay",onClick:t,children:(0,g.jsx)("div",{className:"intro-modal",onClick:e=>e.stopPropagation(),children:(0,g.jsxs)("div",{className:"intro-modal-content",children:[(0,g.jsx)("h1",{className:"intro-title",children:"FontMap"}),(0,g.jsx)("p",{className:"intro-subtitle",children:"Using artificial intelligence to surface new relationships across fonts."}),(0,g.jsxs)("p",{className:"intro-description",children:["This interactive map of more than 1100+ ",(0,g.jsx)("a",{href:"https://fonts.google.com",target:"_blank",rel:"noopener noreferrer",className:"google-fonts-link",children:"Google Fonts"})," has been organized using machine learning."]}),(0,g.jsxs)("div",{className:"intro-features",children:[(0,g.jsxs)("div",{className:"intro-feature",children:[(0,g.jsx)("div",{className:"intro-feature-icon",children:(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("path",{d:"M21 3l-6 6"}),(0,g.jsx)("path",{d:"M3 21l6-6"}),(0,g.jsx)("path",{d:"M21 3l-6 6"}),(0,g.jsx)("path",{d:"M3 21l6-6"}),(0,g.jsx)("circle",{cx:"12",cy:"12",r:"3"})]})}),(0,g.jsx)("span",{children:"Pan and Zoom to explore"})]}),(0,g.jsxs)("div",{className:"intro-feature",children:[(0,g.jsx)("div",{className:"intro-feature-icon",children:(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"m21 21-4.35-4.35"})]})}),(0,g.jsx)("span",{children:"Search for a font by name"})]})]}),(0,g.jsx)("button",{className:"intro-start-button",onClick:t,children:"START EXPLORING"})]})})})})},E=e=>{let{onClose:t,darkMode:n}=e;return(0,g.jsx)(M,{isOpen:!0,children:(0,g.jsx)("div",{className:"unified-overlay",onClick:t,children:(0,g.jsx)("div",{className:"about-modal",onClick:e=>e.stopPropagation(),children:(0,g.jsxs)("div",{className:"about-modal-content",children:[(0,g.jsxs)("div",{className:"about-modal-header",children:[(0,g.jsx)("h1",{className:"about-title",children:"How FontMap Works"}),(0,g.jsx)("button",{className:"about-close-button",onClick:t,title:"Close",children:(0,g.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),(0,g.jsx)("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),(0,g.jsxs)("div",{className:"about-modal-body",children:[(0,g.jsxs)("p",{className:"about-description",children:["FontMap uses ",(0,g.jsx)("strong",{children:"FontCLIP"}),", a vision model fine-tuned for typography, to build an interactive map of font relationships. Each font is encoded into a rich embedding, then projected onto a 2D plane via ",(0,g.jsx)("strong",{children:"UMAP"})," so that visually similar fonts cluster together."]}),(0,g.jsxs)("div",{className:"about-content-grid",children:[(0,g.jsxs)("div",{className:"about-column",children:[(0,g.jsx)("h3",{className:"about-section-title",children:"Technical Process"}),(0,g.jsxs)("div",{className:"pipeline-steps",children:[(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"1"}),(0,g.jsx)("strong",{children:"Multi-Glyph Rendering"})]}),(0,g.jsxs)("p",{className:"step-description",children:["Each font is rendered as a ",(0,g.jsx)("strong",{children:"224 \xd7 224"})," composite image showing multiple representative glyphs, capturing the full typographic character"]})]}),(0,g.jsx)("div",{className:"step-example",children:(0,g.jsxs)("div",{className:"multi-glyph-demo",children:[(0,g.jsxs)("div",{className:"glyph-grid",children:[(0,g.jsx)("span",{style:{fontFamily:"Georgia, serif",fontSize:"18px",fontWeight:"bold"},children:"Aa"}),(0,g.jsx)("span",{style:{fontFamily:"Georgia, serif",fontSize:"18px"},children:"Bb"}),(0,g.jsx)("span",{style:{fontFamily:"Georgia, serif",fontSize:"18px"},children:"Rr"})]}),(0,g.jsx)("div",{className:"glyph-grid-label",children:"224 \xd7 224"})]})})]}),(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"2"}),(0,g.jsx)("strong",{children:"FontCLIP Embeddings"})]}),(0,g.jsxs)("p",{className:"step-description",children:["A ",(0,g.jsx)("strong",{children:"CLIP ViT-B/32"})," model ",(0,g.jsx)("a",{href:"https://github.com/yukistavailable/FontCLIP",target:"_blank",rel:"noopener noreferrer",className:"inline-link",children:"fine-tuned for typography"})," encodes each image into a ",(0,g.jsx)("strong",{children:"512-dimensional vector"})," that captures weight, contrast, style and structure"]})]}),(0,g.jsx)("div",{className:"step-example",children:(0,g.jsxs)("div",{className:"mini-matrix",children:[(0,g.jsxs)("div",{className:"mini-row",children:[(0,g.jsx)("strong",{children:"[ 0.42"}),", -0.13, ",(0,g.jsx)("strong",{children:"0.87"}),", 0.05, -0.61,"]}),(0,g.jsxs)("div",{className:"mini-row",children:["\xa0\xa00.29, ",(0,g.jsx)("strong",{children:"-0.74"}),", 0.18, 0.51, -0.33,"]}),(0,g.jsxs)("div",{className:"mini-row",children:["\xa0\xa00.02, ",(0,g.jsx)("strong",{children:"0.96"}),", -0.47, 0.11, 0.68,"]}),(0,g.jsxs)("div",{className:"mini-row",children:["\xa0\xa0-0.22, 0.39, ",(0,g.jsx)("strong",{children:"-0.85"}),", ... ",(0,g.jsx)("strong",{children:"]"})]})]})})]}),(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"3"}),(0,g.jsx)("strong",{children:"PCA + Font Fusion + UMAP"})]}),(0,g.jsxs)("p",{className:"step-description",children:[(0,g.jsx)("strong",{children:"PCA"})," reduces noise (512D \u2192 50D), font family variants are ",(0,g.jsx)("strong",{children:"merged"})," into single representatives, then ",(0,g.jsx)("strong",{children:"spectral UMAP"})," projects to 2D",(0,g.jsx)("a",{href:"https://pair-code.github.io/understanding-umap/",target:"_blank",rel:"noopener noreferrer",className:"inline-link",children:" (Learn more about UMAP)"})]})]}),(0,g.jsxs)("div",{className:"step-example",children:[(0,g.jsxs)("div",{className:"pipeline-flow",children:[(0,g.jsx)("div",{className:"pipeline-node",children:"512D"}),(0,g.jsx)("div",{className:"pipeline-arrow",children:"\u2192"}),(0,g.jsx)("div",{className:"pipeline-node",children:"50D"}),(0,g.jsx)("div",{className:"pipeline-arrow",children:"\u2192"}),(0,g.jsx)("div",{className:"pipeline-node",children:"fusion"}),(0,g.jsx)("div",{className:"pipeline-arrow",children:"\u2192"}),(0,g.jsx)("div",{className:"pipeline-node",children:(0,g.jsx)("strong",{children:"2D"})})]}),(0,g.jsxs)("div",{className:"coordinates",style:{marginTop:"6px"},children:[(0,g.jsx)("div",{className:"coord",children:"x: -2.34"}),(0,g.jsx)("div",{className:"coord",children:"y: 1.67"})]})]})]}),(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"4"}),(0,g.jsx)("strong",{children:"Interactive Visualization"})]}),(0,g.jsxs)("p",{className:"step-description",children:["Fonts are positioned on a ",(0,g.jsx)("strong",{children:"2D map"})," where proximity indicates ",(0,g.jsx)("strong",{children:"visual similarity"})," \u2014 nearest neighbors are also pre-computed in high-dimensional space"]})]}),(0,g.jsx)("div",{className:"step-example",children:(0,g.jsxs)("div",{className:"font-cluster-demo",children:[(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Times New Roman, serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Georgia, serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Arial, sans-serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Helvetica, sans-serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Courier New, monospace"},children:"A"})]})})]})]})]}),(0,g.jsxs)("div",{className:"about-column",children:[(0,g.jsx)("h3",{className:"about-section-title",children:"Open Source"}),(0,g.jsxs)("p",{className:"about-section-text",children:["This project is ",(0,g.jsx)("strong",{children:"completely open source"})," \u2014 you can explore the code, modify the parameters, or run it on your own font collection."]}),(0,g.jsxs)("p",{className:"about-section-text",children:["The ",(0,g.jsx)("strong",{children:"complete dataset"})," is also open source, including all font metadata, FontCLIP embeddings and positioning data from ",(0,g.jsx)("a",{href:"https://fonts.google.com",target:"_blank",rel:"noopener noreferrer",className:"google-fonts-link",children:"Google Fonts"}),"."]}),(0,g.jsx)("a",{href:"https://huggingface.co/spaces/huggingface/fontmap",target:"_blank",rel:"noopener noreferrer",className:"code-link",children:"View Source on Hugging Face \u2192"}),(0,g.jsx)("h3",{className:"about-section-title",children:"About This Project"}),(0,g.jsxs)("p",{className:"about-section-text",children:["Inspired by the original ",(0,g.jsx)("strong",{children:"IDEO Font Map"}),", this version uses ",(0,g.jsx)("strong",{children:"FontCLIP"})," embeddings \u2014 a CLIP model fine-tuned specifically for typography \u2014 to lay out fonts by visual style."]})]})]})]})]})})})})};var A=n(722),T=n.n(A);const z=e=>{let{isDebugMode:t=!1}=e;const n=(0,s.useRef)(null),o=(0,s.useRef)(null);return(0,s.useEffect)(()=>{if(!t)return;if(!n.current)return;const e=new(T());e.showPanel(0),e.dom.style.position="fixed",e.dom.style.top="20px",e.dom.style.right="80px",e.dom.style.left="auto",e.dom.style.zIndex="10000",e.dom.style.pointerEvents="none",e.dom.style.marginLeft="0",e.dom.style.marginRight="0",n.current.appendChild(e.dom),o.current=e;const s=()=>{e.begin(),e.end(),requestAnimationFrame(s)};return s(),()=>{const e=n.current;o.current&&e&&(e.removeChild(o.current.dom),o.current=null)}},[t]),t?(0,g.jsx)("div",{ref:n}):null},R=e=>{let{darkMode:t=!1}=e;const n=(0,s.useRef)(null),[d]=(0,o.ok)(),u="true"===d.get("debug"),[f,w]=(0,s.useState)("all"),[b,k]=(0,s.useState)(""),[N,L]=(0,s.useState)("loading"),[M,A]=(0,s.useState)(!1),[T,R]=(0,s.useState)(()=>{const e=localStorage.getItem("fontmap-dark-mode");return null!==e?"true"===e:t}),[I,P]=(0,s.useState)(0),B=function(e){const[t,n]=(0,s.useState)(()=>!("undefined"===typeof window||!window.matchMedia)&&window.matchMedia(e).matches);return(0,s.useEffect)(()=>{if("undefined"===typeof window||!window.matchMedia)return;const t=window.matchMedia(e),s=e=>n(e.matches);return n(t.matches),t.addEventListener("change",s),()=>t.removeEventListener("change",s)},[e]),t}("(max-width: 768px)");(0,s.useEffect)(()=>{localStorage.setItem("fontmap-dark-mode",String(T))},[T]);const H=(0,s.useCallback)(()=>{P(e=>e+360),R(e=>!e)},[]),O=i(e=>e.selectedFont),_=i(e=>e.setSelectedFont),W=i(e=>e.setHoveredFont),{fonts:D,glyphPaths:q,loading:G,error:U}=(0,r.t)(),V=!G&&D.length>0;h({svgRef:n,fonts:D,glyphPaths:q,filter:f,searchTerm:b,darkMode:T,loading:G,enabled:V,isMobile:B});const{centerOnFont:Z,resetZoom:X}=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];const n=(0,s.useRef)(null);return(0,s.useEffect)(()=>{if(!t||!e.current)return;const s=a.Ltv(e.current);if(s.select(".viewport-group").empty())return;s.on(".zoom",null);const o=a.s_O().scaleExtent(m).translateExtent([[0,0],[l,c]]).on("zoom",e=>{s.select(".viewport-group").attr("transform",e.transform),s.select(".highlight-group").attr("transform",e.transform),s.select(".centroids-group").attr("transform",e.transform),window.updateCentroidLabels&&window.updateCentroidLabels(),window.updateTooltipTransform&&window.updateTooltipTransform(e.transform),window.updateTooltipPositions&&window.updateTooltipPositions()});s.call(o),s.call(o.transform,p),n.current=o,window.zoomIn=()=>s.transition().duration(200).call(o.scaleBy,1.5),window.zoomOut=()=>s.transition().duration(200).call(o.scaleBy,1/1.5),window.resetZoom=()=>{const e=i.getState();e.setIsTransitioning(!0),e.setHoveredFont(null),s.transition().duration(750).call(o.transform,p).on("end",()=>{i.getState().setIsTransitioning(!1)})};const r=e.current;return()=>{r&&a.Ltv(r).on(".zoom",null),delete window.zoomIn,delete window.zoomOut,delete window.resetZoom,n.current=null}},[t,e]),{centerOnFont:(0,s.useCallback)(t=>{if(!t||!n.current||!e.current)return;const s=a.Ltv(e.current),o=s.select('g.glyph-group[data-font-id="'.concat(t.id,'"]'));if(o.empty())return;const r=o.attr("data-original-transform");if(!r)return;const l=r.match(/translate\(([^,]+),\s*([^)]+)\)/);if(!l)return;const c=800-4*parseFloat(l[1]),d=450-4*parseFloat(l[2]),u=a.GSI.translate(c,d).scale(4),h=i.getState();h.setIsTransitioning(!0),h.setHoveredFont(null),s.transition().duration(800).ease(a.oRn).call(n.current.transform,u).on("end",()=>{i.getState().setIsTransitioning(!1)})},[e]),resetZoom:(0,s.useCallback)(()=>{window.resetZoom&&window.resetZoom()},[])}}(n,V);function Y(e){W(null),_(e)}((e,t,n,o,r)=>{const a=(0,s.useCallback)(()=>t&&0!==t.length?t.filter(e=>{const t="all"===n||e.family===n,s=!o||e.name.toLowerCase().includes(o.toLowerCase())||e.family.toLowerCase().includes(o.toLowerCase());return t&&s}):[],[t,n,o]),i=(0,s.useCallback)(t=>{if(!e||!r)return;const n=a();if(n.length<=1)return;const s=n.find(t=>t.name===e.name);if(!s)return;let o=null,i=1/0;n.forEach(n=>{if(n.name===e.name)return;const r=n.x-s.x,a=n.y-s.y,l=Math.sqrt(r*r+a*a);if(0===l)return;let c=!1;switch(t){case"ArrowUp":c=a>0&&Math.abs(r)<=2*Math.abs(a);break;case"ArrowDown":c=a<0&&Math.abs(r)<=2*Math.abs(a);break;case"ArrowLeft":c=r<0&&Math.abs(a)<=2*Math.abs(r);break;case"ArrowRight":c=r>0&&Math.abs(a)<=2*Math.abs(r);break;default:return}c&&l<i&&(i=l,o=n)}),o&&r(o)},[e,a,r]),l=(0,s.useCallback)(t=>{if(!e)return;const n=document.activeElement;return!n||"INPUT"!==n.tagName&&"TEXTAREA"!==n.tagName&&"true"!==n.contentEditable?"Escape"===t.key?(t.preventDefault(),void r(null)):void(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(t.key)&&(t.preventDefault(),i(t.key))):void 0},[e,i,r]);(0,s.useEffect)(()=>(window.addEventListener("keydown",l),()=>{window.removeEventListener("keydown",l)}),[l]),e&&a().length,a().length,null===e||void 0===e||e.name})(O,D,f,b,Y),(0,s.useEffect)(()=>{O&&Z(O)},[O,Z]),(0,s.useEffect)(()=>{G?L("loading"):D.length>0&&"loading"===N&&L("intro")},[G,D.length,N]);const J=D.length,K="all"===f?J:D.filter(e=>e.family===f).length,Q=(0,s.useMemo)(()=>D.filter(e=>{const t="all"===f||e.family===f,n=!b||e.name.toLowerCase().includes(b.toLowerCase())||e.family.toLowerCase().includes(b.toLowerCase());return t&&n}),[D,f,b]).length,$=(0,s.useMemo)(()=>q&&0!==Object.keys(q).length?(0,g.jsx)("svg",{style:{position:"absolute",width:0,height:0,overflow:"hidden"},"aria-hidden":"true",children:(0,g.jsx)("defs",{children:Object.entries(q).map(e=>{let[t,n]=e;return(0,g.jsx)("symbol",{id:t,viewBox:"0 0 80 80",children:(0,g.jsx)("path",{d:n,fill:"currentColor"})},t)})})}):null,[q]);return U?(0,g.jsx)("div",{className:"fontmap-container",children:(0,g.jsxs)("div",{className:"error",children:[(0,g.jsx)("h3",{children:"Loading error"}),(0,g.jsx)("p",{children:U}),(0,g.jsx)("button",{onClick:()=>window.location.reload(),children:"Reload the page"})]})}):(0,g.jsxs)("div",{className:"fontmap-container ".concat(T?"dark-mode":""," ").concat(O?"has-focus":""),children:[$,(0,g.jsxs)("div",{className:"sidebar",children:[(0,g.jsxs)("div",{className:"sidebar-content",children:[(0,g.jsx)("div",{className:"sidebar-header",children:(0,g.jsxs)("div",{className:"search-section",children:[(0,g.jsx)(v,{searchTerm:b,onSearchChange:k,darkMode:T,big:!0,filteredCount:Q,totalCount:K,filter:f}),(0,g.jsx)(x,{fonts:D,filter:f,onFilterChange:w})]})}),(0,g.jsx)(C,{selectedFont:O,fonts:D,darkMode:T,onClose:()=>_(null),onFontSelect:Y})]}),(0,g.jsxs)("div",{className:"sidebar-footer",children:[(0,g.jsxs)("button",{className:"about-link",onClick:()=>A(!0),title:"How FontMap Works",children:[(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,g.jsx)("path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"}),(0,g.jsx)("line",{x1:"12",y1:"17",x2:"12.01",y2:"17"})]}),"How it works"]}),(0,g.jsxs)("a",{className:"source-link",href:"https://huggingface.co/spaces/tfrere/fontmap",target:"_blank",rel:"noopener noreferrer",title:"View Source on Hugging Face Spaces",children:[(0,g.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:(0,g.jsx)("path",{d:"M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"})}),"Source"]})]})]}),(0,g.jsxs)("div",{className:"main-area",children:[(0,g.jsx)("h1",{className:"map-title","data-text":"FontMap",children:"FontMap"}),(0,g.jsxs)("div",{className:"bottom-controls",children:[(0,g.jsx)("button",{className:"dark-mode-toggle",onClick:H,title:T?"Switch to light mode":"Switch to dark mode","aria-label":"Toggle dark mode",children:(0,g.jsx)("span",{className:"dark-mode-toggle-icon",style:{transform:"rotate(".concat(I,"deg)")},children:T?(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[(0,g.jsx)("circle",{cx:"12",cy:"12",r:"4"}),(0,g.jsx)("path",{d:"M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"})]}):(0,g.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:(0,g.jsx)("path",{d:"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"})})})}),(0,g.jsx)(y,{darkMode:T}),(0,g.jsx)(j,{})]}),(0,g.jsx)("div",{className:"map-container",children:(0,g.jsx)("svg",{ref:n,className:"fontmap-svg"})}),O&&(0,g.jsxs)("div",{className:"focus-hint",children:[(0,g.jsxs)("div",{className:"focus-hint-keys",children:[(0,g.jsx)("kbd",{children:"\u2190"}),(0,g.jsx)("kbd",{children:"\u2191"}),(0,g.jsx)("kbd",{children:"\u2193"}),(0,g.jsx)("kbd",{children:"\u2192"})]}),(0,g.jsx)("span",{className:"focus-hint-label",children:"use arrow keys to navigate"})]}),!G&&D.length>0&&(0,g.jsx)(S,{darkMode:T,isMobile:B,onOpenFont:Y})]}),"loading"===N&&(0,g.jsx)("div",{className:"unified-overlay",children:(0,g.jsx)("div",{className:"overlay-spinner"})}),"intro"===N&&(0,g.jsx)(F,{onStartExploring:()=>L("ready"),darkMode:T}),M&&(0,g.jsx)(E,{onClose:()=>A(!1),darkMode:T}),u&&(0,g.jsx)(z,{isDebugMode:!0})]})}},722:function(e){e.exports=function(){var e=function(){function t(e){return o.appendChild(e.dom),e}function n(e){for(var t=0;t<o.children.length;t++)o.children[t].style.display=t===e?"block":"none";s=e}var s=0,o=document.createElement("div");o.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000",o.addEventListener("click",function(e){e.preventDefault(),n(++s%o.children.length)},!1);var r=(performance||Date).now(),a=r,i=0,l=t(new e.Panel("FPS","#0ff","#002")),c=t(new e.Panel("MS","#0f0","#020"));if(self.performance&&self.performance.memory)var d=t(new e.Panel("MB","#f08","#201"));return n(0),{REVISION:16,dom:o,addPanel:t,showPanel:n,begin:function(){r=(performance||Date).now()},end:function(){i++;var e=(performance||Date).now();if(c.update(e-r,200),e>a+1e3&&(l.update(1e3*i/(e-a),100),a=e,i=0,d)){var t=performance.memory;d.update(t.usedJSHeapSize/1048576,t.jsHeapSizeLimit/1048576)}return e},update:function(){r=this.end()},domElement:o,setMode:n}};return e.Panel=function(e,t,n){var s=1/0,o=0,r=Math.round,a=r(window.devicePixelRatio||1),i=80*a,l=48*a,c=3*a,d=2*a,u=3*a,h=15*a,f=74*a,m=30*a,p=document.createElement("canvas");p.width=i,p.height=l,p.style.cssText="width:80px;height:48px";var g=p.getContext("2d");return g.font="bold "+9*a+"px Helvetica,Arial,sans-serif",g.textBaseline="top",g.fillStyle=n,g.fillRect(0,0,i,l),g.fillStyle=t,g.fillText(e,c,d),g.fillRect(u,h,f,m),g.fillStyle=n,g.globalAlpha=.9,g.fillRect(u,h,f,m),{dom:p,update:function(l,x){s=Math.min(s,l),o=Math.max(o,l),g.fillStyle=n,g.globalAlpha=1,g.fillRect(0,0,i,h),g.fillStyle=t,g.fillText(r(l)+" "+e+" ("+r(s)+"-"+r(o)+")",c,d),g.drawImage(p,u+a,h,f-a,m,u,h,f-a,m),g.fillRect(u+f-a,h,a,m),g.fillStyle=n,g.globalAlpha=.9,g.fillRect(u+f-a,h,a,r((1-l/x)*m))}}},e}()},6907:(e,t,n)=>{"use strict";n.d(t,{t:()=>o});var s=n(5043);function o(){const[e,t]=(0,s.useState)([]),[n,o]=(0,s.useState)({}),[r,a]=(0,s.useState)(!0),[i,l]=(0,s.useState)(null);return(0,s.useEffect)(()=>{(async()=>{try{console.log("\ud83d\udce6 Loading static font map data...");const n={};try{let e="";const t=await fetch("/data/font-sprite.svg");if(t.ok)e=await t.text();else{console.warn("\u26a0\ufe0f Sprite not found at /data/font-sprite.svg, trying root...");const t=await fetch("/font-sprite.svg");t.ok&&(e=await t.text())}if(e){const t=(new DOMParser).parseFromString(e,"image/svg+xml");t.querySelectorAll("symbol").forEach(e=>{const t=e.id,s=e.querySelector("path");t&&s&&(n[t]=s.getAttribute("d"))}),console.log("\ud83c\udfa8 Extracted ".concat(Object.keys(n).length," glyph paths")),o(n)}}catch(e){console.warn("\u26a0\ufe0f Error loading/parsing sprite:",e)}let s;const r=await fetch("/data/font-map.json"),i=r.headers.get("content-type");if(r.ok&&i&&i.includes("application/json"))s=await r.json(),console.log("\ud83d\udccd Loaded from font-map.json");else{console.warn("\u26a0\ufe0f font-map.json not available, falling back to typography_data.json");const e=await fetch("/data/typography_data.json");if(!e.ok)throw new Error("No font data found. Neither font-map.json nor typography_data.json available.");s=await e.json(),console.log("\ud83d\udccd Loaded from typography_data.json (fallback)")}if(!s.fonts||!Array.isArray(s.fonts))throw new Error("Invalid data format: missing fonts array");console.log("\u2705 Loaded ".concat(s.fonts.length," fonts from static map")),t(s.fonts),a(!1)}catch(n){console.error("\u274c Error loading static font data:",n),l(n.message),a(!1)}})()},[]),{fonts:e,glyphPaths:n,loading:r,error:i}}}}]);
|
| 2 |
-
//# sourceMappingURL=632.
|
|
|
|
| 1 |
+
(self.webpackChunkfontmap=self.webpackChunkfontmap||[]).push([[632],{632:(e,t,n)=>{"use strict";n.r(t),n.d(t,{FontMap:()=>R});var s=n(5043),o=n(5439),r=n(6907);var a=n(2491);const i=(0,n(4131).v)((e,t)=>({selectedFont:null,hoveredFont:null,characterSize:1.5,variantSizeImpact:!1,useCategoryColors:!1,isTransitioning:!1,debugMode:!1,setSelectedFont:t=>e({selectedFont:t}),setHoveredFont:t=>e({hoveredFont:t}),setCharacterSize:t=>e({characterSize:t}),setVariantSizeImpact:t=>e({variantSizeImpact:t}),setUseCategoryColors:t=>e({useCategoryColors:t}),setIsTransitioning:t=>e({isTransitioning:t}),setDebugMode:t=>e({debugMode:t}),resetState:()=>{e({selectedFont:null,hoveredFont:null,isTransitioning:!1,characterSize:1.5,variantSizeImpact:!1,useCategoryColors:!1,debugMode:!1})}})),l=1600,c=900,d={"sans-serif":"#3498db",serif:"#e74c3c",display:"#f39c12",handwriting:"#9b59b6",monospace:"#2ecc71"};function u(e,t,n){return t?d[e]||"#95a5a6":n?"#ffffff":"#333333"}function h(e){let{svgRef:t,fonts:n,glyphPaths:o,filter:r,searchTerm:h,darkMode:m,loading:f,enabled:p=!0,isMobile:g=!1}=e;const x=(0,s.useRef)({mapX:null,mapY:null}),v=(0,s.useRef)({width:l,height:c}),y=(0,s.useRef)(!1),j=(0,s.useRef)(null),w=i(e=>e.selectedFont),b=i(e=>e.setSelectedFont),k=i(e=>e.setHoveredFont),N=i(e=>e.useCategoryColors);return j.current=w,(0,s.useEffect)(()=>{if(!p||!n||0===n.length||!t.current)return;const e=a.Ltv(t.current);e.attr("width","100%").attr("height","100%").attr("viewBox","0 0 ".concat(l," ").concat(c));const s=function(e){let t=e.select(".viewport-group");return t.empty()&&(t=e.append("g").attr("class","viewport-group")),t}(e);s.selectAll("g.glyph-group").remove();const{mapX:r,mapY:i}=function(e,t,n){let s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:40;const o=e.map(e=>e.x),r=e.map(e=>e.y),a=Math.min(...o),i=Math.max(...o),l=Math.min(...r),c=Math.max(...r),d=i-a,u=c-l,h=Math.max(1,t-2*s),m=Math.max(1,n-2*s),f=Math.min(h/d,m/u),p=(t-d*f)/2,g=(n-u*f)/2;return{mapX:e=>(e-a)*f+p,mapY:e=>(c-e)*f+g}}(n,l,c);x.current={mapX:r,mapY:i};const d=o&&Object.keys(o).length>0,h=s.node(),f="http://www.w3.org/2000/svg";n.forEach(e=>{const t=(e.imageName||e.name||"").toLowerCase(),n=d?o["".concat(e.id,"_a")]||o[e.id]||o["".concat(t,"_a")]||o[t]:null;if(!n)return;const s=r(e.x),a=i(e.y),l=u(e.family,N,m),c=document.createElementNS(f,"g");c.setAttribute("transform","translate(".concat(s,", ").concat(a,") scale(").concat(.25,")")),c.setAttribute("data-original-transform","translate(".concat(s,", ").concat(a,")")),c.setAttribute("data-font",e.name),c.setAttribute("data-font-id",e.id),c.setAttribute("data-font-name",e.name),c.setAttribute("data-category",e.family),c.setAttribute("class","glyph-group"),c.style.cursor="pointer";const p=document.createElementNS(f,"circle");p.setAttribute("class","glyph-hitbox"),p.setAttribute("cx","40"),p.setAttribute("cy","40"),p.setAttribute("r","44"),p.setAttribute("fill","transparent"),p.setAttribute("pointer-events","all"),c.appendChild(p);const g=document.createElementNS(f,"path");g.setAttribute("d",n),g.setAttribute("fill",l),g.setAttribute("pointer-events","none"),c.appendChild(g),h.appendChild(c)}),y.current=!0},[p,n,o,m,N,t]),(0,s.useEffect)(()=>{t.current&&t.current.querySelectorAll("g.glyph-group").forEach(e=>{const t=u(e.getAttribute("data-category"),N,m);e.querySelectorAll("path").forEach(e=>{e.setAttribute("fill",t)})})},[m,N,t]),(0,s.useEffect)(()=>{if(!t.current||!n||0===n.length)return;const e=a.Ltv(t.current),s=e.select(".viewport-group");if(s.empty())return;e.selectAll(".centroids-group").remove();const{mapX:o,mapY:r}=x.current;if(!o||!r)return;const i={};n.forEach(e=>{const t=e.family;i[t]||(i[t]={x:0,y:0,n:0}),i[t].x+=e.x,i[t].y+=e.y,i[t].n+=1});const u=s.attr("transform")||"",h=e.append("g").attr("class","centroids-group").attr("transform",u).style("pointer-events","none").style("user-select","none"),f=N?null:m?"#ffffff":"#000000",p=m?"#000000":"#ffffff";Object.entries(i).forEach(e=>{let[t,n]=e;const s=o(n.x/n.n),a=r(n.y/n.n),i=f||d[t]||"#95a5a6";h.append("text").attr("x",s).attr("y",a).attr("text-anchor","middle").attr("font-weight","bold").attr("fill",i).attr("stroke",p).attr("paint-order","stroke fill").attr("class","centroid-label").text(t)});const g=t.current,v=()=>{const e=g.getBoundingClientRect();if(!e.width||!e.height)return;const t=Math.min(e.width/l,e.height/c),n=a._V(g).k||1,s=13/(n*t);let o=1;n>=3.2?o=0:n>2.2&&(o=1-(n-2.2)/1),h.selectAll(".centroid-label").attr("font-size",s).attr("stroke-width",.5*s).attr("opacity",o)};v(),window.updateCentroidLabels=v;let y=null;return"undefined"!==typeof ResizeObserver&&(y=new ResizeObserver(v),y.observe(g)),()=>{y&&y.disconnect(),delete window.updateCentroidLabels}},[n,N,m,t]),(0,s.useEffect)(()=>{if(!t.current)return;const e=a.Ltv(t.current),n=e.select(".viewport-group");if(!n.empty())if(e.selectAll(".highlight-group").remove(),w){n.attr("opacity",.1);const t=n.select('g.glyph-group[data-font-id="'.concat(w.id,'"]'));if(!t.empty()){const s=n.attr("transform")||"",o=e.append("g").attr("class","highlight-group").attr("transform",s).style("pointer-events","none"),r=t.node().cloneNode(!0);r.setAttribute("opacity","1"),o.node().appendChild(r)}n.selectAll("g.glyph-group").style("pointer-events","all")}else{n.attr("opacity",1);if("all"!==r||h){const e=h?h.toLowerCase():"";n.selectAll("g.glyph-group").each(function(){const t=this,n=t.getAttribute("data-category"),s=t.getAttribute("data-font-name"),o="all"===r||n===r,a=!e||s&&s.toLowerCase().includes(e)||n&&n.toLowerCase().includes(e),i=o&&a;t.setAttribute("opacity",i?"1":"0.06"),t.style.pointerEvents=i?"all":"none"})}else n.selectAll("g.glyph-group").each(function(){this.removeAttribute("opacity"),this.style.pointerEvents="all"})}},[r,h,w,t]),(0,s.useEffect)(()=>{if(!t.current||!n||0===n.length)return;const e=t.current,s=t=>{let n=t;for(;n&&n!==e;){if(n.classList&&n.classList.contains("glyph-group"))return n;n=n.parentElement}return null},o=e=>{const t=e.getAttribute("data-font-id");return n.find(e=>e.id===t)||null};let r=null;const a=e=>{if(i.getState().isTransitioning)return;if(g)return;const t=s(e.target);if(!t)return;const n=o(t);n&&(clearTimeout(r),r=setTimeout(()=>k(n),80))},l=e=>{if(g)return;if(i.getState().isTransitioning)return;s(e.target)&&(clearTimeout(r),k(null))},c=e=>{clearTimeout(r);const t=s(e.target);if(g){const e=i.getState().hoveredFont;if(!t)return void(e&&k(null));const n=o(t);if(!n)return;return void k(e&&e.id===n.id?null:n)}if(!t)return void(j.current&&b(null));const n=o(t);if(!n)return;k(null);const a=j.current;b(a&&a.id===n.id?null:n)};return e.addEventListener("mouseover",a),e.addEventListener("mouseout",l),e.addEventListener("click",c),()=>{clearTimeout(r),e.removeEventListener("mouseover",a),e.removeEventListener("mouseout",l),e.removeEventListener("click",c)}},[n,b,k,t,g]),{mappingRef:x,dimensionsRef:v}}const m=.8,f=[m,10],p=a.GSI.translate(159.99999999999997,89.99999999999999).scale(m);var g=n(579);const x=e=>{let{fonts:t,filter:n,onFilterChange:s}=e;const o=[...new Set(t.map(e=>e.family))];return(0,g.jsxs)("div",{className:"filters-container",children:[(0,g.jsx)("div",{className:"filters-label",children:"Families"}),(0,g.jsx)("div",{className:"filters-inline",children:o.map(e=>(0,g.jsxs)("span",{className:"filter-link ".concat(n===e?"active":""),onClick:()=>s(n===e?"all":e),children:[e," ",(0,g.jsx)("span",{className:"filter-count",children:t.filter(t=>t.family===e).length})]},e))})]})},v=e=>{let{searchTerm:t,onSearchChange:n,darkMode:s,big:o=!1,filteredCount:r=null,totalCount:a=null,filter:i="all"}=e;const l=null!==r&&null!==a,c=l&&(r!==a||"all"!==i);return(0,g.jsxs)("div",{className:"search-bar ".concat(o?"search-bar-big":""),children:[(0,g.jsx)("input",{type:"text",placeholder:"Search fonts...",value:t,onChange:e=>n(e.target.value),className:"search-input ".concat(s?"dark":"")}),(0,g.jsxs)("div",{className:"search-controls",children:[t&&(0,g.jsx)("button",{className:"search-clear",onClick:()=>n(""),title:"Clear search",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),(0,g.jsx)("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}),l&&(0,g.jsx)("div",{className:"search-counter ".concat(s?"dark":""," ").concat(c?"filtered":""),children:c?(0,g.jsxs)("span",{className:"counter-text",children:[r," of ",a]}):(0,g.jsxs)("span",{className:"counter-text",children:[a," fonts"]})})]})]})},y=()=>(0,g.jsxs)("div",{className:"zoom-controls",children:[(0,g.jsx)("button",{className:"zoom-btn zoom-in",onClick:()=>window.zoomIn&&window.zoomIn(),title:"Zoom In",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"M21 21l-4.35-4.35"}),(0,g.jsx)("line",{x1:"11",y1:"8",x2:"11",y2:"14"}),(0,g.jsx)("line",{x1:"8",y1:"11",x2:"14",y2:"11"})]})}),(0,g.jsx)("button",{className:"zoom-btn zoom-out",onClick:()=>window.zoomOut&&window.zoomOut(),title:"Zoom Out",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"M21 21l-4.35-4.35"}),(0,g.jsx)("line",{x1:"8",y1:"11",x2:"14",y2:"11"})]})}),(0,g.jsx)("button",{className:"zoom-btn zoom-reset",onClick:()=>window.resetZoom&&window.resetZoom(),title:"Reset Zoom",children:(0,g.jsxs)("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"}),(0,g.jsx)("path",{d:"M3 3v5h5"})]})})]}),j=()=>{const e=i(e=>e.useCategoryColors),t=i(e=>e.setUseCategoryColors);return(0,g.jsx)("div",{className:"category-legend",children:(0,g.jsxs)("label",{className:"category-legend-toggle",children:[(0,g.jsx)("input",{type:"checkbox",checked:e,onChange:e=>t(e.target.checked)}),(0,g.jsx)("span",{children:"Category colors"})]})})};var w=n(2555);const b=e=>e?e.toLowerCase()+"_a":"fallback_a",k=e=>{let{size:t="16px",color:n="currentColor",className:s="",minHeight:o=null,centered:r=!0}=e;const a=(0,g.jsx)("div",{className:"spinner ".concat(s),style:{width:t,height:t,border:"2px solid transparent",borderTop:"2px solid ".concat(n),borderRadius:"50%",animation:"spin 1s linear infinite",display:"inline-block"}});return o?(0,g.jsx)("div",{style:{minHeight:o,display:r?"flex":"block",justifyContent:r?"center":"flex-start",alignItems:r?"center":"flex-start",width:"100%",boxSizing:"border-box"},children:a}):a},N=["Arial, sans-serif","Times New Roman, serif","Georgia, serif","Helvetica, sans-serif","Courier New, monospace","Verdana, sans-serif","Trebuchet MS, sans-serif","Tahoma, sans-serif"],C=e=>{let{selectedFont:t,fonts:n,darkMode:o,onClose:r,onFontSelect:a}=e;const[i,l]=(0,s.useState)(!1),[c,d]=(0,s.useState)(!1),[u,h]=(0,s.useState)({}),m=(0,s.useRef)({}),f=(0,s.useRef)(null),[p,x]=(0,s.useState)(0);(0,s.useEffect)(()=>{l(!1),d(!1),h({}),Object.values(m.current).forEach(e=>clearTimeout(e)),m.current={},f.current&&(clearTimeout(f.current),f.current=null);const e=setTimeout(()=>l(!0),100);return f.current=setTimeout(()=>d(!0),500),()=>{clearTimeout(e),f.current&&clearTimeout(f.current)}},[t]),(0,s.useEffect)(()=>{if(t)return;const e=setInterval(()=>{x(e=>(e+1)%N.length)},200);return()=>clearInterval(e)},[t]);const v=(0,s.useCallback)(e=>{m.current[e]&&(clearTimeout(m.current[e]),delete m.current[e]),h(t=>(0,w.A)((0,w.A)({},t),{},{[e]:!0}))},[]),y=(0,s.useMemo)(()=>{if(!t||!n||0===n.length)return[];const e=n.find(e=>e.name===t.name);if(!e)return[];if(e.neighbors&&e.neighbors.length>0){const t=new Map(n.map(e=>[e.id,e]));return e.neighbors.map((e,n)=>{const s=t.get(e);return s?{font:s,distance:n+1}:null}).filter(Boolean).slice(0,4)}return n.filter(e=>e.name!==t.name).map(t=>{const n=t.x-e.x,s=t.y-e.y;return{font:t,distance:Math.sqrt(n*n+s*s)}}).sort((e,t)=>e.distance-t.distance).slice(0,4)},[t,n]);if((0,s.useEffect)(()=>{if(0===y.length)return;const e={};return y.forEach(t=>{let{font:n}=t;if(!u[n.name]&&!m.current[n.name]){const t=setTimeout(()=>{v(n.name)},1e3);m.current[n.name]=t,e[n.name]=t}}),()=>{Object.values(e).forEach(e=>clearTimeout(e))}},[y,u,v]),!t)return(0,g.jsx)("div",{className:"font-details",children:(0,g.jsxs)("div",{className:"font-details-placeholder",children:[(0,g.jsx)("div",{className:"placeholder-icon",children:(0,g.jsxs)("svg",{width:"64",height:"64",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"m21 21-4.35-4.35"}),(0,g.jsx)("text",{x:"11",y:"14",textAnchor:"middle",fontSize:"10",fill:"currentColor",fontWeight:"100",opacity:.65,style:{fontFamily:N[p],fontStyle:"normal",fontVariant:"normal"},children:"A"})]})}),(0,g.jsxs)("div",{className:"placeholder-content",children:[(0,g.jsx)("h3",{children:"Explore fonts"}),(0,g.jsx)("p",{children:"Click any font on the map to discover its details and find similar typefaces."})]})]})});const j=b(t.imageName||t.name),C=t.family||"sans-serif",S=t.google_fonts_url||(e=>{if(!e)return null;const t=e.trim().replace(/\s+/g,"+").replace(/[^\w\s+]/g,"").replace(/\s+/g,"+");return"https://fonts.google.com/specimen/".concat(t)})(t.name),L=t.fusionInfo&&t.fusionInfo.merged,M=t.variantCount||1;return(0,g.jsxs)("div",{className:"font-details",children:[(0,g.jsxs)("button",{type:"button",className:"font-details-back",onClick:r,"aria-label":"Back to map",children:[(0,g.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:(0,g.jsx)("polyline",{points:"15 18 9 12 15 6"})}),(0,g.jsx)("span",{children:"Back"})]}),(0,g.jsxs)("div",{className:"font-details-content",children:[(0,g.jsx)("div",{className:"active-font-label",children:"Active Font"}),(0,g.jsxs)("div",{className:"active-font-card",children:[(0,g.jsxs)("div",{className:"active-font-content",children:[(0,g.jsxs)("div",{className:"font-letter-preview",children:[!i&&(0,g.jsx)(k,{size:"20px",color:o?"#ffffff":"#000000",minHeight:"120px",centered:!0}),(0,g.jsx)("svg",{width:"120",height:"120",viewBox:"0 0 120 120",style:{display:i?"block":"none",transition:"opacity 0.15s ease-in-out"},children:j&&(0,g.jsx)("use",{href:"#".concat(j),fill:o?"#ffffff":"#000000",style:{fill:o?"#ffffff":"#000000"}})})]}),(0,g.jsxs)("div",{className:"font-info-compact",children:[(0,g.jsx)("h2",{className:"font-name-compact",children:t.name}),L&&(0,g.jsx)("div",{className:"font-fusion-badge",style:{display:"inline-flex",alignItems:"center",gap:"4px",color:o?"#ffffff":"#000000"},children:(0,g.jsxs)("span",{className:"fusion-text",children:[M," variants"]})}),(0,g.jsx)("p",{className:"font-category-compact",children:C}),(0,g.jsxs)("div",{className:"font-metadata",children:[t.weights&&t.weights.length>0&&(0,g.jsx)("span",{className:"font-weights",children:t.weights.join(", ")}),t.styles&&t.styles.length>0&&(0,g.jsx)("span",{className:"font-styles",children:t.styles.join(", ")})]})]})]}),(0,g.jsxs)("div",{className:"font-sentence-compact",children:[!c&&(0,g.jsx)(k,{size:"16px",color:o?"#ffffff":"#000000",minHeight:"49px",centered:!0,className:"sentence-preview-spinner"}),(0,g.jsx)("img",{src:"/data/sentences/".concat((t.imageName||t.name).toLowerCase().replace(/\s+/g,"_"),"_sentence.svg"),alt:"".concat(t.name," sentence preview"),style:{width:"100%",height:"auto",maxWidth:"100%",minHeight:"49px",filter:o?"invert(1)":"none",display:c?"block":"none",transition:"opacity 0.15s ease-in-out"},onLoad:()=>d(!0),onError:e=>{e.target.style.display="none",d(!0)}})]}),(0,g.jsx)("div",{className:"font-action-section",children:(0,g.jsxs)("a",{href:S||"#",target:"_blank",rel:"noopener noreferrer",className:"action-btn ghost google-fonts-link",title:"View ".concat(t.name," on Google Fonts"),style:{display:S?"flex":"none"},children:["Find on Google Fonts",(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"}),(0,g.jsx)("polyline",{points:"15,3 21,3 21,9"}),(0,g.jsx)("line",{x1:"10",y1:"14",x2:"21",y2:"3"})]})]})})]}),(0,g.jsxs)("div",{className:"similar-fonts",children:[(0,g.jsx)("h4",{className:"similar-fonts-title",children:"Similar Fonts"}),0===y.length?(0,g.jsx)("p",{className:"no-similar",children:"No similar fonts found"}):(0,g.jsx)("div",{className:"similar-fonts-list",children:y.map(e=>{let{font:t,distance:n}=e;const s=t.imageName||t.name,r="/data/sentences/".concat(s.toLowerCase().replace(/\s+/g,"_"),"_sentence.svg");return(0,g.jsxs)("div",{className:"similar-font-item",title:"".concat(t.name," (distance: ").concat(n.toFixed(2),")"),onClick:()=>a&&a(t),children:[(0,g.jsx)("div",{className:"similar-font-glyph",children:(0,g.jsx)("svg",{width:"32",height:"32",viewBox:"0 0 24 24",className:"font-glyph-small",children:(0,g.jsx)("use",{href:"#".concat(b(t.imageName||t.name)),fill:o?"#ffffff":"#000000",style:{fill:o?"#ffffff":"#000000"}})})}),(0,g.jsxs)("div",{className:"similar-font-info",children:[(0,g.jsx)("span",{className:"font-name",children:t.name}),(0,g.jsx)("span",{className:"font-family",children:t.family})]}),(0,g.jsxs)("div",{className:"similar-font-sentence",children:[!u[t.name]&&(0,g.jsx)(k,{size:"16px",color:o?"#ffffff":"#000000",minHeight:"49px",centered:!0,className:"similar-font-spinner"}),(0,g.jsx)("img",{src:r,alt:"".concat(t.name," sentence preview"),style:{height:"auto",minHeight:"49px",maxHeight:"49px",maxWidth:"100%",objectFit:"contain",filter:o?"invert(1)":"none",display:u[t.name]?"block":"none",transition:"opacity 0.15s ease-in-out"},onLoad:()=>{v(t.name)},onError:e=>{e.target.style.display="none",v(t.name)}})]})]},t.name)})})]})]})]})},S=e=>{let{darkMode:t,isMobile:n,onOpenFont:o}=e;const r=i(e=>e.selectedFont),l=i(e=>e.hoveredFont),{handleFontSelect:c,handleFontHover:d,handleFontUnhover:u,updateTransform:h,updatePositions:m}=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const o=(0,s.useRef)(null),r=(0,s.useRef)(null),i=(0,s.useRef)(a.GSI),l=(0,s.useRef)(new Map),c=(0,s.useRef)(null),d=(0,s.useRef)(n);(0,s.useEffect)(()=>{d.current=n},[n]);const u=(0,s.useMemo)(()=>({dark:{backgroundColor:"var(--color-bg-primary-dark)",borderColor:"var(--color-border-primary-dark)",color:"#ffffff"},light:{backgroundColor:"var(--color-bg-primary)",borderColor:"var(--color-border-primary)",color:"#000000"}}),[]);(0,s.useEffect)(()=>{o.current=a.Ltv("body").append("div").attr("class","font-tooltip font-tooltip-selected").style("opacity",0).style("position","absolute").style("pointer-events","none").style("z-index",1001).style("transition","opacity 0.2s ease"),r.current=a.Ltv("body").append("div").attr("class","font-tooltip font-tooltip-hover").style("opacity",0).style("position","absolute").style("pointer-events","none").style("z-index",1e3).style("transition","opacity 0.2s ease");const e=e=>{if(!e.target.closest(".tooltip-open-btn"))return;const t=c.current,n=d.current;t&&n&&n(t)},t=r.current.node();return t&&t.addEventListener("click",e),()=>{t&&t.removeEventListener("click",e),a.Ubm(".font-tooltip").remove();const n=l.current;n.forEach(e=>clearTimeout(e)),n.clear()}},[]),(0,s.useEffect)(()=>{const t=t=>{if(!t)return;t.classed("dark-mode",e);const n=e?u.dark:u.light;t.style("background-color",n.backgroundColor).style("border-color",n.borderColor).style("color",n.color)};t(o.current),t(r.current)},[e,u]);const h=(0,s.useCallback)(e=>{const n=e.imageName||e.name,s="/data/sentences/".concat(n.toLowerCase().replace(/\s+/g,"_"),"_sentence.svg"),o=t?'<button type="button" class="tooltip-open-btn">Open</button>':"";return'\n <div class="simple-tooltip">\n <div class="tooltip-font-name">'.concat(e.name,'</div>\n <div class="tooltip-sentence-preview">\n <div class="tooltip-image-container" style="position: relative; min-height: 44px; display: flex; align-items: center; justify-content: center;">\n <img src="').concat(s,'"\n alt=""\n class="sentence-image"\n style="max-width: 200px; height: auto; opacity: 0; transition: opacity 0.2s ease;"\n onload="this.style.opacity=\'1\'; this.parentElement.querySelector(\'.tooltip-spinner\').style.display=\'none\';"\n onerror="this.style.display=\'none\'; this.parentElement.querySelector(\'.tooltip-spinner\').style.display=\'flex\'; this.parentElement.querySelector(\'.tooltip-spinner\').innerHTML=\'\u26a0\ufe0f Loading error\';"\n />\n <div class="tooltip-spinner" style="display: flex; align-items: center; justify-content: center; font-size: 12px; position: absolute; top: 0; left: 0; right: 0; bottom: 0;">\n <div style="width: 16px; height: 16px; border: 2px solid transparent; border-top: 2px solid currentColor; border-radius: 50%; animation: spin 1s linear infinite; margin-right: 8px;"></div>\n Loading...\n </div>\n </div>\n </div>\n ').concat(o,"\n </div>\n ")},[t]),m=(0,s.useCallback)((e,t)=>{if(!e||!t)return;const n=e.node().getBoundingClientRect(),s=t.getBoundingClientRect();let o=s.left+s.width/2-n.width/2,r=s.top-n.height-6;o<10&&(o=10),o+n.width>window.innerWidth-10&&(o=window.innerWidth-n.width-10),r<10&&(r=s.bottom+6),e.style("left","".concat(o,"px")).style("top","".concat(r,"px"))},[]),f=(0,s.useCallback)((e,t,n)=>{e&&t&&(e===r.current&&(c.current=t),e.html(h(t)),m(e,n),e.style("opacity",1))},[h,m]),p=(0,s.useCallback)(e=>{e&&e.style("opacity",0)},[]),g=(0,s.useCallback)(()=>{const e=a.Ltv(".fontmap-svg");if(e.empty())return;const t=e.select(".viewport-group");if(!t.empty()){if(o.current&&"0"!==o.current.style("opacity")){var n;const e=null===(n=window.currentSelectedFont)||void 0===n?void 0:n.name;if(e){const n=t.node().querySelector('[data-font="'.concat(CSS.escape(e),'"]'));n&&m(o.current,n)}}if(r.current&&"0"!==r.current.style("opacity")){var s;const e=null===(s=window.currentHoveredFont)||void 0===s?void 0:s.name;if(e){const n=t.node().querySelector('[data-font="'.concat(CSS.escape(e),'"]'));n&&m(r.current,n)}}}},[m]),x=(0,s.useCallback)(e=>{i.current=e,setTimeout(()=>{g()},0)},[g]);return{handleFontSelect:(0,s.useCallback)((e,t)=>{e?(p(r.current),f(o.current,e,t)):p(o.current)},[f,p]),handleFontHover:(0,s.useCallback)((e,t)=>{e?f(r.current,e,t):p(r.current)},[f,p]),handleFontUnhover:(0,s.useCallback)(()=>{p(r.current)},[p]),updateTransform:x,updatePositions:g}}(t,n,o);return(0,s.useEffect)(()=>{if(r){const e=document.querySelector(".fontmap-svg");if(e){const t=e.querySelector(".viewport-group");if(t){const e=t.querySelector('[data-font="'.concat(CSS.escape(r.name),'"]'));e&&c(r,e)}}}else c(null)},[r,c]),(0,s.useEffect)(()=>{if(!l||r&&r.name===l.name)l||u();else{const e=document.querySelector(".fontmap-svg");if(e){const t=e.querySelector(".viewport-group");if(t){const e=t.querySelector('[data-font="'.concat(CSS.escape(l.name),'"]'));e&&d(l,e)}}}},[l,r,d,u]),(0,s.useEffect)(()=>(window.updateTooltipPositions=m,window.updateTooltipTransform=h,window.currentSelectedFont=r,window.currentHoveredFont=l,()=>{delete window.updateTooltipPositions,delete window.updateTooltipTransform,delete window.currentSelectedFont,delete window.currentHoveredFont}),[m,h,r,l]),null};var L=n(7950);const M=e=>{let{children:t,isOpen:n}=e;return n?(0,L.createPortal)(t,document.body):null},F=e=>{let{onStartExploring:t,darkMode:n}=e;return(0,g.jsx)(M,{isOpen:!0,children:(0,g.jsx)("div",{className:"unified-overlay".concat(n?" dark-mode":""),onClick:t,children:(0,g.jsx)("div",{className:"intro-modal",onClick:e=>e.stopPropagation(),children:(0,g.jsxs)("div",{className:"intro-modal-content",children:[(0,g.jsx)("h1",{className:"intro-title",children:"FontMap"}),(0,g.jsx)("p",{className:"intro-subtitle",children:"Using artificial intelligence to surface new relationships across fonts."}),(0,g.jsxs)("p",{className:"intro-description",children:["This interactive map of more than 1100+ ",(0,g.jsx)("a",{href:"https://fonts.google.com",target:"_blank",rel:"noopener noreferrer",className:"google-fonts-link",children:"Google Fonts"})," has been organized using machine learning."]}),(0,g.jsxs)("div",{className:"intro-features",children:[(0,g.jsxs)("div",{className:"intro-feature",children:[(0,g.jsx)("div",{className:"intro-feature-icon",children:(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("path",{d:"M21 3l-6 6"}),(0,g.jsx)("path",{d:"M3 21l6-6"}),(0,g.jsx)("path",{d:"M21 3l-6 6"}),(0,g.jsx)("path",{d:"M3 21l6-6"}),(0,g.jsx)("circle",{cx:"12",cy:"12",r:"3"})]})}),(0,g.jsx)("span",{children:"Pan and Zoom to explore"})]}),(0,g.jsxs)("div",{className:"intro-feature",children:[(0,g.jsx)("div",{className:"intro-feature-icon",children:(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"11",cy:"11",r:"8"}),(0,g.jsx)("path",{d:"m21 21-4.35-4.35"})]})}),(0,g.jsx)("span",{children:"Search for a font by name"})]})]}),(0,g.jsx)("button",{className:"intro-start-button",onClick:t,children:"START EXPLORING"})]})})})})},E=e=>{let{onClose:t,darkMode:n}=e;return(0,g.jsx)(M,{isOpen:!0,children:(0,g.jsx)("div",{className:"unified-overlay".concat(n?" dark-mode":""),onClick:t,children:(0,g.jsx)("div",{className:"about-modal",onClick:e=>e.stopPropagation(),children:(0,g.jsxs)("div",{className:"about-modal-content",children:[(0,g.jsxs)("div",{className:"about-modal-header",children:[(0,g.jsx)("h1",{className:"about-title",children:"How FontMap Works"}),(0,g.jsx)("button",{className:"about-close-button",onClick:t,title:"Close",children:(0,g.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),(0,g.jsx)("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),(0,g.jsxs)("div",{className:"about-modal-body",children:[(0,g.jsxs)("p",{className:"about-description",children:["FontMap uses ",(0,g.jsx)("strong",{children:"FontCLIP"}),", a vision model fine-tuned for typography, to build an interactive map of font relationships. Each font is encoded into a rich embedding, then projected onto a 2D plane via ",(0,g.jsx)("strong",{children:"UMAP"})," so that visually similar fonts cluster together."]}),(0,g.jsxs)("div",{className:"about-content-grid",children:[(0,g.jsxs)("div",{className:"about-column",children:[(0,g.jsx)("h3",{className:"about-section-title",children:"Technical Process"}),(0,g.jsxs)("div",{className:"pipeline-steps",children:[(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"1"}),(0,g.jsx)("strong",{children:"Multi-Glyph Rendering"})]}),(0,g.jsxs)("p",{className:"step-description",children:["Each font is rendered as a ",(0,g.jsx)("strong",{children:"224 \xd7 224"})," composite image showing multiple representative glyphs, capturing the full typographic character"]})]}),(0,g.jsx)("div",{className:"step-example",children:(0,g.jsxs)("div",{className:"multi-glyph-demo",children:[(0,g.jsxs)("div",{className:"glyph-grid",children:[(0,g.jsx)("span",{style:{fontFamily:"Georgia, serif",fontSize:"18px",fontWeight:"bold"},children:"Aa"}),(0,g.jsx)("span",{style:{fontFamily:"Georgia, serif",fontSize:"18px"},children:"Bb"}),(0,g.jsx)("span",{style:{fontFamily:"Georgia, serif",fontSize:"18px"},children:"Rr"})]}),(0,g.jsx)("div",{className:"glyph-grid-label",children:"224 \xd7 224"})]})})]}),(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"2"}),(0,g.jsx)("strong",{children:"FontCLIP Embeddings"})]}),(0,g.jsxs)("p",{className:"step-description",children:["A ",(0,g.jsx)("strong",{children:"CLIP ViT-B/32"})," model ",(0,g.jsx)("a",{href:"https://github.com/yukistavailable/FontCLIP",target:"_blank",rel:"noopener noreferrer",className:"inline-link",children:"fine-tuned for typography"})," encodes each image into a ",(0,g.jsx)("strong",{children:"512-dimensional vector"})," that captures weight, contrast, style and structure"]})]}),(0,g.jsx)("div",{className:"step-example",children:(0,g.jsxs)("div",{className:"mini-matrix",children:[(0,g.jsxs)("div",{className:"mini-row",children:[(0,g.jsx)("strong",{children:"[ 0.42"}),", -0.13, ",(0,g.jsx)("strong",{children:"0.87"}),", 0.05, -0.61,"]}),(0,g.jsxs)("div",{className:"mini-row",children:["\xa0\xa00.29, ",(0,g.jsx)("strong",{children:"-0.74"}),", 0.18, 0.51, -0.33,"]}),(0,g.jsxs)("div",{className:"mini-row",children:["\xa0\xa00.02, ",(0,g.jsx)("strong",{children:"0.96"}),", -0.47, 0.11, 0.68,"]}),(0,g.jsxs)("div",{className:"mini-row",children:["\xa0\xa0-0.22, 0.39, ",(0,g.jsx)("strong",{children:"-0.85"}),", ... ",(0,g.jsx)("strong",{children:"]"})]})]})})]}),(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"3"}),(0,g.jsx)("strong",{children:"PCA + Font Fusion + UMAP"})]}),(0,g.jsxs)("p",{className:"step-description",children:[(0,g.jsx)("strong",{children:"PCA"})," reduces noise (512D \u2192 50D), font family variants are ",(0,g.jsx)("strong",{children:"merged"})," into single representatives, then ",(0,g.jsx)("strong",{children:"spectral UMAP"})," projects to 2D",(0,g.jsx)("a",{href:"https://pair-code.github.io/understanding-umap/",target:"_blank",rel:"noopener noreferrer",className:"inline-link",children:" (Learn more about UMAP)"})]})]}),(0,g.jsxs)("div",{className:"step-example",children:[(0,g.jsxs)("div",{className:"pipeline-flow",children:[(0,g.jsx)("div",{className:"pipeline-node",children:"512D"}),(0,g.jsx)("div",{className:"pipeline-arrow",children:"\u2192"}),(0,g.jsx)("div",{className:"pipeline-node",children:"50D"}),(0,g.jsx)("div",{className:"pipeline-arrow",children:"\u2192"}),(0,g.jsx)("div",{className:"pipeline-node",children:"fusion"}),(0,g.jsx)("div",{className:"pipeline-arrow",children:"\u2192"}),(0,g.jsx)("div",{className:"pipeline-node",children:(0,g.jsx)("strong",{children:"2D"})})]}),(0,g.jsxs)("div",{className:"coordinates",style:{marginTop:"6px"},children:[(0,g.jsx)("div",{className:"coord",children:"x: -2.34"}),(0,g.jsx)("div",{className:"coord",children:"y: 1.67"})]})]})]}),(0,g.jsxs)("div",{className:"step-item",children:[(0,g.jsxs)("div",{className:"step-content",children:[(0,g.jsxs)("div",{className:"step-header",children:[(0,g.jsx)("span",{className:"step-number",children:"4"}),(0,g.jsx)("strong",{children:"Interactive Visualization"})]}),(0,g.jsxs)("p",{className:"step-description",children:["Fonts are positioned on a ",(0,g.jsx)("strong",{children:"2D map"})," where proximity indicates ",(0,g.jsx)("strong",{children:"visual similarity"})," \u2014 nearest neighbors are also pre-computed in high-dimensional space"]})]}),(0,g.jsx)("div",{className:"step-example",children:(0,g.jsxs)("div",{className:"font-cluster-demo",children:[(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Times New Roman, serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Georgia, serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Arial, sans-serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Helvetica, sans-serif"},children:"A"}),(0,g.jsx)("div",{className:"font-sample",style:{fontFamily:"Courier New, monospace"},children:"A"})]})})]})]})]}),(0,g.jsxs)("div",{className:"about-column",children:[(0,g.jsx)("h3",{className:"about-section-title",children:"Open Source"}),(0,g.jsxs)("p",{className:"about-section-text",children:["This project is ",(0,g.jsx)("strong",{children:"completely open source"})," \u2014 you can explore the code, modify the parameters, or run it on your own font collection."]}),(0,g.jsxs)("p",{className:"about-section-text",children:["The ",(0,g.jsx)("strong",{children:"complete dataset"})," is also open source, including all font metadata, FontCLIP embeddings and positioning data from ",(0,g.jsx)("a",{href:"https://fonts.google.com",target:"_blank",rel:"noopener noreferrer",className:"google-fonts-link",children:"Google Fonts"}),"."]}),(0,g.jsx)("a",{href:"https://huggingface.co/spaces/tfrere/fontmap",target:"_blank",rel:"noopener noreferrer",className:"code-link",children:"View Source on Hugging Face \u2192"}),(0,g.jsx)("h3",{className:"about-section-title",children:"About This Project"}),(0,g.jsxs)("p",{className:"about-section-text",children:["Inspired by the original ",(0,g.jsx)("strong",{children:"IDEO Font Map"}),", this version uses ",(0,g.jsx)("strong",{children:"FontCLIP"})," embeddings \u2014 a CLIP model fine-tuned specifically for typography \u2014 to lay out fonts by visual style."]})]})]})]})]})})})})};var A=n(722),T=n.n(A);const z=e=>{let{isDebugMode:t=!1}=e;const n=(0,s.useRef)(null),o=(0,s.useRef)(null);return(0,s.useEffect)(()=>{if(!t)return;if(!n.current)return;const e=new(T());e.showPanel(0),e.dom.style.position="fixed",e.dom.style.top="20px",e.dom.style.right="80px",e.dom.style.left="auto",e.dom.style.zIndex="10000",e.dom.style.pointerEvents="none",e.dom.style.marginLeft="0",e.dom.style.marginRight="0",n.current.appendChild(e.dom),o.current=e;const s=()=>{e.begin(),e.end(),requestAnimationFrame(s)};return s(),()=>{const e=n.current;o.current&&e&&(e.removeChild(o.current.dom),o.current=null)}},[t]),t?(0,g.jsx)("div",{ref:n}):null},R=e=>{let{darkMode:t=!1}=e;const n=(0,s.useRef)(null),[d]=(0,o.ok)(),u="true"===d.get("debug"),[m,w]=(0,s.useState)("all"),[b,k]=(0,s.useState)(""),[N,L]=(0,s.useState)("loading"),[M,A]=(0,s.useState)(!1),[T,R]=(0,s.useState)(()=>{const e=localStorage.getItem("fontmap-dark-mode");return null!==e?"true"===e:t}),[I,P]=(0,s.useState)(0),B=function(e){const[t,n]=(0,s.useState)(()=>!("undefined"===typeof window||!window.matchMedia)&&window.matchMedia(e).matches);return(0,s.useEffect)(()=>{if("undefined"===typeof window||!window.matchMedia)return;const t=window.matchMedia(e),s=e=>n(e.matches);return n(t.matches),t.addEventListener("change",s),()=>t.removeEventListener("change",s)},[e]),t}("(max-width: 768px)");(0,s.useEffect)(()=>{localStorage.setItem("fontmap-dark-mode",String(T))},[T]);const H=(0,s.useCallback)(()=>{P(e=>e+360),R(e=>!e)},[]),O=i(e=>e.selectedFont),_=i(e=>e.setSelectedFont),W=i(e=>e.setHoveredFont),{fonts:D,glyphPaths:q,loading:G,error:U}=(0,r.t)(),V=!G&&D.length>0;h({svgRef:n,fonts:D,glyphPaths:q,filter:m,searchTerm:b,darkMode:T,loading:G,enabled:V,isMobile:B});const{centerOnFont:Z,resetZoom:X}=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];const n=(0,s.useRef)(null);return(0,s.useEffect)(()=>{if(!t||!e.current)return;const s=a.Ltv(e.current);if(s.select(".viewport-group").empty())return;s.on(".zoom",null);const o=a.s_O().scaleExtent(f).translateExtent([[0,0],[l,c]]).on("zoom",e=>{s.select(".viewport-group").attr("transform",e.transform),s.select(".highlight-group").attr("transform",e.transform),s.select(".centroids-group").attr("transform",e.transform),window.updateCentroidLabels&&window.updateCentroidLabels(),window.updateTooltipTransform&&window.updateTooltipTransform(e.transform),window.updateTooltipPositions&&window.updateTooltipPositions()});s.call(o),s.call(o.transform,p),n.current=o,window.zoomIn=()=>s.transition().duration(200).call(o.scaleBy,1.5),window.zoomOut=()=>s.transition().duration(200).call(o.scaleBy,1/1.5),window.resetZoom=()=>{const e=i.getState();e.setIsTransitioning(!0),e.setHoveredFont(null),s.transition().duration(750).call(o.transform,p).on("end",()=>{i.getState().setIsTransitioning(!1)})};const r=e.current;return()=>{r&&a.Ltv(r).on(".zoom",null),delete window.zoomIn,delete window.zoomOut,delete window.resetZoom,n.current=null}},[t,e]),{centerOnFont:(0,s.useCallback)(t=>{if(!t||!n.current||!e.current)return;const s=a.Ltv(e.current),o=s.select('g.glyph-group[data-font-id="'.concat(t.id,'"]'));if(o.empty())return;const r=o.attr("data-original-transform");if(!r)return;const l=r.match(/translate\(([^,]+),\s*([^)]+)\)/);if(!l)return;const c=800-4*parseFloat(l[1]),d=450-4*parseFloat(l[2]),u=a.GSI.translate(c,d).scale(4),h=i.getState();h.setIsTransitioning(!0),h.setHoveredFont(null),s.transition().duration(800).ease(a.oRn).call(n.current.transform,u).on("end",()=>{i.getState().setIsTransitioning(!1)})},[e]),resetZoom:(0,s.useCallback)(()=>{window.resetZoom&&window.resetZoom()},[])}}(n,V);function Y(e){W(null),_(e)}((e,t,n,o,r)=>{const a=(0,s.useCallback)(()=>t&&0!==t.length?t.filter(e=>{const t="all"===n||e.family===n,s=!o||e.name.toLowerCase().includes(o.toLowerCase())||e.family.toLowerCase().includes(o.toLowerCase());return t&&s}):[],[t,n,o]),i=(0,s.useCallback)(t=>{if(!e||!r)return;const n=a();if(n.length<=1)return;const s=n.find(t=>t.name===e.name);if(!s)return;let o=null,i=1/0;n.forEach(n=>{if(n.name===e.name)return;const r=n.x-s.x,a=n.y-s.y,l=Math.sqrt(r*r+a*a);if(0===l)return;let c=!1;switch(t){case"ArrowUp":c=a>0&&Math.abs(r)<=2*Math.abs(a);break;case"ArrowDown":c=a<0&&Math.abs(r)<=2*Math.abs(a);break;case"ArrowLeft":c=r<0&&Math.abs(a)<=2*Math.abs(r);break;case"ArrowRight":c=r>0&&Math.abs(a)<=2*Math.abs(r);break;default:return}c&&l<i&&(i=l,o=n)}),o&&r(o)},[e,a,r]),l=(0,s.useCallback)(t=>{if(!e)return;const n=document.activeElement;return!n||"INPUT"!==n.tagName&&"TEXTAREA"!==n.tagName&&"true"!==n.contentEditable?"Escape"===t.key?(t.preventDefault(),void r(null)):void(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(t.key)&&(t.preventDefault(),i(t.key))):void 0},[e,i,r]);(0,s.useEffect)(()=>(window.addEventListener("keydown",l),()=>{window.removeEventListener("keydown",l)}),[l]),e&&a().length,a().length,null===e||void 0===e||e.name})(O,D,m,b,Y),(0,s.useEffect)(()=>{O&&Z(O)},[O,Z]),(0,s.useEffect)(()=>{G?L("loading"):D.length>0&&"loading"===N&&L("intro")},[G,D.length,N]);const J=D.length,K="all"===m?J:D.filter(e=>e.family===m).length,Q=(0,s.useMemo)(()=>D.filter(e=>{const t="all"===m||e.family===m,n=!b||e.name.toLowerCase().includes(b.toLowerCase())||e.family.toLowerCase().includes(b.toLowerCase());return t&&n}),[D,m,b]).length,$=(0,s.useMemo)(()=>q&&0!==Object.keys(q).length?(0,g.jsx)("svg",{style:{position:"absolute",width:0,height:0,overflow:"hidden"},"aria-hidden":"true",children:(0,g.jsx)("defs",{children:Object.entries(q).map(e=>{let[t,n]=e;return(0,g.jsx)("symbol",{id:t,viewBox:"0 0 80 80",children:(0,g.jsx)("path",{d:n,fill:"currentColor"})},t)})})}):null,[q]);return U?(0,g.jsx)("div",{className:"fontmap-container",children:(0,g.jsxs)("div",{className:"error",children:[(0,g.jsx)("h3",{children:"Loading error"}),(0,g.jsx)("p",{children:U}),(0,g.jsx)("button",{onClick:()=>window.location.reload(),children:"Reload the page"})]})}):(0,g.jsxs)("div",{className:"fontmap-container ".concat(T?"dark-mode":""," ").concat(O?"has-focus":""),children:[$,(0,g.jsxs)("div",{className:"sidebar",children:[(0,g.jsxs)("div",{className:"sidebar-content",children:[(0,g.jsx)("div",{className:"sidebar-header",children:(0,g.jsxs)("div",{className:"search-section",children:[(0,g.jsx)(v,{searchTerm:b,onSearchChange:k,darkMode:T,big:!0,filteredCount:Q,totalCount:K,filter:m}),(0,g.jsx)(x,{fonts:D,filter:m,onFilterChange:w})]})}),(0,g.jsx)(C,{selectedFont:O,fonts:D,darkMode:T,onClose:()=>_(null),onFontSelect:Y})]}),(0,g.jsxs)("div",{className:"sidebar-footer",children:[(0,g.jsxs)("button",{className:"about-link",onClick:()=>A(!0),title:"How FontMap Works",children:[(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,g.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,g.jsx)("path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"}),(0,g.jsx)("line",{x1:"12",y1:"17",x2:"12.01",y2:"17"})]}),"How it works"]}),(0,g.jsxs)("a",{className:"source-link",href:"https://huggingface.co/spaces/tfrere/fontmap",target:"_blank",rel:"noopener noreferrer",title:"View Source on Hugging Face Spaces",children:[(0,g.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:(0,g.jsx)("path",{d:"M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"})}),"Source"]})]})]}),(0,g.jsxs)("div",{className:"main-area",children:[(0,g.jsx)("h1",{className:"map-title","data-text":"FontMap",children:"FontMap"}),(0,g.jsxs)("div",{className:"bottom-controls",children:[(0,g.jsx)("button",{className:"dark-mode-toggle",onClick:H,title:T?"Switch to light mode":"Switch to dark mode","aria-label":"Toggle dark mode",children:(0,g.jsx)("span",{className:"dark-mode-toggle-icon",style:{transform:"rotate(".concat(I,"deg)")},children:T?(0,g.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[(0,g.jsx)("circle",{cx:"12",cy:"12",r:"4"}),(0,g.jsx)("path",{d:"M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"})]}):(0,g.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:(0,g.jsx)("path",{d:"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"})})})}),(0,g.jsx)(j,{darkMode:T}),(0,g.jsx)(y,{})]}),(0,g.jsx)("div",{className:"map-container",children:(0,g.jsx)("svg",{ref:n,className:"fontmap-svg"})}),O&&(0,g.jsxs)("div",{className:"focus-hint",children:[(0,g.jsxs)("div",{className:"focus-hint-keys",children:[(0,g.jsx)("kbd",{children:"\u2190"}),(0,g.jsx)("kbd",{children:"\u2191"}),(0,g.jsx)("kbd",{children:"\u2193"}),(0,g.jsx)("kbd",{children:"\u2192"})]}),(0,g.jsx)("span",{className:"focus-hint-label",children:"use arrow keys to navigate"})]}),!G&&D.length>0&&(0,g.jsx)(S,{darkMode:T,isMobile:B,onOpenFont:Y})]}),"loading"===N&&(0,g.jsx)("div",{className:"unified-overlay",children:(0,g.jsx)("div",{className:"overlay-spinner"})}),"intro"===N&&(0,g.jsx)(F,{onStartExploring:()=>L("ready"),darkMode:T}),M&&(0,g.jsx)(E,{onClose:()=>A(!1),darkMode:T}),u&&(0,g.jsx)(z,{isDebugMode:!0})]})}},722:function(e){e.exports=function(){var e=function(){function t(e){return o.appendChild(e.dom),e}function n(e){for(var t=0;t<o.children.length;t++)o.children[t].style.display=t===e?"block":"none";s=e}var s=0,o=document.createElement("div");o.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000",o.addEventListener("click",function(e){e.preventDefault(),n(++s%o.children.length)},!1);var r=(performance||Date).now(),a=r,i=0,l=t(new e.Panel("FPS","#0ff","#002")),c=t(new e.Panel("MS","#0f0","#020"));if(self.performance&&self.performance.memory)var d=t(new e.Panel("MB","#f08","#201"));return n(0),{REVISION:16,dom:o,addPanel:t,showPanel:n,begin:function(){r=(performance||Date).now()},end:function(){i++;var e=(performance||Date).now();if(c.update(e-r,200),e>a+1e3&&(l.update(1e3*i/(e-a),100),a=e,i=0,d)){var t=performance.memory;d.update(t.usedJSHeapSize/1048576,t.jsHeapSizeLimit/1048576)}return e},update:function(){r=this.end()},domElement:o,setMode:n}};return e.Panel=function(e,t,n){var s=1/0,o=0,r=Math.round,a=r(window.devicePixelRatio||1),i=80*a,l=48*a,c=3*a,d=2*a,u=3*a,h=15*a,m=74*a,f=30*a,p=document.createElement("canvas");p.width=i,p.height=l,p.style.cssText="width:80px;height:48px";var g=p.getContext("2d");return g.font="bold "+9*a+"px Helvetica,Arial,sans-serif",g.textBaseline="top",g.fillStyle=n,g.fillRect(0,0,i,l),g.fillStyle=t,g.fillText(e,c,d),g.fillRect(u,h,m,f),g.fillStyle=n,g.globalAlpha=.9,g.fillRect(u,h,m,f),{dom:p,update:function(l,x){s=Math.min(s,l),o=Math.max(o,l),g.fillStyle=n,g.globalAlpha=1,g.fillRect(0,0,i,h),g.fillStyle=t,g.fillText(r(l)+" "+e+" ("+r(s)+"-"+r(o)+")",c,d),g.drawImage(p,u+a,h,m-a,f,u,h,m-a,f),g.fillRect(u+m-a,h,a,f),g.fillStyle=n,g.globalAlpha=.9,g.fillRect(u+m-a,h,a,r((1-l/x)*f))}}},e}()},6907:(e,t,n)=>{"use strict";n.d(t,{t:()=>o});var s=n(5043);function o(){const[e,t]=(0,s.useState)([]),[n,o]=(0,s.useState)({}),[r,a]=(0,s.useState)(!0),[i,l]=(0,s.useState)(null);return(0,s.useEffect)(()=>{(async()=>{try{console.log("\ud83d\udce6 Loading static font map data...");const n={};try{let e="";const t=await fetch("/data/font-sprite.svg");if(t.ok)e=await t.text();else{console.warn("\u26a0\ufe0f Sprite not found at /data/font-sprite.svg, trying root...");const t=await fetch("/font-sprite.svg");t.ok&&(e=await t.text())}if(e){const t=(new DOMParser).parseFromString(e,"image/svg+xml");t.querySelectorAll("symbol").forEach(e=>{const t=e.id,s=e.querySelector("path");t&&s&&(n[t]=s.getAttribute("d"))}),console.log("\ud83c\udfa8 Extracted ".concat(Object.keys(n).length," glyph paths")),o(n)}}catch(e){console.warn("\u26a0\ufe0f Error loading/parsing sprite:",e)}let s;const r=await fetch("/data/font-map.json"),i=r.headers.get("content-type");if(r.ok&&i&&i.includes("application/json"))s=await r.json(),console.log("\ud83d\udccd Loaded from font-map.json");else{console.warn("\u26a0\ufe0f font-map.json not available, falling back to typography_data.json");const e=await fetch("/data/typography_data.json");if(!e.ok)throw new Error("No font data found. Neither font-map.json nor typography_data.json available.");s=await e.json(),console.log("\ud83d\udccd Loaded from typography_data.json (fallback)")}if(!s.fonts||!Array.isArray(s.fonts))throw new Error("Invalid data format: missing fonts array");console.log("\u2705 Loaded ".concat(s.fonts.length," fonts from static map")),t(s.fonts),a(!1)}catch(n){console.error("\u274c Error loading static font data:",n),l(n.message),a(!1)}})()},[]),{fonts:e,glyphPaths:n,loading:r,error:i}}}}]);
|
| 2 |
+
//# sourceMappingURL=632.2f16deee.chunk.js.map
|
build/static/js/632.2f16deee.chunk.js.map
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/static/js/632.d7330879.chunk.js.map
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/static/js/{main.7e00c86e.js → main.ac7b1f26.js}
RENAMED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/static/js/{main.7e00c86e.js.LICENSE.txt → main.ac7b1f26.js.LICENSE.txt}
RENAMED
|
File without changes
|
build/static/js/{main.7e00c86e.js.map → main.ac7b1f26.js.map}
RENAMED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/components/FontMap/components/AboutModal.js
CHANGED
|
@@ -7,7 +7,8 @@ import ModalPortal from './ModalPortal';
|
|
| 7 |
const AboutModal = ({ onClose, darkMode }) => {
|
| 8 |
return (
|
| 9 |
<ModalPortal isOpen={true}>
|
| 10 |
-
|
|
|
|
| 11 |
<div className="about-modal" onClick={(e) => e.stopPropagation()}>
|
| 12 |
<div className="about-modal-content">
|
| 13 |
<div className="about-modal-header">
|
|
@@ -136,7 +137,7 @@ const AboutModal = ({ onClose, darkMode }) => {
|
|
| 136 |
<p className="about-section-text">
|
| 137 |
The <strong>complete dataset</strong> is also open source, including all font metadata, FontCLIP embeddings and positioning data from <a href="https://fonts.google.com" target="_blank" rel="noopener noreferrer" className="google-fonts-link">Google Fonts</a>.
|
| 138 |
</p>
|
| 139 |
-
<a href="https://huggingface.co/spaces/
|
| 140 |
View Source on Hugging Face →
|
| 141 |
</a>
|
| 142 |
|
|
|
|
| 7 |
const AboutModal = ({ onClose, darkMode }) => {
|
| 8 |
return (
|
| 9 |
<ModalPortal isOpen={true}>
|
| 10 |
+
{/* dark-mode class must be re-applied here: the portal renders outside .fontmap-container */}
|
| 11 |
+
<div className={`unified-overlay${darkMode ? ' dark-mode' : ''}`} onClick={onClose}>
|
| 12 |
<div className="about-modal" onClick={(e) => e.stopPropagation()}>
|
| 13 |
<div className="about-modal-content">
|
| 14 |
<div className="about-modal-header">
|
|
|
|
| 137 |
<p className="about-section-text">
|
| 138 |
The <strong>complete dataset</strong> is also open source, including all font metadata, FontCLIP embeddings and positioning data from <a href="https://fonts.google.com" target="_blank" rel="noopener noreferrer" className="google-fonts-link">Google Fonts</a>.
|
| 139 |
</p>
|
| 140 |
+
<a href="https://huggingface.co/spaces/tfrere/fontmap" target="_blank" rel="noopener noreferrer" className="code-link">
|
| 141 |
View Source on Hugging Face →
|
| 142 |
</a>
|
| 143 |
|
src/components/FontMap/components/IntroModal.js
CHANGED
|
@@ -7,7 +7,8 @@ import ModalPortal from './ModalPortal';
|
|
| 7 |
const IntroModal = ({ onStartExploring, darkMode }) => {
|
| 8 |
return (
|
| 9 |
<ModalPortal isOpen={true}>
|
| 10 |
-
|
|
|
|
| 11 |
<div className="intro-modal" onClick={(e) => e.stopPropagation()}>
|
| 12 |
<div className="intro-modal-content">
|
| 13 |
<h1 className="intro-title">FontMap</h1>
|
|
|
|
| 7 |
const IntroModal = ({ onStartExploring, darkMode }) => {
|
| 8 |
return (
|
| 9 |
<ModalPortal isOpen={true}>
|
| 10 |
+
{/* dark-mode class must be re-applied here: the portal renders outside .fontmap-container */}
|
| 11 |
+
<div className={`unified-overlay${darkMode ? ' dark-mode' : ''}`} onClick={onStartExploring}>
|
| 12 |
<div className="intro-modal" onClick={(e) => e.stopPropagation()}>
|
| 13 |
<div className="intro-modal-content">
|
| 14 |
<h1 className="intro-title">FontMap</h1>
|
src/components/FontMap/hooks/useTooltipOptimized.js
CHANGED
|
@@ -17,13 +17,13 @@ export const useTooltipOptimized = (darkMode, isMobile = false, onOpenFont = nul
|
|
| 17 |
// Mémoriser les styles du tooltip selon le mode sombre
|
| 18 |
const tooltipStyles = useMemo(() => ({
|
| 19 |
dark: {
|
| 20 |
-
backgroundColor: '
|
| 21 |
-
borderColor: '
|
| 22 |
color: '#ffffff'
|
| 23 |
},
|
| 24 |
light: {
|
| 25 |
-
backgroundColor: '
|
| 26 |
-
borderColor: '
|
| 27 |
color: '#000000'
|
| 28 |
}
|
| 29 |
}), []);
|
|
|
|
| 17 |
// Mémoriser les styles du tooltip selon le mode sombre
|
| 18 |
const tooltipStyles = useMemo(() => ({
|
| 19 |
dark: {
|
| 20 |
+
backgroundColor: 'var(--color-bg-primary-dark)',
|
| 21 |
+
borderColor: 'var(--color-border-primary-dark)',
|
| 22 |
color: '#ffffff'
|
| 23 |
},
|
| 24 |
light: {
|
| 25 |
+
backgroundColor: 'var(--color-bg-primary)',
|
| 26 |
+
borderColor: 'var(--color-border-primary)',
|
| 27 |
color: '#000000'
|
| 28 |
}
|
| 29 |
}), []);
|
src/components/FontMap/styles/about-modal.css
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
/* About Modal Styles */
|
| 2 |
|
| 3 |
.about-modal {
|
|
|
|
|
|
|
| 4 |
background: var(--color-bg-primary);
|
| 5 |
border: 1px solid var(--color-border-primary);
|
| 6 |
border-radius: var(--border-radius-lg);
|
|
@@ -21,7 +23,9 @@
|
|
| 21 |
.about-modal-content {
|
| 22 |
display: flex;
|
| 23 |
flex-direction: column;
|
| 24 |
-
|
|
|
|
|
|
|
| 25 |
}
|
| 26 |
|
| 27 |
/* Header */
|
|
@@ -87,6 +91,7 @@
|
|
| 87 |
padding: 20px 24px;
|
| 88 |
overflow-y: auto;
|
| 89 |
flex: 1;
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
/* Hero Section */
|
|
@@ -116,17 +121,25 @@
|
|
| 116 |
}
|
| 117 |
|
| 118 |
.about-section-title {
|
| 119 |
-
font-size:
|
| 120 |
font-weight: 600;
|
| 121 |
-
|
| 122 |
-
|
|
|
|
|
|
|
| 123 |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
| 124 |
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
| 125 |
sans-serif;
|
| 126 |
}
|
| 127 |
|
| 128 |
.dark-mode .about-section-title {
|
| 129 |
-
color: var(--color-text-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
}
|
| 131 |
|
| 132 |
.about-section-text {
|
|
@@ -143,8 +156,9 @@
|
|
| 143 |
/* Content Grid Layout */
|
| 144 |
.about-content-grid {
|
| 145 |
display: grid;
|
| 146 |
-
|
| 147 |
-
|
|
|
|
| 148 |
align-items: start;
|
| 149 |
margin-top: 24px;
|
| 150 |
}
|
|
@@ -155,6 +169,19 @@
|
|
| 155 |
gap: 16px;
|
| 156 |
}
|
| 157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
/* Pipeline Demo */
|
| 159 |
.pipeline-demo {
|
| 160 |
display: flex;
|
|
@@ -178,14 +205,26 @@
|
|
| 178 |
.pipeline-steps {
|
| 179 |
display: flex;
|
| 180 |
flex-direction: column;
|
| 181 |
-
gap:
|
| 182 |
}
|
| 183 |
|
| 184 |
.step-item {
|
| 185 |
display: flex;
|
| 186 |
align-items: center;
|
| 187 |
-
gap:
|
| 188 |
-
padding: 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
}
|
| 190 |
|
| 191 |
.step-content {
|
|
@@ -197,6 +236,11 @@
|
|
| 197 |
align-items: center;
|
| 198 |
gap: 8px;
|
| 199 |
margin-bottom: 4px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
}
|
| 201 |
|
| 202 |
.step-number {
|
|
@@ -232,6 +276,12 @@
|
|
| 232 |
|
| 233 |
.step-example {
|
| 234 |
flex-shrink: 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
}
|
| 236 |
|
| 237 |
/* Mini Matrix */
|
|
@@ -239,7 +289,8 @@
|
|
| 239 |
font-family: 'Courier New', monospace;
|
| 240 |
font-size: 6px;
|
| 241 |
line-height: 1;
|
| 242 |
-
background:
|
|
|
|
| 243 |
padding: 4px;
|
| 244 |
border-radius: 2px;
|
| 245 |
border: 1px solid var(--color-border-primary);
|
|
@@ -248,6 +299,7 @@
|
|
| 248 |
.dark-mode .mini-matrix {
|
| 249 |
background: var(--color-bg-secondary-dark);
|
| 250 |
border-color: var(--color-border-primary-dark);
|
|
|
|
| 251 |
}
|
| 252 |
|
| 253 |
.mini-row {
|
|
@@ -352,25 +404,29 @@
|
|
| 352 |
/* Code Link */
|
| 353 |
.code-link {
|
| 354 |
display: inline-block;
|
| 355 |
-
|
| 356 |
-
font-
|
|
|
|
| 357 |
color: var(--color-text-primary);
|
| 358 |
-
text-decoration:
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
|
|
|
| 362 |
}
|
| 363 |
|
| 364 |
.code-link:hover {
|
| 365 |
-
color: var(--color-text-
|
|
|
|
| 366 |
}
|
| 367 |
|
| 368 |
.dark-mode .code-link {
|
| 369 |
color: var(--color-text-primary-dark);
|
|
|
|
| 370 |
}
|
| 371 |
|
| 372 |
.dark-mode .code-link:hover {
|
| 373 |
-
color: var(--color-text-
|
| 374 |
}
|
| 375 |
|
| 376 |
/* Inline Link */
|
|
@@ -686,12 +742,31 @@
|
|
| 686 |
gap: 24px;
|
| 687 |
}
|
| 688 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 689 |
.step-item {
|
| 690 |
flex-direction: column;
|
| 691 |
align-items: flex-start;
|
| 692 |
gap: 12px;
|
| 693 |
}
|
| 694 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
.step-example {
|
| 696 |
align-self: center;
|
| 697 |
}
|
|
|
|
| 1 |
/* About Modal Styles */
|
| 2 |
|
| 3 |
.about-modal {
|
| 4 |
+
display: flex;
|
| 5 |
+
flex-direction: column;
|
| 6 |
background: var(--color-bg-primary);
|
| 7 |
border: 1px solid var(--color-border-primary);
|
| 8 |
border-radius: var(--border-radius-lg);
|
|
|
|
| 23 |
.about-modal-content {
|
| 24 |
display: flex;
|
| 25 |
flex-direction: column;
|
| 26 |
+
flex: 1;
|
| 27 |
+
/* Allows the flex child to shrink below its content size so the body can scroll */
|
| 28 |
+
min-height: 0;
|
| 29 |
}
|
| 30 |
|
| 31 |
/* Header */
|
|
|
|
| 91 |
padding: 20px 24px;
|
| 92 |
overflow-y: auto;
|
| 93 |
flex: 1;
|
| 94 |
+
min-height: 0;
|
| 95 |
}
|
| 96 |
|
| 97 |
/* Hero Section */
|
|
|
|
| 121 |
}
|
| 122 |
|
| 123 |
.about-section-title {
|
| 124 |
+
font-size: 12px;
|
| 125 |
font-weight: 600;
|
| 126 |
+
text-transform: uppercase;
|
| 127 |
+
letter-spacing: 0.08em;
|
| 128 |
+
color: var(--color-text-tertiary);
|
| 129 |
+
margin: 0;
|
| 130 |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
| 131 |
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
| 132 |
sans-serif;
|
| 133 |
}
|
| 134 |
|
| 135 |
.dark-mode .about-section-title {
|
| 136 |
+
color: var(--color-text-tertiary-dark);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
/* Second section in a column gets breathing room above */
|
| 140 |
+
.about-column .about-section-title + .about-section-title,
|
| 141 |
+
.about-column .code-link + .about-section-title {
|
| 142 |
+
margin-top: 16px;
|
| 143 |
}
|
| 144 |
|
| 145 |
.about-section-text {
|
|
|
|
| 156 |
/* Content Grid Layout */
|
| 157 |
.about-content-grid {
|
| 158 |
display: grid;
|
| 159 |
+
/* Left column holds the dense technical steps, give it more room */
|
| 160 |
+
grid-template-columns: 1.5fr 1fr;
|
| 161 |
+
gap: 0;
|
| 162 |
align-items: start;
|
| 163 |
margin-top: 24px;
|
| 164 |
}
|
|
|
|
| 169 |
gap: 16px;
|
| 170 |
}
|
| 171 |
|
| 172 |
+
.about-column:first-child {
|
| 173 |
+
padding-right: 32px;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
.about-column:last-child {
|
| 177 |
+
padding-left: 32px;
|
| 178 |
+
border-left: 1px solid var(--color-border-primary);
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
.dark-mode .about-column:last-child {
|
| 182 |
+
border-left-color: var(--color-border-primary-dark);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
/* Pipeline Demo */
|
| 186 |
.pipeline-demo {
|
| 187 |
display: flex;
|
|
|
|
| 205 |
.pipeline-steps {
|
| 206 |
display: flex;
|
| 207 |
flex-direction: column;
|
| 208 |
+
gap: 0;
|
| 209 |
}
|
| 210 |
|
| 211 |
.step-item {
|
| 212 |
display: flex;
|
| 213 |
align-items: center;
|
| 214 |
+
gap: 20px;
|
| 215 |
+
padding: 16px 0;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
.step-item:first-child {
|
| 219 |
+
padding-top: 8px;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
.step-item + .step-item {
|
| 223 |
+
border-top: 1px solid var(--color-border-primary);
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
.dark-mode .step-item + .step-item {
|
| 227 |
+
border-top-color: var(--color-border-primary-dark);
|
| 228 |
}
|
| 229 |
|
| 230 |
.step-content {
|
|
|
|
| 236 |
align-items: center;
|
| 237 |
gap: 8px;
|
| 238 |
margin-bottom: 4px;
|
| 239 |
+
color: var(--color-text-primary);
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
.dark-mode .step-header {
|
| 243 |
+
color: var(--color-text-primary-dark);
|
| 244 |
}
|
| 245 |
|
| 246 |
.step-number {
|
|
|
|
| 276 |
|
| 277 |
.step-example {
|
| 278 |
flex-shrink: 0;
|
| 279 |
+
/* Fixed column so the demos align vertically across steps */
|
| 280 |
+
width: 150px;
|
| 281 |
+
display: flex;
|
| 282 |
+
flex-direction: column;
|
| 283 |
+
align-items: center;
|
| 284 |
+
justify-content: center;
|
| 285 |
}
|
| 286 |
|
| 287 |
/* Mini Matrix */
|
|
|
|
| 289 |
font-family: 'Courier New', monospace;
|
| 290 |
font-size: 6px;
|
| 291 |
line-height: 1;
|
| 292 |
+
background: var(--color-bg-primary);
|
| 293 |
+
color: var(--color-text-primary);
|
| 294 |
padding: 4px;
|
| 295 |
border-radius: 2px;
|
| 296 |
border: 1px solid var(--color-border-primary);
|
|
|
|
| 299 |
.dark-mode .mini-matrix {
|
| 300 |
background: var(--color-bg-secondary-dark);
|
| 301 |
border-color: var(--color-border-primary-dark);
|
| 302 |
+
color: var(--color-text-primary-dark);
|
| 303 |
}
|
| 304 |
|
| 305 |
.mini-row {
|
|
|
|
| 404 |
/* Code Link */
|
| 405 |
.code-link {
|
| 406 |
display: inline-block;
|
| 407 |
+
align-self: flex-start;
|
| 408 |
+
font-size: 13px;
|
| 409 |
+
font-weight: 600;
|
| 410 |
color: var(--color-text-primary);
|
| 411 |
+
text-decoration: none;
|
| 412 |
+
padding: 8px 14px;
|
| 413 |
+
border: 1px solid var(--color-border-secondary);
|
| 414 |
+
border-radius: var(--border-radius-md);
|
| 415 |
+
transition: all var(--transition-normal);
|
| 416 |
}
|
| 417 |
|
| 418 |
.code-link:hover {
|
| 419 |
+
border-color: var(--color-text-primary);
|
| 420 |
+
box-shadow: var(--shadow-sm);
|
| 421 |
}
|
| 422 |
|
| 423 |
.dark-mode .code-link {
|
| 424 |
color: var(--color-text-primary-dark);
|
| 425 |
+
border-color: var(--color-border-secondary-dark);
|
| 426 |
}
|
| 427 |
|
| 428 |
.dark-mode .code-link:hover {
|
| 429 |
+
border-color: var(--color-text-primary-dark);
|
| 430 |
}
|
| 431 |
|
| 432 |
/* Inline Link */
|
|
|
|
| 742 |
gap: 24px;
|
| 743 |
}
|
| 744 |
|
| 745 |
+
.about-column:first-child {
|
| 746 |
+
padding-right: 0;
|
| 747 |
+
}
|
| 748 |
+
|
| 749 |
+
.about-column:last-child {
|
| 750 |
+
padding-left: 0;
|
| 751 |
+
border-left: none;
|
| 752 |
+
border-top: 1px solid var(--color-border-primary);
|
| 753 |
+
padding-top: 24px;
|
| 754 |
+
}
|
| 755 |
+
|
| 756 |
+
.dark-mode .about-column:last-child {
|
| 757 |
+
border-top-color: var(--color-border-primary-dark);
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
.step-item {
|
| 761 |
flex-direction: column;
|
| 762 |
align-items: flex-start;
|
| 763 |
gap: 12px;
|
| 764 |
}
|
| 765 |
|
| 766 |
+
.step-example {
|
| 767 |
+
width: 100%;
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
.step-example {
|
| 771 |
align-self: center;
|
| 772 |
}
|
src/components/FontMap/styles/font-details.css
CHANGED
|
@@ -425,7 +425,7 @@
|
|
| 425 |
}
|
| 426 |
|
| 427 |
.action-btn.ghost {
|
| 428 |
-
background:
|
| 429 |
color: var(--color-text-primary);
|
| 430 |
border: 1px solid var(--color-text-secondary);
|
| 431 |
margin-top: var(--spacing-md);
|
|
|
|
| 425 |
}
|
| 426 |
|
| 427 |
.action-btn.ghost {
|
| 428 |
+
background: var(--color-bg-primary);
|
| 429 |
color: var(--color-text-primary);
|
| 430 |
border: 1px solid var(--color-text-secondary);
|
| 431 |
margin-top: var(--spacing-md);
|
src/components/FontMap/styles/intro-modal.css
CHANGED
|
@@ -44,6 +44,8 @@
|
|
| 44 |
/* Intro Modal Styles */
|
| 45 |
|
| 46 |
.intro-modal {
|
|
|
|
|
|
|
| 47 |
background: var(--color-bg-primary);
|
| 48 |
border: 1px solid var(--color-border-primary);
|
| 49 |
border-radius: var(--border-radius-lg);
|
|
@@ -74,6 +76,8 @@
|
|
| 74 |
.intro-modal-content {
|
| 75 |
padding: var(--spacing-xl);
|
| 76 |
text-align: center;
|
|
|
|
|
|
|
| 77 |
}
|
| 78 |
|
| 79 |
.intro-title {
|
|
|
|
| 44 |
/* Intro Modal Styles */
|
| 45 |
|
| 46 |
.intro-modal {
|
| 47 |
+
display: flex;
|
| 48 |
+
flex-direction: column;
|
| 49 |
background: var(--color-bg-primary);
|
| 50 |
border: 1px solid var(--color-border-primary);
|
| 51 |
border-radius: var(--border-radius-lg);
|
|
|
|
| 76 |
.intro-modal-content {
|
| 77 |
padding: var(--spacing-xl);
|
| 78 |
text-align: center;
|
| 79 |
+
overflow-y: auto;
|
| 80 |
+
min-height: 0;
|
| 81 |
}
|
| 82 |
|
| 83 |
.intro-title {
|
src/components/FontMap/styles/tooltip.css
CHANGED
|
@@ -155,7 +155,7 @@
|
|
| 155 |
|
| 156 |
/* Force dark mode styles */
|
| 157 |
.font-tooltip.dark-mode {
|
| 158 |
-
background:
|
| 159 |
border: none !important;
|
| 160 |
color: #ffffff !important;
|
| 161 |
}
|
|
|
|
| 155 |
|
| 156 |
/* Force dark mode styles */
|
| 157 |
.font-tooltip.dark-mode {
|
| 158 |
+
background: var(--color-bg-primary-dark) !important;
|
| 159 |
border: none !important;
|
| 160 |
color: #ffffff !important;
|
| 161 |
}
|
src/components/FontMap/styles/variables.css
CHANGED
|
@@ -1,21 +1,21 @@
|
|
| 1 |
/* CSS Variables for style normalization */
|
| 2 |
:root {
|
| 3 |
-
/* Primary colors */
|
| 4 |
-
--color-bg-primary: #
|
| 5 |
-
--color-bg-secondary: #
|
| 6 |
-
--color-bg-tertiary: #
|
| 7 |
--color-text-primary: #000000;
|
| 8 |
--color-text-secondary: #666666;
|
| 9 |
--color-text-tertiary: #999999;
|
| 10 |
-
--color-border-primary: #
|
| 11 |
-
--color-border-secondary: #
|
| 12 |
--color-accent: #007acc;
|
| 13 |
--color-accent-hover: #005a9e;
|
| 14 |
|
| 15 |
-
/* Dark mode colors */
|
| 16 |
-
--color-bg-primary-dark: #
|
| 17 |
-
--color-bg-secondary-dark: #
|
| 18 |
-
--color-bg-tertiary-dark: #
|
| 19 |
--color-text-primary-dark: #ffffff;
|
| 20 |
--color-text-secondary-dark: #cccccc;
|
| 21 |
--color-text-tertiary-dark: #999999;
|
|
|
|
| 1 |
/* CSS Variables for style normalization */
|
| 2 |
:root {
|
| 3 |
+
/* Primary colors — backgrounds are very slightly warm (paper feel) */
|
| 4 |
+
--color-bg-primary: #fcfbf8;
|
| 5 |
+
--color-bg-secondary: #f7f5f1;
|
| 6 |
+
--color-bg-tertiary: #ece9e3;
|
| 7 |
--color-text-primary: #000000;
|
| 8 |
--color-text-secondary: #666666;
|
| 9 |
--color-text-tertiary: #999999;
|
| 10 |
+
--color-border-primary: #e3e0da;
|
| 11 |
+
--color-border-secondary: #d5d2cb;
|
| 12 |
--color-accent: #007acc;
|
| 13 |
--color-accent-hover: #005a9e;
|
| 14 |
|
| 15 |
+
/* Dark mode colors — same subtle warmth on charcoal */
|
| 16 |
+
--color-bg-primary-dark: #121110;
|
| 17 |
+
--color-bg-secondary-dark: #1c1a18;
|
| 18 |
+
--color-bg-tertiary-dark: #363330;
|
| 19 |
--color-text-primary-dark: #ffffff;
|
| 20 |
--color-text-secondary-dark: #cccccc;
|
| 21 |
--color-text-tertiary-dark: #999999;
|