Spaces:
Running
Running
Upload 7 files
Browse files- data.js +0 -0
- favicon.svg +16 -0
- index.html +418 -17
- manifest.json +20 -0
- scripts.js +858 -0
- skills.json +0 -0
- styles.css +1573 -0
data.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
favicon.svg
ADDED
|
|
index.html
CHANGED
|
@@ -1,19 +1,420 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
| 6 |
+
<title>SkillsAllYouNeed for LLMs β The Open Registry of AI Skills</title>
|
| 7 |
+
|
| 8 |
+
<!-- Favicon & PWA -->
|
| 9 |
+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
| 10 |
+
<link rel="apple-touch-icon" href="favicon.svg">
|
| 11 |
+
<link rel="manifest" href="manifest.json">
|
| 12 |
+
<meta name="theme-color" content="#F2EFE6" media="(prefers-color-scheme: light)">
|
| 13 |
+
<meta name="theme-color" content="#17140F" media="(prefers-color-scheme: dark)">
|
| 14 |
+
|
| 15 |
+
<!-- SEO -->
|
| 16 |
+
<meta name="description" content="The open registry of AI skills β 226 ready-to-use skill definitions for Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi. Browse, filter, copy the trigger phrase and go.">
|
| 17 |
+
<meta name="keywords" content="AI skills, Claude Code skills, ChatGPT skills, Gemini skills, LLM skills, AI capabilities, Claude skills, Perplexity skills, Copilot skills, OpenCode skills, Codex skills, Cursor skills, Kiro skills, Pi skills, Antigravity skills, GitHub Copilot skills, skill definitions">
|
| 18 |
+
<link rel="canonical" href="https://kishormorol.github.io/SkillsAllYouNeed/">
|
| 19 |
+
|
| 20 |
+
<!-- Open Graph (rich previews on Slack, LinkedIn, iMessage, etc.) -->
|
| 21 |
+
<meta property="og:type" content="website">
|
| 22 |
+
<meta property="og:url" content="https://kishormorol.github.io/SkillsAllYouNeed/">
|
| 23 |
+
<meta property="og:title" content="SkillsAllYouNeed for LLMs β The Open Registry of AI Skills">
|
| 24 |
+
<meta property="og:description" content="226 ready-to-use skill definitions for Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi. Browse, filter, copy the trigger phrase and go.">
|
| 25 |
+
<meta property="og:site_name" content="SkillsAllYouNeed">
|
| 26 |
+
|
| 27 |
+
<!-- Twitter / X card -->
|
| 28 |
+
<meta name="twitter:card" content="summary">
|
| 29 |
+
<meta name="twitter:title" content="SkillsAllYouNeed for LLMs">
|
| 30 |
+
<meta name="twitter:description" content="226 ready-to-use AI skill definitions for Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi. Free, open, filterable.">
|
| 31 |
+
<meta name="twitter:site" content="@kishormorol">
|
| 32 |
+
|
| 33 |
+
<!-- apply saved theme immediately so there's no flash on reload -->
|
| 34 |
+
<script>if(localStorage.getItem("sayn-theme")==="dark")document.documentElement.setAttribute("data-theme","dark");</script>
|
| 35 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 36 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 37 |
+
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;0,6..72,500;0,6..72,600;0,6..72,700;1,6..72,300;1,6..72,400&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
| 38 |
+
<script>
|
| 39 |
+
/* swap fallback fonts for web fonts once the font files have loaded, so first paint never flashes the wrong face */
|
| 40 |
+
if (document.fonts && document.fonts.ready) {
|
| 41 |
+
document.fonts.ready.then(function () {
|
| 42 |
+
document.documentElement.classList.add("fonts-loaded");
|
| 43 |
+
});
|
| 44 |
+
}
|
| 45 |
+
</script>
|
| 46 |
+
<link rel="stylesheet" href="styles.css">
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
<!-- JSON-LD structured data -->
|
| 51 |
+
<script type="application/ld+json">
|
| 52 |
+
{
|
| 53 |
+
"@context": "https://schema.org",
|
| 54 |
+
"@type": "Dataset",
|
| 55 |
+
"name": "SkillsAllYouNeed for LLMs",
|
| 56 |
+
"description": "The open registry of AI skills β ready-to-use skill definitions for Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi.",
|
| 57 |
+
"url": "https://kishormorol.github.io/SkillsAllYouNeed/",
|
| 58 |
+
"license": "https://creativecommons.org/licenses/by/4.0/",
|
| 59 |
+
"creator": {
|
| 60 |
+
"@type": "Person",
|
| 61 |
+
"name": "Md. Kishor Morol"
|
| 62 |
+
},
|
| 63 |
+
"keywords": ["AI skills","Claude","ChatGPT","Gemini","Perplexity","Copilot","OpenCode","Codex","Cursor","GitHub Copilot","Antigravity","Kiro","Pi","LLM","prompt engineering"],
|
| 64 |
+
"distribution": [
|
| 65 |
+
{
|
| 66 |
+
"@type": "DataDownload",
|
| 67 |
+
"encodingFormat": "application/json",
|
| 68 |
+
"contentUrl": "https://kishormorol.github.io/SkillsAllYouNeed/skills.json"
|
| 69 |
+
}
|
| 70 |
+
]
|
| 71 |
+
}
|
| 72 |
+
</script>
|
| 73 |
+
</head>
|
| 74 |
+
|
| 75 |
+
<body data-screen-label="SkillsAllYouNeed β single page">
|
| 76 |
+
|
| 77 |
+
<div class="shell">
|
| 78 |
+
|
| 79 |
+
<!-- βββ HERO βββ -->
|
| 80 |
+
<header class="hero" aria-label="Site header">
|
| 81 |
+
<div class="hero-top">
|
| 82 |
+
<div class="hero-brand">
|
| 83 |
+
<span class="hero-dot"></span>
|
| 84 |
+
SkillsAllYouNeed
|
| 85 |
+
</div>
|
| 86 |
+
<nav class="hero-nav" aria-label="Site links">
|
| 87 |
+
<a href="https://github.com/kishormorol/SkillsAllYouNeed" target="_blank" rel="noopener">GitHub</a>
|
| 88 |
+
<a href="https://github.com/kishormorol/SkillsAllYouNeed/issues/new?template=submit-capability.yml" target="_blank" rel="noopener">Submit skill</a>
|
| 89 |
+
<a id="star-btn" class="star-btn"
|
| 90 |
+
href="https://github.com/kishormorol/SkillsAllYouNeed"
|
| 91 |
+
target="_blank" rel="noopener"
|
| 92 |
+
aria-label="Star this project on GitHub"
|
| 93 |
+
title="Star on GitHub">
|
| 94 |
+
<span class="star-icon">β
</span>
|
| 95 |
+
Star
|
| 96 |
+
<span class="star-count" id="star-count" style="display:none"></span>
|
| 97 |
+
</a>
|
| 98 |
+
<button class="dark-toggle" id="dark-toggle" aria-label="Toggle dark mode" title="Toggle dark mode">β</button>
|
| 99 |
+
</nav>
|
| 100 |
+
</div>
|
| 101 |
+
<div class="hero-body">
|
| 102 |
+
<h1>Skills<em>All</em><br/>You<em>Need</em><span class="h1-sub"> for LLMs</span></h1>
|
| 103 |
+
<p class="hero-sub">The open registry of AI skills β ready-to-use skill definitions for Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi. Copy into your project, drop into Settings, and go.</p>
|
| 104 |
+
<div class="hero-stats" aria-label="Registry stats">
|
| 105 |
+
<div class="stat"><b id="hero-skill-count">0</b><span>skills</span></div>
|
| 106 |
+
<div class="stat"><b>13</b><span>ecosystems</span></div>
|
| 107 |
+
<div class="stat"><b>9</b><span>categories</span></div>
|
| 108 |
+
<div class="stat"><b>Free</b><span>to use</span></div>
|
| 109 |
+
</div>
|
| 110 |
+
<div class="hero-cta">
|
| 111 |
+
<a href="#catalog-section" class="cta-primary">Browse skills β</a>
|
| 112 |
+
<a href="https://github.com/kishormorol/SkillsAllYouNeed/issues/new?template=submit-capability.yml" target="_blank" rel="noopener" class="cta-ghost">Submit a skill</a>
|
| 113 |
+
<a href="https://github.com/kishormorol/SkillsAllYouNeed" target="_blank" rel="noopener" class="cta-ghost star-cta" aria-label="Star on GitHub">
|
| 114 |
+
β
Star on GitHub
|
| 115 |
+
<span id="star-count-cta" class="star-count-cta"></span>
|
| 116 |
+
</a>
|
| 117 |
+
</div>
|
| 118 |
+
</div>
|
| 119 |
+
</header>
|
| 120 |
+
|
| 121 |
+
<!-- βββ ONBOARDING STRIP (shown once, dismissible) βββ -->
|
| 122 |
+
<div class="onboarding-strip" id="onboarding-strip" aria-label="Welcome guide">
|
| 123 |
+
<div class="onboarding-inner">
|
| 124 |
+
<div class="onboarding-title">New here?</div>
|
| 125 |
+
<div class="onboarding-steps">
|
| 126 |
+
<div class="onboarding-step"><span class="step-num">1</span><span>Browse skills across Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi</span></div>
|
| 127 |
+
<div class="onboarding-step"><span class="step-num">2</span><span>Click any card β see the trigger phrase and how to activate it</span></div>
|
| 128 |
+
<div class="onboarding-step"><span class="step-num">3</span><span>Save favourites β₯, export as JSON, or submit a missing skill</span></div>
|
| 129 |
+
</div>
|
| 130 |
+
<button class="onboarding-dismiss" id="onboarding-dismiss" aria-label="Dismiss welcome guide">Got it β</button>
|
| 131 |
+
</div>
|
| 132 |
+
</div>
|
| 133 |
+
|
| 134 |
+
<!-- βββ CATALOG + FILTERS (combined) βββ -->
|
| 135 |
+
<section class="section tight" id="catalog-section">
|
| 136 |
+
<div class="section-head">
|
| 137 |
+
<div>
|
| 138 |
+
<div class="label">Catalog</div>
|
| 139 |
+
<h2>Browse all <span class="it">skills.</span></h2>
|
| 140 |
+
</div>
|
| 141 |
+
<div class="right">
|
| 142 |
+
<span class="sort-toggle" aria-label="Sort entries">
|
| 143 |
+
sort:
|
| 144 |
+
<a id="sort-index" class="on" tabindex="0" role="button">index</a> |
|
| 145 |
+
<a id="sort-recent" tabindex="0" role="button">recent</a>
|
| 146 |
+
</span><br/>
|
| 147 |
+
13 ecosystems Β· 9 categories<br/>
|
| 148 |
+
click any card to open
|
| 149 |
+
</div>
|
| 150 |
+
</div>
|
| 151 |
+
|
| 152 |
+
<!-- ββ Filters ββ -->
|
| 153 |
+
<div class="filters" id="filters-section">
|
| 154 |
+
<!-- search -->
|
| 155 |
+
<div class="search-wrap">
|
| 156 |
+
<span class="lbl">Q</span>
|
| 157 |
+
<input id="q" type="search" placeholder="search names, descriptions, triggersβ¦" aria-label="Search skills" />
|
| 158 |
+
<span class="count"><b id="count">226</b> of <b id="total-count">226</b> skills</span>
|
| 159 |
+
</div>
|
| 160 |
+
|
| 161 |
+
<!-- quick presets -->
|
| 162 |
+
<div class="filter-row preset-row" role="group" aria-label="Quick filter presets">
|
| 163 |
+
<span class="lbl">Quick</span>
|
| 164 |
+
<button class="preset-btn" data-preset="claude-code" aria-label="Show Claude Code skills only">Claude Code</button>
|
| 165 |
+
<button class="preset-btn" data-preset="agentic" aria-label="Show Agentic category only">Agentic</button>
|
| 166 |
+
<button class="preset-btn" data-preset="stable" aria-label="Show Stable skills only">Stable only</button>
|
| 167 |
+
<button class="preset-btn" data-preset="new" aria-label="Show newly added skills">New additions β¦</button>
|
| 168 |
+
<button class="preset-btn preset-clear" data-preset="clear" aria-label="Clear all filters">Clear all βΊ</button>
|
| 169 |
+
</div>
|
| 170 |
+
|
| 171 |
+
<!-- ecosystem chips -->
|
| 172 |
+
<div class="filter-row" role="group" aria-label="Filter by ecosystem">
|
| 173 |
+
<span class="lbl">Ecosystem</span>
|
| 174 |
+
<div id="eco-chips" class="filter-row" style="gap:8px"></div>
|
| 175 |
+
</div>
|
| 176 |
+
|
| 177 |
+
<!-- category chips -->
|
| 178 |
+
<div class="filter-row" role="group" aria-label="Filter by category">
|
| 179 |
+
<span class="lbl">Category</span>
|
| 180 |
+
<div id="cat-chips" class="filter-row" style="gap:8px"></div>
|
| 181 |
+
</div>
|
| 182 |
+
|
| 183 |
+
<!-- status chips -->
|
| 184 |
+
<div class="filter-row" role="group" aria-label="Filter by status">
|
| 185 |
+
<span class="lbl">Status</span>
|
| 186 |
+
<div id="status-chips" class="filter-row" style="gap:8px"></div>
|
| 187 |
+
<button class="chip" id="reset" style="margin-left:auto" aria-label="Reset all filters">Reset βΊ</button>
|
| 188 |
+
</div>
|
| 189 |
+
</div>
|
| 190 |
+
<div id="active-filters" class="active-filters" aria-live="polite"></div>
|
| 191 |
+
|
| 192 |
+
<!-- ββ Ecosystem strip ββ -->
|
| 193 |
+
<div id="eco-strip" class="eco-strip" aria-label="Jump to an ecosystem"></div>
|
| 194 |
+
|
| 195 |
+
<!-- ββ Grid toolbar ββ -->
|
| 196 |
+
<div class="grid-toolbar" id="grid-toolbar">
|
| 197 |
+
<button id="surprise-btn" class="chip" aria-label="Open a random skill">Surprise me β</button>
|
| 198 |
+
<button id="add-skill-btn" class="chip" aria-label="Add a new skill">Add skill +</button>
|
| 199 |
+
<span class="spacer"></span>
|
| 200 |
+
<button id="fav-filter-btn" class="chip" aria-pressed="false" aria-label="Show saved skills only">Saved <span id="fav-count" class="badge"></span></button>
|
| 201 |
+
<button id="export-btn" class="chip" aria-label="Export visible skills as JSON">Export JSON β</button>
|
| 202 |
+
</div>
|
| 203 |
+
|
| 204 |
+
<div id="grid" class="grid" aria-live="polite" style="border-top:0"></div>
|
| 205 |
+
</section>
|
| 206 |
+
|
| 207 |
+
<!-- βββ CAPABILITY MATRIX βββ -->
|
| 208 |
+
<section class="section" id="matrix-section">
|
| 209 |
+
<div class="section-head">
|
| 210 |
+
<div>
|
| 211 |
+
<div class="label">Compare</div>
|
| 212 |
+
<h2>Capability <span class="it">matrix.</span></h2>
|
| 213 |
+
</div>
|
| 214 |
+
<div class="right">
|
| 215 |
+
<span id="matrix-count">36</span> capabilities<br/>
|
| 216 |
+
<span id="matrix-ecosystem-count">13</span> ecosystems<br/>
|
| 217 |
+
scroll horizontally to compare
|
| 218 |
+
</div>
|
| 219 |
+
</div>
|
| 220 |
+
|
| 221 |
+
<div class="matrix-wrap" role="region" aria-label="Capability comparison table, horizontally scrollable" tabindex="0">
|
| 222 |
+
<table class="matrix" id="matrix">
|
| 223 |
+
<caption><b>Comparison.</b> Side-by-side capability coverage across every catalogued ecosystem. Cells are coded β supported Β· β not supported Β· partial (limited or via third party).</caption>
|
| 224 |
+
</table>
|
| 225 |
+
</div>
|
| 226 |
+
</section>
|
| 227 |
+
|
| 228 |
+
<!-- βββ CONTRIBUTE BANNER βββ -->
|
| 229 |
+
<section class="section tight" id="contribute-section">
|
| 230 |
+
<div class="section-head">
|
| 231 |
+
<div>
|
| 232 |
+
<div class="label">Contribute</div>
|
| 233 |
+
<h2>Missing a <span class="it">skill?</span></h2>
|
| 234 |
+
</div>
|
| 235 |
+
<div class="right">
|
| 236 |
+
Open a GitHub issue<br/>
|
| 237 |
+
reviewed within days<br/>
|
| 238 |
+
added to the registry
|
| 239 |
+
</div>
|
| 240 |
+
</div>
|
| 241 |
+
<div class="contribute-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:0;border-top:1px solid var(--rule)">
|
| 242 |
+
<a href="https://github.com/kishormorol/SkillsAllYouNeed/issues/new?template=submit-capability.yml"
|
| 243 |
+
target="_blank" rel="noopener"
|
| 244 |
+
style="display:flex;flex-direction:column;padding:32px 28px;border-right:1px solid var(--rule-soft);text-decoration:none;transition:background .14s ease;"
|
| 245 |
+
onmouseover="this.style.background='var(--paper-2)'" onmouseout="this.style.background=''">
|
| 246 |
+
<span style="font-family:var(--serif-display);font-size:clamp(28px,3vw,40px);line-height:1;margin-bottom:10px;">Submit a <em style="color:var(--accent)">capability</em></span>
|
| 247 |
+
<span style="font-family:var(--serif-body);font-size:16px;color:var(--ink-2);line-height:1.45;max-width:40ch;">Know a firstβparty skill we're missing? Fill in the structured form β name, ecosystem, trigger, how-to, example, source β and we'll add it.</span>
|
| 248 |
+
<span style="font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--accent);margin-top:20px;">β Open submission form</span>
|
| 249 |
+
</a>
|
| 250 |
+
<a href="https://github.com/kishormorol/SkillsAllYouNeed/issues/new?template=report-correction.yml"
|
| 251 |
+
target="_blank" rel="noopener"
|
| 252 |
+
style="display:flex;flex-direction:column;padding:32px 28px;text-decoration:none;transition:background .14s ease;"
|
| 253 |
+
onmouseover="this.style.background='var(--paper-2)'" onmouseout="this.style.background=''">
|
| 254 |
+
<span style="font-family:var(--serif-display);font-size:clamp(28px,3vw,40px);line-height:1;margin-bottom:10px;">Report a <em style="color:var(--accent)">correction</em></span>
|
| 255 |
+
<span style="font-family:var(--serif-body);font-size:16px;color:var(--ink-2);line-height:1.45;max-width:40ch;">Spotted an inaccuracy, a broken link, or a status that's changed? Flag it with the skill ID and what it should say.</span>
|
| 256 |
+
<span style="font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--accent);margin-top:20px;">β Open correction form</span>
|
| 257 |
+
</a>
|
| 258 |
+
</div>
|
| 259 |
+
</section>
|
| 260 |
+
|
| 261 |
+
<!-- βββ COLOPHON βββ -->
|
| 262 |
+
<footer class="colophon">
|
| 263 |
+
<div>
|
| 264 |
+
<h5>About Β· v2.0</h5>
|
| 265 |
+
<p>An open registry of usable AI skill definitions β Claude Code .md skills, CLAUDE.md templates, Claude.ai skill uploads, ChatGPT custom instructions, and more. Composed in plain HTML & CSS without a framework. <em>v1.x:</em> capability directory with filters, deepβlinking, keyboard shortcuts, favorites, Export JSON. <em>v2.0:</em> redesigned as a skills marketplace; removed academic framing.</p>
|
| 266 |
+
</div>
|
| 267 |
+
<div>
|
| 268 |
+
<h5>Contribute</h5>
|
| 269 |
+
<ul>
|
| 270 |
+
<li><a href="https://github.com/kishormorol/SkillsAllYouNeed/issues/new?template=submit-capability.yml" target="_blank" rel="noopener">β Submit a skill</a></li>
|
| 271 |
+
<li><a href="https://github.com/kishormorol/SkillsAllYouNeed/issues/new?template=report-correction.yml" target="_blank" rel="noopener">β Report a correction</a></li>
|
| 272 |
+
<li><a href="https://github.com/kishormorol/SkillsAllYouNeed/commits/main" target="_blank" rel="noopener">β View changelog</a></li>
|
| 273 |
+
<li><a href="#" id="export-corpus-link">β Download JSON</a></li>
|
| 274 |
+
</ul>
|
| 275 |
+
</div>
|
| 276 |
+
<div>
|
| 277 |
+
<h5>Maintainer</h5>
|
| 278 |
+
<p>Curated & maintained by <em>Kishor Morol</em>. Contributions welcome β open an issue or PR on GitHub.</p>
|
| 279 |
+
<p style="margin-top:10px"><a href="https://github.com/kishormorol/SkillsAllYouNeed" target="_blank" rel="noopener" style="border-bottom:1px solid var(--rule)">github.com/kishormorol/SkillsAllYouNeed</a></p>
|
| 280 |
+
</div>
|
| 281 |
+
|
| 282 |
+
<div class="end">
|
| 283 |
+
<span>Β© 2026 Β· SkillsAllYouNeed Β· CC BY 4.0</span>
|
| 284 |
+
<span>skills Β· 13 ecosystems Β· 9 categories</span>
|
| 285 |
+
<span>kishormorol.github.io/SkillsAllYouNeed</span>
|
| 286 |
+
</div>
|
| 287 |
+
</footer>
|
| 288 |
+
|
| 289 |
+
</div>
|
| 290 |
+
|
| 291 |
+
<!-- βββ HINT + SHORTCUTS MODAL βββ -->
|
| 292 |
+
<button class="hint-key" id="hint-key" aria-label="Show keyboard shortcuts"><kbd>?</kbd>shortcuts</button>
|
| 293 |
+
<button class="scroll-top" id="scroll-top" aria-label="Scroll to top">β top</button>
|
| 294 |
+
<aside class="shortcuts" id="shortcuts" role="dialog" aria-label="Keyboard shortcuts">
|
| 295 |
+
<button class="closeFn" id="closeFn" aria-label="Dismiss shortcuts">β</button>
|
| 296 |
+
<h6>Footnote</h6>
|
| 297 |
+
<p class="ftitle">Keyboard shortcuts.</p>
|
| 298 |
+
<dl>
|
| 299 |
+
<dt>/</dt><dd>focus the search field</dd>
|
| 300 |
+
<dt>?</dt><dd>toggle this footnote</dd>
|
| 301 |
+
<dt>Esc</dt><dd>close any open sheet or this card</dd>
|
| 302 |
+
<dt>Enter</dt><dd>open the focused skill card</dd>
|
| 303 |
+
<dt>ΒΆ</dt><dd>copy a deep link to a skill</dd>
|
| 304 |
+
<dt>j / k</dt><dd>navigate forward / backward through cards</dd>
|
| 305 |
+
<dt>β β</dt><dd>previous / next skill inside an open sheet</dd>
|
| 306 |
+
<dt>f</dt><dd>toggle favorite on focused card or open sheet</dd>
|
| 307 |
+
<dt>r</dt><dd>open a random skill from current results</dd>
|
| 308 |
+
</dl>
|
| 309 |
+
</aside>
|
| 310 |
+
|
| 311 |
+
<!-- βββ ADD SKILL SCRIM βββ -->
|
| 312 |
+
<div class="add-scrim" id="add-scrim" role="dialog" aria-modal="true" aria-label="Add a new skill">
|
| 313 |
+
<div class="add-sheet">
|
| 314 |
+
<button class="close" id="add-close-btn" aria-label="Close" style="position:absolute;top:18px;right:18px;font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.12em;border:1px solid var(--rule);padding:6px 10px;background:none;cursor:pointer;">Close β</button>
|
| 315 |
+
<h3>Add a <span class="it">skill.</span></h3>
|
| 316 |
+
<p class="form-sub">Saves to this browser Β· survives refreshes Β· export JSON to back up</p>
|
| 317 |
+
<form id="add-skill-form" novalidate>
|
| 318 |
+
<div class="form-row">
|
| 319 |
+
<div class="form-group">
|
| 320 |
+
<label for="f-name">Name *</label>
|
| 321 |
+
<input id="f-name" type="text" placeholder="e.g. Smart Notes" autocomplete="off" />
|
| 322 |
+
</div>
|
| 323 |
+
<div class="form-group">
|
| 324 |
+
<label for="f-ecosystem">Ecosystem *</label>
|
| 325 |
+
<select id="f-ecosystem">
|
| 326 |
+
<option value="">β select β</option>
|
| 327 |
+
<option>Claude</option>
|
| 328 |
+
<option>Claude Code</option>
|
| 329 |
+
<option>ChatGPT</option>
|
| 330 |
+
<option>Codex</option>
|
| 331 |
+
<option>OpenCode</option>
|
| 332 |
+
<option>Cursor</option>
|
| 333 |
+
<option>Gemini</option>
|
| 334 |
+
<option>Perplexity</option>
|
| 335 |
+
<option>Microsoft 365 Copilot</option>
|
| 336 |
+
<option>GitHub Copilot</option>
|
| 337 |
+
<option>Antigravity</option>
|
| 338 |
+
<option>Kiro</option>
|
| 339 |
+
<option>Pi</option>
|
| 340 |
+
</select>
|
| 341 |
+
</div>
|
| 342 |
+
</div>
|
| 343 |
+
<div class="form-row">
|
| 344 |
+
<div class="form-group">
|
| 345 |
+
<label for="f-category">Category *</label>
|
| 346 |
+
<select id="f-category">
|
| 347 |
+
<option value="">β select β</option>
|
| 348 |
+
<option>Document</option>
|
| 349 |
+
<option>Code</option>
|
| 350 |
+
<option>Web</option>
|
| 351 |
+
<option>Data</option>
|
| 352 |
+
<option>Memory</option>
|
| 353 |
+
<option>Integration</option>
|
| 354 |
+
<option>Visual</option>
|
| 355 |
+
<option>Agentic</option>
|
| 356 |
+
<option>API</option>
|
| 357 |
+
</select>
|
| 358 |
+
</div>
|
| 359 |
+
<div class="form-group">
|
| 360 |
+
<label for="f-status">Status *</label>
|
| 361 |
+
<select id="f-status">
|
| 362 |
+
<option value="">β select β</option>
|
| 363 |
+
<option>Stable</option>
|
| 364 |
+
<option>Beta</option>
|
| 365 |
+
<option>Deprecated</option>
|
| 366 |
+
</select>
|
| 367 |
+
</div>
|
| 368 |
+
</div>
|
| 369 |
+
<div class="form-row full">
|
| 370 |
+
<div class="form-group">
|
| 371 |
+
<label for="f-desc">Description *</label>
|
| 372 |
+
<textarea id="f-desc" rows="2" placeholder="What this skill does in one or two sentences."></textarea>
|
| 373 |
+
</div>
|
| 374 |
+
</div>
|
| 375 |
+
<div class="form-row full">
|
| 376 |
+
<div class="form-group">
|
| 377 |
+
<label for="f-trigger">Trigger phrase *</label>
|
| 378 |
+
<input id="f-trigger" type="text" placeholder='"Phrase that triggers it" Β· "alternate phrasing"' autocomplete="off" />
|
| 379 |
+
</div>
|
| 380 |
+
</div>
|
| 381 |
+
<div class="form-row full">
|
| 382 |
+
<div class="form-group">
|
| 383 |
+
<label for="f-howto">How to use *</label>
|
| 384 |
+
<input id="f-howto" type="text" placeholder="e.g. Settings β Connectors β enable, or `npm install -g package`" autocomplete="off" />
|
| 385 |
+
</div>
|
| 386 |
+
</div>
|
| 387 |
+
<div class="form-row full">
|
| 388 |
+
<div class="form-group">
|
| 389 |
+
<label for="f-example">Worked example *</label>
|
| 390 |
+
<textarea id="f-example" rows="2" placeholder="A concrete real-world scenario showing the skill in action."></textarea>
|
| 391 |
+
</div>
|
| 392 |
+
</div>
|
| 393 |
+
<div class="form-row full">
|
| 394 |
+
<div class="form-group">
|
| 395 |
+
<label for="f-source">Source URL</label>
|
| 396 |
+
<input id="f-source" type="url" placeholder="https://docs.example.com/this-skill" />
|
| 397 |
+
<span class="id-preview" id="id-preview">id: <b>β</b></span>
|
| 398 |
+
</div>
|
| 399 |
+
</div>
|
| 400 |
+
<div class="form-actions">
|
| 401 |
+
<button type="submit" class="btn-primary">Add to catalog β</button>
|
| 402 |
+
<button type="button" class="btn-ghost" id="add-cancel-btn">Cancel</button>
|
| 403 |
+
</div>
|
| 404 |
+
</form>
|
| 405 |
+
</div>
|
| 406 |
+
</div>
|
| 407 |
+
|
| 408 |
+
<!-- βββ TOAST βββ -->
|
| 409 |
+
<div class="toast" id="toast" role="status" aria-live="polite">link copied</div>
|
| 410 |
+
|
| 411 |
+
<!-- βββ DETAIL SCRIM βββ -->
|
| 412 |
+
<div class="scrim" id="scrim" role="dialog" aria-modal="true" aria-labelledby="sheet-title">
|
| 413 |
+
<div class="sheet" id="sheet"></div>
|
| 414 |
+
</div>
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
<script src="data.js"></script>
|
| 418 |
+
<script src="scripts.js"></script>
|
| 419 |
+
</body>
|
| 420 |
</html>
|
manifest.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "SkillsAllYouNeed for LLMs",
|
| 3 |
+
"short_name": "SAYN",
|
| 4 |
+
"description": "The open registry of AI skills β ready-to-use skill definitions for Claude, Claude Code, ChatGPT, Codex, OpenCode, Cursor, Gemini, Perplexity, Microsoft 365 Copilot, GitHub Copilot, Antigravity, Kiro, and Pi.",
|
| 5 |
+
"start_url": "/SkillsAllYouNeed/",
|
| 6 |
+
"scope": "/SkillsAllYouNeed/",
|
| 7 |
+
"display": "standalone",
|
| 8 |
+
"orientation": "any",
|
| 9 |
+
"background_color": "#F2EFE6",
|
| 10 |
+
"theme_color": "#15130E",
|
| 11 |
+
"icons": [
|
| 12 |
+
{
|
| 13 |
+
"src": "favicon.svg",
|
| 14 |
+
"sizes": "any",
|
| 15 |
+
"type": "image/svg+xml",
|
| 16 |
+
"purpose": "any maskable"
|
| 17 |
+
}
|
| 18 |
+
],
|
| 19 |
+
"categories": ["productivity", "education", "developer tools"]
|
| 20 |
+
}
|
scripts.js
ADDED
|
@@ -0,0 +1,858 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const $ = (sel,root=document) => root.querySelector(sel);
|
| 2 |
+
const $$ = (sel,root=document) => Array.from(root.querySelectorAll(sel));
|
| 3 |
+
|
| 4 |
+
/* βββββ Smooth scroll with ease-in-out βββββ */
|
| 5 |
+
function smoothScrollTo(el, offset = 0) {
|
| 6 |
+
const start = window.scrollY;
|
| 7 |
+
const end = el.getBoundingClientRect().top + start + offset;
|
| 8 |
+
const duration = 400;
|
| 9 |
+
const startTime = performance.now();
|
| 10 |
+
function step(now) {
|
| 11 |
+
const elapsed = (now - startTime) / duration;
|
| 12 |
+
const t = Math.min(elapsed, 1);
|
| 13 |
+
const ease = t < .5 ? 2*t*t : -1+(4-2*t)*t; // easeInOutQuad
|
| 14 |
+
window.scrollTo(0, start + (end - start) * ease);
|
| 15 |
+
if (t < 1) requestAnimationFrame(step);
|
| 16 |
+
}
|
| 17 |
+
requestAnimationFrame(step);
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
/* βββββ Build chips βββββ */
|
| 21 |
+
function buildChips(){
|
| 22 |
+
const ecoBox = $("#eco-chips"); ecoBox.innerHTML = "";
|
| 23 |
+
ECOSYSTEMS.forEach(e=>{
|
| 24 |
+
const cnt = SKILLS.filter(x=>x.ecosystem===e).length;
|
| 25 |
+
const b = document.createElement("button");
|
| 26 |
+
b.className = "chip"; b.setAttribute("aria-pressed","false");
|
| 27 |
+
b.dataset.eco = e; b.dataset.filterVal = e;
|
| 28 |
+
b.innerHTML = `<span class="glyph-wrap">${uniqueSvg(GLYPHS[e])}<span>${e}</span></span><span class="badge">${cnt}</span>`;
|
| 29 |
+
b.addEventListener("click", ()=>toggle(state.ecosystems,e,b));
|
| 30 |
+
ecoBox.appendChild(b);
|
| 31 |
+
});
|
| 32 |
+
|
| 33 |
+
const catBox = $("#cat-chips"); catBox.innerHTML = "";
|
| 34 |
+
CATEGORIES.forEach(c=>{
|
| 35 |
+
const cnt = SKILLS.filter(x=>x.category===c).length;
|
| 36 |
+
const b = document.createElement("button");
|
| 37 |
+
b.className = "chip"; b.setAttribute("aria-pressed","false");
|
| 38 |
+
b.dataset.filterVal = c;
|
| 39 |
+
b.innerHTML = `${c}<span class="badge">${cnt}</span>`;
|
| 40 |
+
b.addEventListener("click", ()=>toggle(state.categories,c,b));
|
| 41 |
+
catBox.appendChild(b);
|
| 42 |
+
});
|
| 43 |
+
|
| 44 |
+
const stBox = $("#status-chips"); stBox.innerHTML = "";
|
| 45 |
+
STATUSES.forEach(s=>{
|
| 46 |
+
const cnt = SKILLS.filter(x=>x.status===s).length;
|
| 47 |
+
const b = document.createElement("button");
|
| 48 |
+
b.className = "chip"; b.setAttribute("aria-pressed","false");
|
| 49 |
+
b.dataset.filterVal = s;
|
| 50 |
+
b.innerHTML = `${s}<span class="badge">${cnt}</span>`;
|
| 51 |
+
b.addEventListener("click", ()=>toggle(state.statuses,s,b));
|
| 52 |
+
stBox.appendChild(b);
|
| 53 |
+
});
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
function toggle(set, value, el){
|
| 57 |
+
if(set.has(value)){ set.delete(value); el.setAttribute("aria-pressed","false"); }
|
| 58 |
+
else{ set.add(value); el.setAttribute("aria-pressed","true"); }
|
| 59 |
+
render();
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/* βββββ Grid render with asymmetric spans βββββ */
|
| 63 |
+
const SPAN_PATTERN = [4, 4, 4, 6, 6, 4, 4, 4, 8, 4, 4, 4, 4, 6, 6];
|
| 64 |
+
function spanFor(i){ return SPAN_PATTERN[i % SPAN_PATTERN.length]; }
|
| 65 |
+
|
| 66 |
+
function matchesFilters(s){
|
| 67 |
+
if(state.favOnly && !favorites.has(s.id)) return false;
|
| 68 |
+
if(state.newOnly && !NEW_IDS.has(s.id)) return false;
|
| 69 |
+
if(state.ecosystems.size && !state.ecosystems.has(s.ecosystem)) return false;
|
| 70 |
+
if(state.categories.size && !state.categories.has(s.category)) return false;
|
| 71 |
+
if(state.statuses.size && !state.statuses.has(s.status)) return false;
|
| 72 |
+
if(state.query){
|
| 73 |
+
const q = state.query.toLowerCase();
|
| 74 |
+
const blob = (s.name+" "+s.description+" "+s.trigger+" "+s.example+" "+s.category+" "+s.ecosystem+" "+(s.howto||HOWTO[s.id]||"")).toLowerCase();
|
| 75 |
+
if(!blob.includes(q)) return false;
|
| 76 |
+
}
|
| 77 |
+
return true;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
function render(){
|
| 81 |
+
const grid = $("#grid");
|
| 82 |
+
grid.innerHTML = "";
|
| 83 |
+
let filtered = SKILLS.filter(matchesFilters);
|
| 84 |
+
|
| 85 |
+
// sort
|
| 86 |
+
if(state.sort === "recent"){
|
| 87 |
+
const rank = s => (s.status === "Beta" ? 0 : (s.status === "Stable" ? 1 : 2));
|
| 88 |
+
filtered = filtered.slice().sort((a,b)=> rank(a) - rank(b));
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
lastFiltered = filtered;
|
| 92 |
+
focusedCardIdx = -1;
|
| 93 |
+
|
| 94 |
+
$("#count").textContent = filtered.length;
|
| 95 |
+
const totalEl = $("#total-count"); if(totalEl) totalEl.textContent = SKILLS.length;
|
| 96 |
+
/* Only update the hero counter after the first load β boot uses animateCount() instead */
|
| 97 |
+
const heroCount = $("#hero-skill-count");
|
| 98 |
+
if(heroCount && render._firstDone) heroCount.textContent = SKILLS.length;
|
| 99 |
+
|
| 100 |
+
renderActiveFilters();
|
| 101 |
+
|
| 102 |
+
if(filtered.length === 0){
|
| 103 |
+
const qLabel = state.query ? `"${escapeHTML(state.query)}"` : "that combination";
|
| 104 |
+
grid.innerHTML = `<div class="no-results">Nothing matched ${qLabel}.<small>Try broader terms Β· or fewer filters</small><button class="nr-reset" onclick="document.getElementById('reset').click()">Reset all filters βΊ</button></div>`;
|
| 105 |
+
return;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
filtered.forEach((s, i)=>{
|
| 109 |
+
const span = spanFor(i);
|
| 110 |
+
const featured = (span >= 8) || (i === 0);
|
| 111 |
+
const isSaved = favorites.has(s.id);
|
| 112 |
+
const card = document.createElement("article");
|
| 113 |
+
card.className = `card ${span===6?"span-6":""} ${span===8?"span-8":""} ${span===12?"span-12":""} ${featured?"featured":""}`;
|
| 114 |
+
card.tabIndex = 0;
|
| 115 |
+
card.setAttribute("role","button");
|
| 116 |
+
card.setAttribute("aria-label", `${s.name} β ${s.ecosystem} β open details`);
|
| 117 |
+
card.id = `skill-${s.id}`;
|
| 118 |
+
card.dataset.id = s.id;
|
| 119 |
+
card.dataset.eco = s.ecosystem;
|
| 120 |
+
card.dataset.trigger = s.trigger;
|
| 121 |
+
card.dataset.example = s.example;
|
| 122 |
+
card.dataset.source = s.source;
|
| 123 |
+
|
| 124 |
+
const nameHTML = s.name.replace(/(\S+)$/, '<span class="it">$1</span>');
|
| 125 |
+
const isNew = NEW_IDS.has(s.id);
|
| 126 |
+
|
| 127 |
+
card.innerHTML = `
|
| 128 |
+
<div class="top">
|
| 129 |
+
<div class="glyph">${uniqueSvg(GLYPHS[s.ecosystem])}</div>
|
| 130 |
+
<div class="id-wrap">
|
| 131 |
+
<div class="id">${s.id}${s._custom?'<span class="custom-badge">custom</span>':''}${isNew?'<span class="new-badge">new</span>':''}</div>
|
| 132 |
+
<button class="anchor" title="Copy deep link" aria-label="Copy deep link to ${s.name}" data-copy="${s.id}">ΒΆ</button>
|
| 133 |
+
</div>
|
| 134 |
+
<div class="meta-top" style="flex:1">
|
| 135 |
+
<span class="eco-label">${s.ecosystem}</span>
|
| 136 |
+
<span>β ${String(SKILLS.indexOf(s)+1).padStart(3,'0')} / ${String(SKILLS.length).padStart(3,'0')}</span>
|
| 137 |
+
</div>
|
| 138 |
+
</div>
|
| 139 |
+
<h3 class="name">${nameHTML}</h3>
|
| 140 |
+
<p class="desc">${codeBacktick(escapeHTML(s.description))}</p>
|
| 141 |
+
<p class="trigger" title="Click to copy trigger phrase">${codeBacktick(escapeHTML(s.trigger))}<span class="copy-hint" aria-hidden="true">β copy</span></p>
|
| 142 |
+
<div class="bottom">
|
| 143 |
+
<span class="cat" data-cat="${s.category}">${s.category}</span>
|
| 144 |
+
<span class="status" data-status="${s.status}"><span class="status-dot"></span>${s.status}</span>
|
| 145 |
+
<button class="fav-btn${isSaved?" saved":""}" data-fav-id="${s.id}"
|
| 146 |
+
title="${isSaved?"Remove from saved":"Save this skill"}"
|
| 147 |
+
aria-label="${isSaved?"Remove from saved":"Save"}">${isSaved?"β₯":"β‘"}</button>
|
| 148 |
+
</div>
|
| 149 |
+
`;
|
| 150 |
+
card.addEventListener("click", (e)=>{
|
| 151 |
+
if(e.target.closest(".anchor") || e.target.closest(".fav-btn")) return;
|
| 152 |
+
openSheet(s);
|
| 153 |
+
});
|
| 154 |
+
card.addEventListener("keydown", e=>{
|
| 155 |
+
if((e.key==="Enter"||e.key===" ") && !e.target.classList.contains("anchor") && !e.target.classList.contains("fav-btn")){
|
| 156 |
+
e.preventDefault(); openSheet(s);
|
| 157 |
+
}
|
| 158 |
+
});
|
| 159 |
+
card.querySelector(".anchor").addEventListener("click", (e)=>{
|
| 160 |
+
e.stopPropagation(); copyDeepLink(s.id);
|
| 161 |
+
});
|
| 162 |
+
card.querySelector(".fav-btn").addEventListener("click", (e)=>{
|
| 163 |
+
e.stopPropagation();
|
| 164 |
+
const was = favorites.has(s.id);
|
| 165 |
+
was ? favorites.delete(s.id) : favorites.add(s.id);
|
| 166 |
+
saveFavs(); updateFavCount();
|
| 167 |
+
const btn = e.currentTarget;
|
| 168 |
+
btn.classList.toggle("saved", !was);
|
| 169 |
+
btn.textContent = !was ? "β₯" : "β‘";
|
| 170 |
+
btn.title = !was ? "Remove from saved" : "Save this skill";
|
| 171 |
+
if(state.favOnly) render();
|
| 172 |
+
});
|
| 173 |
+
card.querySelector(".trigger").addEventListener("click", (e)=>{
|
| 174 |
+
e.stopPropagation();
|
| 175 |
+
navigator.clipboard && navigator.clipboard.writeText(s.trigger).catch(()=>{});
|
| 176 |
+
showToast("trigger copied");
|
| 177 |
+
});
|
| 178 |
+
grid.appendChild(card);
|
| 179 |
+
});
|
| 180 |
+
|
| 181 |
+
// staggered fade-in β fast stagger on filter, gentle on first load
|
| 182 |
+
requestAnimationFrame(()=>{
|
| 183 |
+
const step = render._firstDone ? 8 : 18;
|
| 184 |
+
$$("#grid .card").forEach((c,i)=>{
|
| 185 |
+
setTimeout(()=>c.classList.add("in"), i*step);
|
| 186 |
+
});
|
| 187 |
+
render._firstDone = true;
|
| 188 |
+
});
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
/* βββββ Sheet βββββ */
|
| 192 |
+
function openSheet(s, opts){
|
| 193 |
+
opts = opts || {};
|
| 194 |
+
const sheet = $("#sheet");
|
| 195 |
+
const nameHTML = s.name.replace(/(\S+)$/, '<span class="it">$1</span>');
|
| 196 |
+
currentSheetIdx = lastFiltered.findIndex(x => x.id === s.id);
|
| 197 |
+
const hasPrev = currentSheetIdx > 0;
|
| 198 |
+
const hasNext = currentSheetIdx < lastFiltered.length - 1;
|
| 199 |
+
const isSaved = favorites.has(s.id);
|
| 200 |
+
|
| 201 |
+
sheet.innerHTML = `
|
| 202 |
+
<button class="close" aria-label="Close" id="closeBtn">Close β</button>
|
| 203 |
+
<div class="sheet-top">
|
| 204 |
+
<div class="glyph-lg">${uniqueSvg(GLYPHS[s.ecosystem])}</div>
|
| 205 |
+
<div class="top-meta" style="flex:1">
|
| 206 |
+
<div><b>${s.ecosystem}</b> Β· ${s.category} Β· ${s.status}</div>
|
| 207 |
+
<div>id: ${s.id} Β· entry β ${String(SKILLS.indexOf(s)+1).padStart(3,'0')} of ${SKILLS.length} Β· <a href="#${s.id}" id="sheetCopy" style="color:var(--accent);border-bottom:1px solid var(--accent)">copy deep link</a></div>
|
| 208 |
+
</div>
|
| 209 |
+
</div>
|
| 210 |
+
<h3 id="sheet-title">${nameHTML}</h3>
|
| 211 |
+
<p class="lede">${codeBacktick(escapeHTML(s.description))}</p>
|
| 212 |
+
|
| 213 |
+
<h4>Trigger</h4>
|
| 214 |
+
<pre class="field">${splitTriggers(codeBacktick(escapeHTML(s.trigger)))}</pre>
|
| 215 |
+
|
| 216 |
+
<h4>How to use</h4>
|
| 217 |
+
<p class="field serif">${codeBacktick(escapeHTML(s.howto || HOWTO[s.id] || "See the source link below for setup instructions."))}</p>
|
| 218 |
+
|
| 219 |
+
<h4>Worked example</h4>
|
| 220 |
+
<p class="field serif">${codeBacktick(escapeHTML(s.example))}</p>
|
| 221 |
+
|
| 222 |
+
<h4>Source & citation</h4>
|
| 223 |
+
<a class="src" href="${escapeHTML(s.source)}" target="_blank" rel="noopener">${escapeHTML(s.source)}</a>
|
| 224 |
+
|
| 225 |
+
<div class="sheet-actions">
|
| 226 |
+
<button id="favSheetBtn" class="${isSaved?"is-saved":""}" aria-label="${isSaved?"Remove from saved":"Save this skill"}">${isSaved?"β₯ Saved":"β‘ Save"}</button>
|
| 227 |
+
<button id="shareBtn" aria-label="Share this skill">Share β</button>
|
| 228 |
+
<button id="copyTriggerBtn" aria-label="Copy trigger phrase">Copy trigger</button>
|
| 229 |
+
</div>
|
| 230 |
+
|
| 231 |
+
${(()=>{
|
| 232 |
+
const related = SKILLS.filter(r =>
|
| 233 |
+
r.id !== s.id && (
|
| 234 |
+
r.category === s.category ||
|
| 235 |
+
(r.ecosystem === s.ecosystem && r.id !== s.id)
|
| 236 |
+
)
|
| 237 |
+
).slice(0,4);
|
| 238 |
+
if(!related.length) return "";
|
| 239 |
+
return `<h4>Related skills</h4>
|
| 240 |
+
<div class="related-list">${
|
| 241 |
+
related.map(r => `<button class="related-chip" data-related-id="${r.id}">${r.name}</button>`).join("")
|
| 242 |
+
}</div>`;
|
| 243 |
+
})()}
|
| 244 |
+
|
| 245 |
+
<div class="sheet-nav">
|
| 246 |
+
<button id="prevSkill"${!hasPrev?" disabled":""} aria-label="Previous skill">β prev</button>
|
| 247 |
+
<span class="nav-pos">${currentSheetIdx+1} of ${lastFiltered.length}</span>
|
| 248 |
+
<button id="nextSkill"${!hasNext?" disabled":""} aria-label="Next skill">next β</button>
|
| 249 |
+
</div>
|
| 250 |
+
`;
|
| 251 |
+
|
| 252 |
+
$("#scrim").classList.add("open");
|
| 253 |
+
document.body.style.overflow = "hidden";
|
| 254 |
+
sheet.scrollTop = 0;
|
| 255 |
+
|
| 256 |
+
$("#closeBtn").addEventListener("click", closeSheet);
|
| 257 |
+
$("#sheetCopy").addEventListener("click", (e)=>{ e.preventDefault(); copyDeepLink(s.id); });
|
| 258 |
+
|
| 259 |
+
if(hasPrev) $("#prevSkill").addEventListener("click", ()=>openSheet(lastFiltered[currentSheetIdx-1]));
|
| 260 |
+
if(hasNext) $("#nextSkill").addEventListener("click", ()=>openSheet(lastFiltered[currentSheetIdx+1]));
|
| 261 |
+
|
| 262 |
+
$("#favSheetBtn").addEventListener("click", ()=>{
|
| 263 |
+
const was = favorites.has(s.id);
|
| 264 |
+
was ? favorites.delete(s.id) : favorites.add(s.id);
|
| 265 |
+
saveFavs(); updateFavCount();
|
| 266 |
+
const fb = $("#favSheetBtn");
|
| 267 |
+
fb.className = favorites.has(s.id) ? "is-saved" : "";
|
| 268 |
+
fb.textContent = favorites.has(s.id) ? "β₯ Saved" : "β‘ Save";
|
| 269 |
+
fb.setAttribute("aria-label", favorites.has(s.id) ? "Remove from saved" : "Save this skill");
|
| 270 |
+
const cardFav = document.querySelector(`[data-fav-id="${s.id}"]`);
|
| 271 |
+
if(cardFav){ cardFav.classList.toggle("saved", favorites.has(s.id)); cardFav.textContent = favorites.has(s.id)?"β₯":"β‘"; }
|
| 272 |
+
if(state.favOnly) render();
|
| 273 |
+
});
|
| 274 |
+
|
| 275 |
+
$("#shareBtn").addEventListener("click", ()=>{
|
| 276 |
+
const url = location.origin + location.pathname + location.search + "#" + s.id;
|
| 277 |
+
if(navigator.share){ navigator.share({title:`${s.name} β SkillsAllYouNeed`, url}).catch(()=>copyDeepLink(s.id)); }
|
| 278 |
+
else { copyDeepLink(s.id); }
|
| 279 |
+
});
|
| 280 |
+
|
| 281 |
+
$("#copyTriggerBtn").addEventListener("click", ()=>{
|
| 282 |
+
navigator.clipboard && navigator.clipboard.writeText(s.trigger).catch(()=>{});
|
| 283 |
+
showToast("trigger copied");
|
| 284 |
+
});
|
| 285 |
+
|
| 286 |
+
$$(".related-chip", sheet).forEach(btn => {
|
| 287 |
+
btn.addEventListener("click", ()=>{
|
| 288 |
+
const target = SKILLS.find(x=>x.id === btn.dataset.relatedId);
|
| 289 |
+
if(target) openSheet(target);
|
| 290 |
+
});
|
| 291 |
+
});
|
| 292 |
+
|
| 293 |
+
if(s._custom){
|
| 294 |
+
const delBtn = document.createElement("button");
|
| 295 |
+
delBtn.className = "is-delete"; delBtn.textContent = "Delete β";
|
| 296 |
+
delBtn.setAttribute("aria-label","Delete this custom skill");
|
| 297 |
+
delBtn.addEventListener("click", ()=>{
|
| 298 |
+
if(!confirm(`Delete "${s.name}"? This cannot be undone.`)) return;
|
| 299 |
+
const idx = SKILLS.findIndex(x=>x.id===s.id);
|
| 300 |
+
if(idx > -1) SKILLS.splice(idx, 1);
|
| 301 |
+
const remaining = JSON.parse(localStorage.getItem("skills-custom")||"[]").filter(x=>x.id!==s.id);
|
| 302 |
+
localStorage.setItem("skills-custom", JSON.stringify(remaining));
|
| 303 |
+
closeSheet(); render();
|
| 304 |
+
showToast(`"${s.name}" deleted`);
|
| 305 |
+
});
|
| 306 |
+
sheet.querySelector(".sheet-actions").appendChild(delBtn);
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
if(opts.pushHash !== false && location.hash !== "#"+s.id){
|
| 310 |
+
history.replaceState(null, "", "#"+s.id);
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
function closeSheet(){
|
| 314 |
+
$("#scrim").classList.remove("open");
|
| 315 |
+
document.body.style.overflow = "";
|
| 316 |
+
if(location.hash){ history.replaceState(null, "", location.pathname + location.search); }
|
| 317 |
+
}
|
| 318 |
+
$("#scrim").addEventListener("click", e=>{ if(e.target.id === "scrim") closeSheet(); });
|
| 319 |
+
|
| 320 |
+
/* βββββ Deep link / toast βββββ */
|
| 321 |
+
function copyDeepLink(id){
|
| 322 |
+
const url = location.origin + location.pathname + location.search + "#" + id;
|
| 323 |
+
const fallback = () => {
|
| 324 |
+
const ta = document.createElement("textarea");
|
| 325 |
+
ta.value = url; ta.style.position="fixed"; ta.style.left="-9999px";
|
| 326 |
+
document.body.appendChild(ta); ta.select();
|
| 327 |
+
try{ document.execCommand("copy"); }catch(_){}
|
| 328 |
+
document.body.removeChild(ta);
|
| 329 |
+
};
|
| 330 |
+
if(navigator.clipboard && navigator.clipboard.writeText){
|
| 331 |
+
navigator.clipboard.writeText(url).catch(fallback);
|
| 332 |
+
} else { fallback(); }
|
| 333 |
+
showToast("link copied Β· ΒΆ " + id);
|
| 334 |
+
}
|
| 335 |
+
let toastTimer;
|
| 336 |
+
function showToast(msg){
|
| 337 |
+
const t = $("#toast");
|
| 338 |
+
t.textContent = msg;
|
| 339 |
+
t.classList.add("show");
|
| 340 |
+
clearTimeout(toastTimer);
|
| 341 |
+
toastTimer = setTimeout(()=>t.classList.remove("show"), 1800);
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
/* βββββ Ecosystem deep-dive strip βββββ */
|
| 345 |
+
function buildEcoStrip(){
|
| 346 |
+
const wrap = $("#eco-strip");
|
| 347 |
+
wrap.innerHTML = "";
|
| 348 |
+
ECOSYSTEMS.forEach(eco => {
|
| 349 |
+
const count = SKILLS.filter(s => s.ecosystem === eco).length;
|
| 350 |
+
const cell = document.createElement("button");
|
| 351 |
+
cell.className = "eco-cell";
|
| 352 |
+
cell.dataset.eco = eco;
|
| 353 |
+
cell.setAttribute("aria-label", `Filter to ${eco} β ${count} entries`);
|
| 354 |
+
cell.innerHTML = `
|
| 355 |
+
<div class="eco-head">
|
| 356 |
+
<div class="eco-glyph">${uniqueSvg(GLYPHS[eco])}</div>
|
| 357 |
+
<div class="eco-tag"><b>${String(count).padStart(2,'0')}</b>entries</div>
|
| 358 |
+
</div>
|
| 359 |
+
<h4 class="eco-name">${eco.replace(/(\w+)$/, '<span class="it">$1</span>')}</h4>
|
| 360 |
+
<p class="eco-blurb">${ECO_BLURB[eco]}</p>
|
| 361 |
+
<div class="eco-link">β Jump to ${eco} entries</div>
|
| 362 |
+
`;
|
| 363 |
+
cell.addEventListener("click", ()=>{
|
| 364 |
+
// single-select this ecosystem
|
| 365 |
+
state.ecosystems.clear();
|
| 366 |
+
state.ecosystems.add(eco);
|
| 367 |
+
$$("#eco-chips .chip").forEach(c=>{
|
| 368 |
+
c.setAttribute("aria-pressed", c.dataset.eco === eco ? "true" : "false");
|
| 369 |
+
});
|
| 370 |
+
render();
|
| 371 |
+
smoothScrollTo($("#grid"), -20);
|
| 372 |
+
});
|
| 373 |
+
wrap.appendChild(cell);
|
| 374 |
+
});
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
/* βββββ Shortcuts modal βββββ */
|
| 378 |
+
function openShortcuts(){ $("#shortcuts").classList.add("open"); }
|
| 379 |
+
function closeShortcuts(){ $("#shortcuts").classList.remove("open"); }
|
| 380 |
+
$("#hint-key").addEventListener("click", ()=>{
|
| 381 |
+
const s = $("#shortcuts");
|
| 382 |
+
s.classList.toggle("open");
|
| 383 |
+
});
|
| 384 |
+
$("#closeFn").addEventListener("click", closeShortcuts);
|
| 385 |
+
|
| 386 |
+
/* βββββ Global keyboard shortcuts (unified) βββββ */
|
| 387 |
+
document.addEventListener("keydown", (e)=>{
|
| 388 |
+
const tag = (e.target && e.target.tagName || "").toLowerCase();
|
| 389 |
+
const typing = tag === "input" || tag === "textarea" || e.target.isContentEditable;
|
| 390 |
+
const sheetOpen = $("#scrim").classList.contains("open");
|
| 391 |
+
|
| 392 |
+
// Escape closes whatever is open
|
| 393 |
+
if(e.key === "Escape"){
|
| 394 |
+
if(sheetOpen) { closeSheet(); return; }
|
| 395 |
+
if(document.getElementById("add-scrim").classList.contains("open")){ closeAddSheet(); return; }
|
| 396 |
+
if($("#shortcuts").classList.contains("open")){ closeShortcuts(); return; }
|
| 397 |
+
return;
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
// Arrow navigation inside open sheet
|
| 401 |
+
if(sheetOpen){
|
| 402 |
+
if(e.key === "ArrowLeft" && currentSheetIdx > 0){
|
| 403 |
+
e.preventDefault(); openSheet(lastFiltered[currentSheetIdx-1]); return;
|
| 404 |
+
}
|
| 405 |
+
if(e.key === "ArrowRight" && currentSheetIdx < lastFiltered.length-1){
|
| 406 |
+
e.preventDefault(); openSheet(lastFiltered[currentSheetIdx+1]); return;
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
if(typing) return;
|
| 411 |
+
|
| 412 |
+
if(e.key === "/"){
|
| 413 |
+
e.preventDefault(); $("#q").focus(); $("#q").select();
|
| 414 |
+
} else if(e.key === "?" || (e.shiftKey && e.key === "/")){
|
| 415 |
+
e.preventDefault(); $("#shortcuts").classList.toggle("open");
|
| 416 |
+
} else if((e.key === "j" || e.key === "k") && !sheetOpen){
|
| 417 |
+
e.preventDefault();
|
| 418 |
+
const cards = $$("#grid .card");
|
| 419 |
+
if(!cards.length) return;
|
| 420 |
+
focusedCardIdx = e.key==="j"
|
| 421 |
+
? Math.min(focusedCardIdx+1, cards.length-1)
|
| 422 |
+
: Math.max(focusedCardIdx-1, 0);
|
| 423 |
+
cards[focusedCardIdx].focus();
|
| 424 |
+
cards[focusedCardIdx].scrollIntoView({block:"nearest", behavior:"smooth"});
|
| 425 |
+
} else if(e.key === "f"){
|
| 426 |
+
if(sheetOpen){
|
| 427 |
+
const fb = $("#favSheetBtn"); if(fb) fb.click();
|
| 428 |
+
} else {
|
| 429 |
+
const focused = document.activeElement;
|
| 430 |
+
if(focused && focused.classList.contains("card")){
|
| 431 |
+
const btn = focused.querySelector(".fav-btn"); if(btn) btn.click();
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
+
} else if(e.key === "r" && !sheetOpen){
|
| 435 |
+
if(lastFiltered.length) openSheet(lastFiltered[Math.floor(Math.random()*lastFiltered.length)]);
|
| 436 |
+
}
|
| 437 |
+
});
|
| 438 |
+
|
| 439 |
+
/* βββββ Sort toggle βββββ */
|
| 440 |
+
function setSort(mode){
|
| 441 |
+
state.sort = mode;
|
| 442 |
+
$("#sort-index").classList.toggle("on", mode === "index");
|
| 443 |
+
$("#sort-recent").classList.toggle("on", mode === "recent");
|
| 444 |
+
render();
|
| 445 |
+
}
|
| 446 |
+
$("#sort-index").addEventListener("click", ()=>setSort("index"));
|
| 447 |
+
$("#sort-recent").addEventListener("click", ()=>setSort("recent"));
|
| 448 |
+
["sort-index","sort-recent"].forEach(id=>{
|
| 449 |
+
$("#"+id).addEventListener("keydown", e=>{
|
| 450 |
+
if(e.key === "Enter" || e.key === " "){ e.preventDefault(); setSort(id==="sort-index"?"index":"recent"); }
|
| 451 |
+
});
|
| 452 |
+
});
|
| 453 |
+
|
| 454 |
+
/* βββββ Active filters bar βββββ */
|
| 455 |
+
function renderActiveFilters(){
|
| 456 |
+
const bar = $("#active-filters"); if(!bar) return;
|
| 457 |
+
const tags = [];
|
| 458 |
+
state.ecosystems.forEach(e => tags.push({type:"eco", val:e}));
|
| 459 |
+
state.categories.forEach(c => tags.push({type:"cat", val:c}));
|
| 460 |
+
state.statuses.forEach(s => tags.push({type:"stat", val:s}));
|
| 461 |
+
if(state.favOnly) tags.push({type:"fav", val:"Saved only"});
|
| 462 |
+
if(state.newOnly) tags.push({type:"newOnly", val:"New additions"});
|
| 463 |
+
if(state.query) tags.push({type:"q", val:`"${state.query}"`});
|
| 464 |
+
|
| 465 |
+
if(!tags.length){ bar.style.display="none"; return; }
|
| 466 |
+
bar.style.display = "flex";
|
| 467 |
+
bar.innerHTML = `<span class="af-label">Active:</span>` + tags.map(t=>
|
| 468 |
+
`<button class="active-filter-tag" data-type="${t.type}" data-val="${escapeHTML(t.val)}">${escapeHTML(t.val)} Γ</button>`
|
| 469 |
+
).join("");
|
| 470 |
+
|
| 471 |
+
$$(".active-filter-tag", bar).forEach(tag => {
|
| 472 |
+
tag.addEventListener("click", ()=>{
|
| 473 |
+
const {type, val} = tag.dataset;
|
| 474 |
+
if(type==="eco"){
|
| 475 |
+
state.ecosystems.delete(val);
|
| 476 |
+
$$(`#eco-chips .chip`).forEach(c=>{ if(c.dataset.filterVal===val) c.setAttribute("aria-pressed","false"); });
|
| 477 |
+
} else if(type==="cat"){
|
| 478 |
+
state.categories.delete(val);
|
| 479 |
+
$$(`#cat-chips .chip`).forEach(c=>{ if(c.dataset.filterVal===val) c.setAttribute("aria-pressed","false"); });
|
| 480 |
+
} else if(type==="stat"){
|
| 481 |
+
state.statuses.delete(val);
|
| 482 |
+
$$(`#status-chips .chip`).forEach(c=>{ if(c.dataset.filterVal===val) c.setAttribute("aria-pressed","false"); });
|
| 483 |
+
} else if(type==="fav"){
|
| 484 |
+
state.favOnly = false;
|
| 485 |
+
$("#fav-filter-btn")?.setAttribute("aria-pressed","false");
|
| 486 |
+
} else if(type==="newOnly"){
|
| 487 |
+
state.newOnly = false;
|
| 488 |
+
$$(".preset-btn").forEach(b=>{ if(b.dataset.preset==="new") b.classList.remove("active"); });
|
| 489 |
+
} else if(type==="q"){
|
| 490 |
+
state.query = ""; $("#q").value = "";
|
| 491 |
+
}
|
| 492 |
+
render();
|
| 493 |
+
});
|
| 494 |
+
});
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
/* βββββ Scroll-to-top βββββ */
|
| 498 |
+
window.addEventListener("scroll", ()=>{
|
| 499 |
+
const btn = $("#scroll-top");
|
| 500 |
+
if(btn) btn.classList.toggle("visible", window.scrollY > 500);
|
| 501 |
+
}, {passive:true});
|
| 502 |
+
$("#scroll-top").addEventListener("click", ()=>window.scrollTo({top:0, behavior:"smooth"}));
|
| 503 |
+
|
| 504 |
+
/* βββββ Grid toolbar βββββ */
|
| 505 |
+
$("#surprise-btn").addEventListener("click", ()=>{
|
| 506 |
+
if(!lastFiltered.length) return;
|
| 507 |
+
openSheet(lastFiltered[Math.floor(Math.random()*lastFiltered.length)]);
|
| 508 |
+
});
|
| 509 |
+
|
| 510 |
+
$("#fav-filter-btn").addEventListener("click", ()=>{
|
| 511 |
+
state.favOnly = !state.favOnly;
|
| 512 |
+
$("#fav-filter-btn").setAttribute("aria-pressed", state.favOnly?"true":"false");
|
| 513 |
+
render();
|
| 514 |
+
});
|
| 515 |
+
|
| 516 |
+
$("#export-btn").addEventListener("click", ()=>{
|
| 517 |
+
const data = lastFiltered.map(s=>{
|
| 518 |
+
const h = s.howto || HOWTO[s.id] || "";
|
| 519 |
+
return {id:s.id,name:s.name,ecosystem:s.ecosystem,category:s.category,status:s.status,description:s.description,trigger:s.trigger,howto:h,example:s.example,source:s.source};
|
| 520 |
+
});
|
| 521 |
+
const blob = new Blob([JSON.stringify(data,null,2)], {type:"application/json"});
|
| 522 |
+
const url = URL.createObjectURL(blob);
|
| 523 |
+
const a = Object.assign(document.createElement("a"), {href:url, download:`skills-${Date.now()}.json`});
|
| 524 |
+
document.body.appendChild(a); a.click(); document.body.removeChild(a);
|
| 525 |
+
URL.revokeObjectURL(url);
|
| 526 |
+
showToast(`exported ${data.length} entr${data.length===1?"y":"ies"}`);
|
| 527 |
+
});
|
| 528 |
+
|
| 529 |
+
/* βββββ Hash routing βββββ */
|
| 530 |
+
function openFromHash(){
|
| 531 |
+
const id = location.hash.replace("#","");
|
| 532 |
+
if(!id) return;
|
| 533 |
+
const s = SKILLS.find(x => x.id === id);
|
| 534 |
+
if(s){
|
| 535 |
+
openSheet(s, {pushHash:false});
|
| 536 |
+
const card = document.getElementById("skill-"+id);
|
| 537 |
+
if(card){ card.classList.add("hashed"); setTimeout(()=>card.classList.remove("hashed"), 2400); }
|
| 538 |
+
}
|
| 539 |
+
}
|
| 540 |
+
window.addEventListener("hashchange", openFromHash);
|
| 541 |
+
|
| 542 |
+
/* βββββ Matrix βββββ */
|
| 543 |
+
function buildMatrix(){
|
| 544 |
+
const t = $("#matrix");
|
| 545 |
+
$("#matrix-count").textContent = MATRIX_ROWS.length;
|
| 546 |
+
$("#matrix-ecosystem-count").textContent = ECOSYSTEMS.length;
|
| 547 |
+
const headRow = `
|
| 548 |
+
<thead>
|
| 549 |
+
<tr>
|
| 550 |
+
<th>Capability</th>
|
| 551 |
+
${ECOSYSTEMS.map(e=>`<th><div class="head-glyph">${uniqueSvg(GLYPHS[e])}<span>${e}</span></div></th>`).join("")}
|
| 552 |
+
</tr>
|
| 553 |
+
</thead>`;
|
| 554 |
+
const body = `
|
| 555 |
+
<tbody>
|
| 556 |
+
${MATRIX_ROWS.map((row, i)=>{
|
| 557 |
+
const [label, ...cells] = row;
|
| 558 |
+
return `<tr>
|
| 559 |
+
<th scope="row"><span class="row-num">${String(i+1).padStart(2,'0')}</span>${label}</th>
|
| 560 |
+
${cells.map(c=>{
|
| 561 |
+
if(c==="y") return `<td><span class="mark yes" aria-label="Supported">β</span></td>`;
|
| 562 |
+
if(c==="n") return `<td><span class="mark no" aria-label="Not supported">β</span></td>`;
|
| 563 |
+
return `<td><span class="mark partial" aria-label="Partial support">partial</span></td>`;
|
| 564 |
+
}).join("")}
|
| 565 |
+
</tr>`;
|
| 566 |
+
}).join("")}
|
| 567 |
+
</tbody>`;
|
| 568 |
+
t.insertAdjacentHTML("beforeend", headRow);
|
| 569 |
+
t.insertAdjacentHTML("beforeend", body);
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
/* βββββ References βββββ */
|
| 573 |
+
function buildRefs(){
|
| 574 |
+
const ol = $("#refs-list");
|
| 575 |
+
ol.innerHTML = REFS.map(r=>{
|
| 576 |
+
const isUrl = r.venue && !r.venue.includes(' ');
|
| 577 |
+
const venueHTML = isUrl
|
| 578 |
+
? `<a href="https://${r.venue}" target="_blank" rel="noopener">${r.venue}</a>`
|
| 579 |
+
: r.venue;
|
| 580 |
+
return `<li>${r.who}. <em>${r.title}</em>. ${r.year}.<span class="where">${venueHTML}</span></li>`;
|
| 581 |
+
}).join("");
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
/* βββββ Wire search βββββ */
|
| 585 |
+
$("#q").addEventListener("input", e=>{ state.query = e.target.value.trim(); render(); });
|
| 586 |
+
$("#reset").addEventListener("click", ()=>{
|
| 587 |
+
state.query = "";
|
| 588 |
+
state.ecosystems.clear(); state.categories.clear(); state.statuses.clear();
|
| 589 |
+
state.favOnly = false; state.newOnly = false;
|
| 590 |
+
$("#q").value = "";
|
| 591 |
+
$$(".chip[aria-pressed='true']").forEach(c=>c.setAttribute("aria-pressed","false"));
|
| 592 |
+
$$(".preset-btn").forEach(b=>b.classList.remove("active"));
|
| 593 |
+
render();
|
| 594 |
+
});
|
| 595 |
+
|
| 596 |
+
/* βββββ Add Skill modal βββββ */
|
| 597 |
+
function genId(eco, name){
|
| 598 |
+
const prefix = ECO_PREFIX[eco] || "xx";
|
| 599 |
+
const slug = name.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");
|
| 600 |
+
return prefix + "-" + slug;
|
| 601 |
+
}
|
| 602 |
+
function openAddSheet(){
|
| 603 |
+
document.getElementById("add-scrim").classList.add("open");
|
| 604 |
+
document.body.style.overflow = "hidden";
|
| 605 |
+
setTimeout(()=>document.getElementById("f-name").focus(), 60);
|
| 606 |
+
}
|
| 607 |
+
function closeAddSheet(){
|
| 608 |
+
document.getElementById("add-scrim").classList.remove("open");
|
| 609 |
+
document.body.style.overflow = "";
|
| 610 |
+
document.getElementById("add-skill-form").reset();
|
| 611 |
+
document.getElementById("id-preview").innerHTML = "id: <b>β</b>";
|
| 612 |
+
}
|
| 613 |
+
document.getElementById("add-skill-btn").addEventListener("click", openAddSheet);
|
| 614 |
+
document.getElementById("add-close-btn").addEventListener("click", closeAddSheet);
|
| 615 |
+
document.getElementById("add-cancel-btn").addEventListener("click", closeAddSheet);
|
| 616 |
+
document.getElementById("add-scrim").addEventListener("click", e=>{ if(e.target.id==="add-scrim") closeAddSheet(); });
|
| 617 |
+
|
| 618 |
+
// Live ID preview as user types name / picks ecosystem
|
| 619 |
+
["f-name","f-ecosystem"].forEach(fid=>{
|
| 620 |
+
document.getElementById(fid).addEventListener("input", ()=>{
|
| 621 |
+
const name = document.getElementById("f-name").value;
|
| 622 |
+
const eco = document.getElementById("f-ecosystem").value;
|
| 623 |
+
const el = document.getElementById("id-preview");
|
| 624 |
+
el.innerHTML = (name && eco) ? `id: <b>${genId(eco,name)}</b>` : "id: <b>β</b>";
|
| 625 |
+
});
|
| 626 |
+
});
|
| 627 |
+
|
| 628 |
+
document.getElementById("add-skill-form").addEventListener("submit", e=>{
|
| 629 |
+
e.preventDefault();
|
| 630 |
+
const val = id => document.getElementById(id).value.trim();
|
| 631 |
+
const name = val("f-name");
|
| 632 |
+
const ecosystem = val("f-ecosystem");
|
| 633 |
+
const category = val("f-category");
|
| 634 |
+
const status = val("f-status");
|
| 635 |
+
const description = val("f-desc");
|
| 636 |
+
const trigger = val("f-trigger");
|
| 637 |
+
const howto = val("f-howto");
|
| 638 |
+
const example = val("f-example");
|
| 639 |
+
const source = val("f-source") || "#";
|
| 640 |
+
|
| 641 |
+
if(!name||!ecosystem||!category||!status||!description||!trigger||!howto||!example){
|
| 642 |
+
showToast("please fill in all required fields");
|
| 643 |
+
return;
|
| 644 |
+
}
|
| 645 |
+
const id = genId(ecosystem, name);
|
| 646 |
+
if(SKILLS.find(x=>x.id===id)){
|
| 647 |
+
showToast("a skill with that name already exists");
|
| 648 |
+
return;
|
| 649 |
+
}
|
| 650 |
+
const skill = {id,name,ecosystem,category,status,description,trigger,howto,example,source,_custom:true};
|
| 651 |
+
SKILLS.push(skill);
|
| 652 |
+
const saved = JSON.parse(localStorage.getItem("skills-custom")||"[]");
|
| 653 |
+
saved.push(skill);
|
| 654 |
+
localStorage.setItem("skills-custom", JSON.stringify(saved));
|
| 655 |
+
closeAddSheet();
|
| 656 |
+
render();
|
| 657 |
+
showToast(`"${name}" added`);
|
| 658 |
+
requestAnimationFrame(()=>openSheet(skill));
|
| 659 |
+
});
|
| 660 |
+
|
| 661 |
+
/* βββββ Boot βββββ */
|
| 662 |
+
buildChips();
|
| 663 |
+
buildEcoStrip();
|
| 664 |
+
buildMatrix();
|
| 665 |
+
render();
|
| 666 |
+
openFromHash();
|
| 667 |
+
updateFavCount();
|
| 668 |
+
|
| 669 |
+
/* Wire corpus download link in footer */
|
| 670 |
+
const _corpusLink = document.getElementById("export-corpus-link");
|
| 671 |
+
if(_corpusLink) _corpusLink.addEventListener("click", (e)=>{ e.preventDefault(); $("#export-btn").click(); });
|
| 672 |
+
|
| 673 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 674 |
+
DARK MODE TOGGLE
|
| 675 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 676 |
+
(function(){
|
| 677 |
+
const btn = document.getElementById("dark-toggle");
|
| 678 |
+
if(!btn) return;
|
| 679 |
+
function applyIcon(){
|
| 680 |
+
const dark = document.documentElement.getAttribute("data-theme") === "dark";
|
| 681 |
+
btn.textContent = dark ? "β" : "β";
|
| 682 |
+
btn.title = dark ? "Switch to light mode" : "Switch to dark mode";
|
| 683 |
+
btn.setAttribute("aria-label", dark ? "Switch to light mode" : "Switch to dark mode");
|
| 684 |
+
}
|
| 685 |
+
applyIcon();
|
| 686 |
+
btn.addEventListener("click", ()=>{
|
| 687 |
+
const isDark = document.documentElement.getAttribute("data-theme") === "dark";
|
| 688 |
+
document.documentElement.setAttribute("data-theme", isDark ? "light" : "dark");
|
| 689 |
+
localStorage.setItem("sayn-theme", isDark ? "light" : "dark");
|
| 690 |
+
applyIcon();
|
| 691 |
+
});
|
| 692 |
+
})();
|
| 693 |
+
|
| 694 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 695 |
+
ANIMATED HERO COUNTERS
|
| 696 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 697 |
+
function animateCount(el, target, duration){
|
| 698 |
+
if(!el) return;
|
| 699 |
+
duration = duration || 1100;
|
| 700 |
+
const startTime = performance.now();
|
| 701 |
+
function tick(now){
|
| 702 |
+
const t = Math.min((now - startTime) / duration, 1);
|
| 703 |
+
const eased = 1 - Math.pow(1 - t, 3); /* ease-out cubic */
|
| 704 |
+
el.textContent = Math.round(eased * target);
|
| 705 |
+
if(t < 1) requestAnimationFrame(tick);
|
| 706 |
+
else el.textContent = target;
|
| 707 |
+
}
|
| 708 |
+
requestAnimationFrame(tick);
|
| 709 |
+
}
|
| 710 |
+
/* Run after boot (boot is synchronous above, so this fires right after) */
|
| 711 |
+
setTimeout(()=>{
|
| 712 |
+
animateCount(document.getElementById("hero-skill-count"), SKILLS.length, 1100);
|
| 713 |
+
}, 80);
|
| 714 |
+
|
| 715 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 716 |
+
GITHUB STAR COUNT β always fetches live on every page load
|
| 717 |
+
so the count reflects new stars immediately.
|
| 718 |
+
GitHub allows 60 unauthenticated req/hr per IP β fine for
|
| 719 |
+
a static site where each visitor has their own quota.
|
| 720 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 721 |
+
(function(){
|
| 722 |
+
const REPO = "kishormorol/SkillsAllYouNeed";
|
| 723 |
+
|
| 724 |
+
function fmtStars(n){
|
| 725 |
+
if(n >= 1000) return (n/1000).toFixed(1).replace(/\.0$/,"") + "k";
|
| 726 |
+
return String(n);
|
| 727 |
+
}
|
| 728 |
+
|
| 729 |
+
function applyCount(n){
|
| 730 |
+
const navCount = document.getElementById("star-count");
|
| 731 |
+
const ctaCount = document.getElementById("star-count-cta");
|
| 732 |
+
if(n < 1){ return; } /* keep hidden until at least 1 star */
|
| 733 |
+
const formatted = fmtStars(n);
|
| 734 |
+
if(navCount){ navCount.textContent = formatted; navCount.style.display = ""; }
|
| 735 |
+
if(ctaCount){ ctaCount.textContent = formatted; ctaCount.classList.add("loaded"); }
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
+
fetch("https://api.github.com/repos/" + REPO, {cache:"no-store"})
|
| 739 |
+
.then(r => r.ok ? r.json() : Promise.reject(r.status))
|
| 740 |
+
.then(data => applyCount(data.stargazers_count || 0))
|
| 741 |
+
.catch(() => {}); /* fail silently β button still works */
|
| 742 |
+
})();
|
| 743 |
+
|
| 744 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 745 |
+
QUICK PRESET FILTERS
|
| 746 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 747 |
+
(function(){
|
| 748 |
+
function resetAll(){
|
| 749 |
+
state.ecosystems.clear(); state.categories.clear();
|
| 750 |
+
state.statuses.clear(); state.query = ""; state.favOnly = false; state.newOnly = false;
|
| 751 |
+
document.getElementById("q").value = "";
|
| 752 |
+
document.querySelectorAll(".chip[aria-pressed='true']").forEach(c=>c.setAttribute("aria-pressed","false"));
|
| 753 |
+
document.querySelectorAll(".preset-btn").forEach(b=>b.classList.remove("active"));
|
| 754 |
+
}
|
| 755 |
+
document.querySelectorAll(".preset-btn").forEach(btn=>{
|
| 756 |
+
btn.addEventListener("click", ()=>{
|
| 757 |
+
const p = btn.dataset.preset;
|
| 758 |
+
resetAll();
|
| 759 |
+
|
| 760 |
+
if(p === "claude-code"){
|
| 761 |
+
state.ecosystems.add("Claude Code");
|
| 762 |
+
document.querySelector(`#eco-chips .chip[data-eco="Claude Code"]`)?.setAttribute("aria-pressed","true");
|
| 763 |
+
btn.classList.add("active");
|
| 764 |
+
} else if(p === "agentic"){
|
| 765 |
+
state.categories.add("Agentic");
|
| 766 |
+
document.querySelector(`#cat-chips .chip[data-filter-val="Agentic"]`)?.setAttribute("aria-pressed","true");
|
| 767 |
+
btn.classList.add("active");
|
| 768 |
+
} else if(p === "stable"){
|
| 769 |
+
state.statuses.add("Stable");
|
| 770 |
+
document.querySelector(`#status-chips .chip[data-filter-val="Stable"]`)?.setAttribute("aria-pressed","true");
|
| 771 |
+
btn.classList.add("active");
|
| 772 |
+
} else if(p === "new"){
|
| 773 |
+
state.newOnly = true;
|
| 774 |
+
btn.classList.add("active");
|
| 775 |
+
}
|
| 776 |
+
/* "clear" just resets β already done above */
|
| 777 |
+
render();
|
| 778 |
+
smoothScrollTo(document.getElementById("catalog-section"), -20);
|
| 779 |
+
});
|
| 780 |
+
});
|
| 781 |
+
|
| 782 |
+
/* Deactivate preset buttons when user manually changes filters */
|
| 783 |
+
document.getElementById("q").addEventListener("input", ()=>{
|
| 784 |
+
document.querySelectorAll(".preset-btn").forEach(b=>b.classList.remove("active"));
|
| 785 |
+
});
|
| 786 |
+
document.querySelectorAll(".chip").forEach(c=>{
|
| 787 |
+
c.addEventListener("click", ()=>{
|
| 788 |
+
document.querySelectorAll(".preset-btn").forEach(b=>b.classList.remove("active"));
|
| 789 |
+
});
|
| 790 |
+
});
|
| 791 |
+
})();
|
| 792 |
+
|
| 793 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 794 |
+
ROTATING SEARCH PLACEHOLDER
|
| 795 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 796 |
+
(function(){
|
| 797 |
+
const hints = [
|
| 798 |
+
"search names, descriptions, triggersβ¦",
|
| 799 |
+
"try: memory",
|
| 800 |
+
"try: code review",
|
| 801 |
+
"try: generate image",
|
| 802 |
+
"try: webhook",
|
| 803 |
+
"try: artifacts",
|
| 804 |
+
"try: voice mode",
|
| 805 |
+
"try: Claude Code",
|
| 806 |
+
"try: export to docx",
|
| 807 |
+
"try: browser automation",
|
| 808 |
+
];
|
| 809 |
+
let idx = 0;
|
| 810 |
+
const q = document.getElementById("q");
|
| 811 |
+
setInterval(()=>{
|
| 812 |
+
if(document.activeElement !== q && !state.query){
|
| 813 |
+
idx = (idx + 1) % hints.length;
|
| 814 |
+
q.setAttribute("placeholder", hints[idx]);
|
| 815 |
+
}
|
| 816 |
+
}, 3200);
|
| 817 |
+
})();
|
| 818 |
+
|
| 819 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 820 |
+
ONBOARDING STRIP β show once, dismiss to localStorage
|
| 821 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 822 |
+
(function(){
|
| 823 |
+
const strip = document.getElementById("onboarding-strip");
|
| 824 |
+
if(!strip) return;
|
| 825 |
+
if(!localStorage.getItem("sayn-onboarding-seen")){
|
| 826 |
+
strip.style.display = "block";
|
| 827 |
+
}
|
| 828 |
+
document.getElementById("onboarding-dismiss").addEventListener("click", ()=>{
|
| 829 |
+
const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
|
| 830 |
+
strip.classList.add("is-leaving");
|
| 831 |
+
setTimeout(()=>{ strip.style.display = "none"; }, reduced ? 0 : 180);
|
| 832 |
+
localStorage.setItem("sayn-onboarding-seen", "1");
|
| 833 |
+
});
|
| 834 |
+
})();
|
| 835 |
+
|
| 836 |
+
/* βββββ Smooth-scroll all internal anchor links βββββ */
|
| 837 |
+
document.querySelectorAll('a[href^="#"]').forEach(link=>{
|
| 838 |
+
link.addEventListener("click", (e)=>{
|
| 839 |
+
const id = link.getAttribute("href").slice(1);
|
| 840 |
+
const target = document.getElementById(id);
|
| 841 |
+
if(target){ e.preventDefault(); target.scrollIntoView({behavior:"smooth", block:"start"}); }
|
| 842 |
+
});
|
| 843 |
+
});
|
| 844 |
+
|
| 845 |
+
/* βββββ Chip: reset all on double-click of already-active chip βββββ */
|
| 846 |
+
// (chips already toggle on single click; this just adds polish)
|
| 847 |
+
|
| 848 |
+
|
| 849 |
+
/* βββββ Make add-skill-btn also reachable via keyboard Enter/Space βββββ */
|
| 850 |
+
document.getElementById("add-skill-btn").addEventListener("keydown", e=>{
|
| 851 |
+
if(e.key === "Enter" || e.key === " "){ e.preventDefault(); openAddSheet(); }
|
| 852 |
+
});
|
| 853 |
+
document.getElementById("surprise-btn").addEventListener("keydown", e=>{
|
| 854 |
+
if(e.key === "Enter" || e.key === " "){
|
| 855 |
+
e.preventDefault();
|
| 856 |
+
if(lastFiltered.length) openSheet(lastFiltered[Math.floor(Math.random()*lastFiltered.length)]);
|
| 857 |
+
}
|
| 858 |
+
});
|
skills.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
styles.css
ADDED
|
@@ -0,0 +1,1573 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2 |
+
SkillsAllYouNeed β Open AI Skills Registry
|
| 3 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 4 |
+
|
| 5 |
+
:root{
|
| 6 |
+
--paper: #F2EFE6; /* off-white, warm */
|
| 7 |
+
--paper-rgb: 242, 239, 230;
|
| 8 |
+
--paper-2: #EAE6DA;
|
| 9 |
+
--paper-edge: #DCD7C7;
|
| 10 |
+
--ink: #15130E; /* near-black, warm */
|
| 11 |
+
--ink-2: #2A2620;
|
| 12 |
+
--ink-soft: #5A5448;
|
| 13 |
+
--ink-mute: #8A8474;
|
| 14 |
+
--rule: #15130E;
|
| 15 |
+
--rule-soft: rgba(21,19,14,.18);
|
| 16 |
+
--accent: #C7401E; /* vermillion ink */
|
| 17 |
+
--accent-deep: #9E2D11;
|
| 18 |
+
--highlight: #F5D77A; /* archival manila tab */
|
| 19 |
+
|
| 20 |
+
--serif-display: Georgia, "Source Serif 4", serif;
|
| 21 |
+
--serif-body: Georgia, "Source Serif 4", serif;
|
| 22 |
+
--mono: ui-monospace, "Menlo", monospace;
|
| 23 |
+
|
| 24 |
+
--grid-max: 1320px;
|
| 25 |
+
--gutter: clamp(20px, 3.2vw, 44px);
|
| 26 |
+
|
| 27 |
+
/* Per-ecosystem brand colours */
|
| 28 |
+
--eco-claude: #d97757;
|
| 29 |
+
--eco-claude-code: #d97757;
|
| 30 |
+
--eco-chatgpt: #1A7A44;
|
| 31 |
+
--eco-gemini: #4527A0;
|
| 32 |
+
--eco-perplexity: #1B9E86;
|
| 33 |
+
--eco-copilot: #0078D4;
|
| 34 |
+
--eco-opencode: #14B85A;
|
| 35 |
+
--eco-cursor: #26251E;
|
| 36 |
+
--eco-codex: #19C37D;
|
| 37 |
+
--eco-github-copilot: #24292F;
|
| 38 |
+
--eco-antigravity: #4285F4;
|
| 39 |
+
--eco-kiro: #993FF5;
|
| 40 |
+
--eco-pi: #5B6470;
|
| 41 |
+
|
| 42 |
+
--eco-cl: var(--eco-claude);
|
| 43 |
+
--eco-cc: var(--eco-claude-code);
|
| 44 |
+
--eco-gpt: var(--eco-chatgpt);
|
| 45 |
+
--eco-cx: var(--eco-codex);
|
| 46 |
+
--eco-oc: var(--eco-opencode);
|
| 47 |
+
--eco-gm: var(--eco-gemini);
|
| 48 |
+
--eco-pp: var(--eco-perplexity);
|
| 49 |
+
--eco-mc: var(--eco-copilot);
|
| 50 |
+
--eco-ghc: var(--eco-github-copilot);
|
| 51 |
+
--eco-ag: var(--eco-antigravity);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
*{ box-sizing:border-box; }
|
| 55 |
+
html{ scroll-behavior: smooth; }
|
| 56 |
+
html,body{ margin:0; padding:0; background:var(--paper); color:var(--ink); }
|
| 57 |
+
.fonts-loaded{
|
| 58 |
+
--serif-display: "Instrument Serif", "Source Serif 4", Georgia, serif;
|
| 59 |
+
--serif-body: "Newsreader", "Source Serif 4", Georgia, serif;
|
| 60 |
+
--mono: "JetBrains Mono", ui-monospace, "Menlo", monospace;
|
| 61 |
+
}
|
| 62 |
+
body{
|
| 63 |
+
font-family:var(--serif-body);
|
| 64 |
+
font-size:17px;
|
| 65 |
+
line-height:1.5;
|
| 66 |
+
text-rendering:optimizeLegibility;
|
| 67 |
+
-webkit-font-smoothing:antialiased;
|
| 68 |
+
font-feature-settings:"ss01","ss02","onum","liga";
|
| 69 |
+
background-image:
|
| 70 |
+
radial-gradient(rgba(21,19,14,.035) 1px, transparent 1px);
|
| 71 |
+
background-size: 3px 3px;
|
| 72 |
+
background-position: 0 0;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
/* paper grain β extremely subtle */
|
| 76 |
+
body::before{
|
| 77 |
+
content:""; position:fixed; inset:0; pointer-events:none; z-index:1;
|
| 78 |
+
background:
|
| 79 |
+
repeating-linear-gradient(0deg, rgba(21,19,14,.012) 0 1px, transparent 1px 3px),
|
| 80 |
+
repeating-linear-gradient(90deg, rgba(21,19,14,.008) 0 1px, transparent 1px 4px);
|
| 81 |
+
mix-blend-mode:multiply;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
::selection{ background:var(--accent); color:var(--paper); }
|
| 85 |
+
|
| 86 |
+
a{ color:inherit; text-decoration:none; }
|
| 87 |
+
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; padding:0; }
|
| 88 |
+
|
| 89 |
+
/* ββ Layout shell ββββββββββββββββββββββββββββββββββββββββββ */
|
| 90 |
+
.shell{
|
| 91 |
+
max-width:var(--grid-max);
|
| 92 |
+
margin:0 auto;
|
| 93 |
+
padding:0 var(--gutter);
|
| 94 |
+
position:relative;
|
| 95 |
+
z-index:2;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/* ββ Hero / site header ββββββββββββββββββββββββββββββββββββ */
|
| 99 |
+
.hero{ border-bottom:1px solid var(--rule); }
|
| 100 |
+
.hero-top{
|
| 101 |
+
display:flex; justify-content:space-between; align-items:center;
|
| 102 |
+
padding:14px 0 12px;
|
| 103 |
+
border-bottom:1px solid var(--rule-soft);
|
| 104 |
+
font-family:var(--mono);
|
| 105 |
+
font-size:11px;
|
| 106 |
+
letter-spacing:.08em;
|
| 107 |
+
text-transform:uppercase;
|
| 108 |
+
}
|
| 109 |
+
.hero-brand{ display:flex; align-items:center; gap:8px; font-weight:500; color:var(--ink); }
|
| 110 |
+
.hero-dot{ width:8px; height:8px; background:var(--accent); display:inline-block; flex-shrink:0; }
|
| 111 |
+
.hero-nav{ display:flex; gap:20px; align-items:center; }
|
| 112 |
+
.hero-nav a{ color:var(--ink-soft); transition:color .12s ease; }
|
| 113 |
+
.hero-nav a:hover{ color:var(--accent); }
|
| 114 |
+
|
| 115 |
+
/* GitHub star button */
|
| 116 |
+
.star-btn{
|
| 117 |
+
display:inline-flex; align-items:center; gap:6px;
|
| 118 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.06em; text-transform:uppercase;
|
| 119 |
+
padding:5px 10px 5px 9px;
|
| 120 |
+
border:1px solid var(--rule); background:var(--paper-2);
|
| 121 |
+
color:var(--ink-soft); cursor:pointer; text-decoration:none;
|
| 122 |
+
transition: all .15s ease; white-space:nowrap;
|
| 123 |
+
border-radius:2px;
|
| 124 |
+
}
|
| 125 |
+
.star-btn:hover{ background:var(--ink); color:var(--paper); border-color:var(--ink); }
|
| 126 |
+
.star-btn svg{ width:13px; height:13px; flex-shrink:0; }
|
| 127 |
+
.star-btn .star-icon{ color:var(--accent); font-size:13px; line-height:1; }
|
| 128 |
+
.star-btn .star-count{
|
| 129 |
+
font-size:10px; color:var(--ink-mute); padding-left:4px;
|
| 130 |
+
border-left:1px solid var(--rule); margin-left:2px;
|
| 131 |
+
transition: color .15s ease;
|
| 132 |
+
}
|
| 133 |
+
.star-btn:hover .star-count{ color:var(--paper); border-color:rgba(255,255,255,.2); }
|
| 134 |
+
[data-theme="dark"] .star-btn{ background:rgba(255,255,255,.05); }
|
| 135 |
+
|
| 136 |
+
.hero-body{ padding:56px 0 52px; position:relative; z-index:0; }
|
| 137 |
+
/* blurred orange glow behind hero area */
|
| 138 |
+
.hero-body::before{
|
| 139 |
+
content:""; position:absolute; z-index:-1; pointer-events:none;
|
| 140 |
+
left:-5%; top:10%; width:65%; height:80%;
|
| 141 |
+
background: radial-gradient(ellipse at 30% 50%, rgba(217,119,87,.09) 0%, transparent 70%);
|
| 142 |
+
filter: blur(48px);
|
| 143 |
+
}
|
| 144 |
+
.hero-body h1{
|
| 145 |
+
font-family:var(--serif-display);
|
| 146 |
+
font-weight:400;
|
| 147 |
+
font-size: clamp(56px, 9vw, 130px);
|
| 148 |
+
line-height:.9;
|
| 149 |
+
letter-spacing:-.025em;
|
| 150 |
+
margin:0 0 28px;
|
| 151 |
+
}
|
| 152 |
+
.hero-body h1 em{ font-style:italic; color:var(--accent); }
|
| 153 |
+
.hero-body h1 .h1-sub{
|
| 154 |
+
font-size: clamp(22px, 2.8vw, 44px);
|
| 155 |
+
font-style: normal;
|
| 156 |
+
color: var(--ink-soft);
|
| 157 |
+
letter-spacing: -.01em;
|
| 158 |
+
}
|
| 159 |
+
.hero-sub{
|
| 160 |
+
font-family:var(--serif-body);
|
| 161 |
+
font-size: clamp(17px, 1.4vw, 21px);
|
| 162 |
+
line-height:1.45;
|
| 163 |
+
color:var(--ink-2);
|
| 164 |
+
max-width:64ch;
|
| 165 |
+
margin:0 0 40px;
|
| 166 |
+
text-wrap:pretty;
|
| 167 |
+
}
|
| 168 |
+
.hero-stats{
|
| 169 |
+
display:flex; gap:0; margin-bottom:36px; flex-wrap:wrap;
|
| 170 |
+
}
|
| 171 |
+
.hero-stats .stat{
|
| 172 |
+
display:flex; flex-direction:column; gap:3px;
|
| 173 |
+
padding:16px 32px 14px;
|
| 174 |
+
}
|
| 175 |
+
.hero-stats .stat:last-child{ }
|
| 176 |
+
.hero-stats .stat b{
|
| 177 |
+
font-family:var(--serif-display);
|
| 178 |
+
font-size: clamp(32px, 3.8vw, 48px);
|
| 179 |
+
font-style:italic;
|
| 180 |
+
line-height:1;
|
| 181 |
+
color:var(--accent);
|
| 182 |
+
font-weight:400;
|
| 183 |
+
letter-spacing:-.02em;
|
| 184 |
+
}
|
| 185 |
+
.hero-stats .stat span{
|
| 186 |
+
font-family:var(--mono);
|
| 187 |
+
font-size:10px;
|
| 188 |
+
text-transform:uppercase;
|
| 189 |
+
letter-spacing:.14em;
|
| 190 |
+
color:var(--ink-mute);
|
| 191 |
+
}
|
| 192 |
+
@media(max-width:540px){
|
| 193 |
+
.hero-stats .stat{ padding:12px 20px 10px; }
|
| 194 |
+
}
|
| 195 |
+
.hero-cta{ display:flex; gap:10px; flex-wrap:wrap; }
|
| 196 |
+
.cta-primary{
|
| 197 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase;
|
| 198 |
+
padding:13px 26px; background:var(--ink); color:var(--paper); border:1px solid var(--ink);
|
| 199 |
+
display:inline-block; position:relative;
|
| 200 |
+
box-shadow: 4px 4px 0 var(--accent);
|
| 201 |
+
transition: box-shadow .14s ease, transform .14s ease, background .12s ease, border-color .12s ease;
|
| 202 |
+
}
|
| 203 |
+
.cta-primary:hover{
|
| 204 |
+
background:var(--accent); border-color:var(--accent);
|
| 205 |
+
box-shadow: none; transform: translate(4px,4px);
|
| 206 |
+
}
|
| 207 |
+
.cta-ghost{
|
| 208 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase;
|
| 209 |
+
padding:13px 26px; background:transparent; color:var(--ink-soft); border:1px solid var(--rule);
|
| 210 |
+
display:inline-block;
|
| 211 |
+
transition:background .12s ease, color .12s ease, border-color .12s ease;
|
| 212 |
+
}
|
| 213 |
+
.cta-ghost:hover{ background:var(--ink); color:var(--paper); border-color:var(--ink); }
|
| 214 |
+
.star-cta{ gap:8px; }
|
| 215 |
+
.star-count-cta{
|
| 216 |
+
font-family:var(--mono); font-size:10px; letter-spacing:.04em;
|
| 217 |
+
background:var(--paper-edge); color:var(--ink-mute);
|
| 218 |
+
padding:1px 6px; border-radius:20px; display:none;
|
| 219 |
+
}
|
| 220 |
+
.star-count-cta.loaded{ display:inline; }
|
| 221 |
+
.star-cta:hover .star-count-cta{ background:rgba(255,255,255,.15); color:var(--paper); }
|
| 222 |
+
|
| 223 |
+
/* ββ Section header βββββββββββββββββββββββββββββββββββββββ */
|
| 224 |
+
.section{ padding:80px 0 40px; border-bottom:1px solid var(--rule); }
|
| 225 |
+
.section.tight{ padding-top:48px; }
|
| 226 |
+
.section-head{
|
| 227 |
+
display:grid;
|
| 228 |
+
grid-template-columns: 1fr auto;
|
| 229 |
+
gap:32px;
|
| 230 |
+
align-items:baseline;
|
| 231 |
+
margin-bottom:36px;
|
| 232 |
+
}
|
| 233 |
+
.section-head .label{
|
| 234 |
+
font-family:var(--mono);
|
| 235 |
+
font-size:11px;
|
| 236 |
+
letter-spacing:.18em;
|
| 237 |
+
text-transform:uppercase;
|
| 238 |
+
color:var(--ink-mute);
|
| 239 |
+
margin-bottom:6px;
|
| 240 |
+
}
|
| 241 |
+
.section-head h2{
|
| 242 |
+
font-family:var(--serif-display);
|
| 243 |
+
font-weight:400;
|
| 244 |
+
font-size: clamp(34px, 4.4vw, 56px);
|
| 245 |
+
line-height:1;
|
| 246 |
+
letter-spacing:-.01em;
|
| 247 |
+
margin:0;
|
| 248 |
+
}
|
| 249 |
+
.section-head h2 .it{ font-style:italic; }
|
| 250 |
+
.section-head .right{
|
| 251 |
+
font-family:var(--mono);
|
| 252 |
+
font-size:11px;
|
| 253 |
+
text-transform:uppercase;
|
| 254 |
+
letter-spacing:.1em;
|
| 255 |
+
color:var(--ink-mute);
|
| 256 |
+
text-align:right;
|
| 257 |
+
line-height:1.6;
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
/* ββ Filter bar βββββββββββββββββββββββββββββββββββββββββββ */
|
| 261 |
+
.filters{
|
| 262 |
+
display:grid;
|
| 263 |
+
grid-template-columns: 1fr;
|
| 264 |
+
gap:20px;
|
| 265 |
+
margin-bottom:8px;
|
| 266 |
+
}
|
| 267 |
+
.filter-row{
|
| 268 |
+
display:flex; gap:8px; align-items:center;
|
| 269 |
+
flex-wrap:wrap;
|
| 270 |
+
}
|
| 271 |
+
.filter-row .lbl{
|
| 272 |
+
font-family:var(--mono);
|
| 273 |
+
font-size:10px;
|
| 274 |
+
text-transform:uppercase;
|
| 275 |
+
letter-spacing:.14em;
|
| 276 |
+
color:var(--ink-mute);
|
| 277 |
+
margin-right:6px;
|
| 278 |
+
min-width:80px;
|
| 279 |
+
flex-shrink:0;
|
| 280 |
+
}
|
| 281 |
+
/* on narrow screens, chip rows scroll horizontally */
|
| 282 |
+
@media(max-width:640px){
|
| 283 |
+
.filter-row{ flex-wrap:nowrap; overflow-x:auto; -webkit-overflow-scrolling:touch; padding-bottom:4px; }
|
| 284 |
+
.filter-row::-webkit-scrollbar{ height:2px; }
|
| 285 |
+
.filter-row::-webkit-scrollbar-thumb{ background:var(--rule-soft); }
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
.chip{
|
| 289 |
+
font-family:var(--mono);
|
| 290 |
+
font-size:11px;
|
| 291 |
+
text-transform:uppercase;
|
| 292 |
+
letter-spacing:.08em;
|
| 293 |
+
padding:6px 12px 5px;
|
| 294 |
+
border:1px solid var(--rule-soft);
|
| 295 |
+
background:var(--paper);
|
| 296 |
+
color:var(--ink-soft);
|
| 297 |
+
border-radius:0;
|
| 298 |
+
cursor:pointer;
|
| 299 |
+
position:relative;
|
| 300 |
+
white-space:nowrap;
|
| 301 |
+
flex-shrink:0;
|
| 302 |
+
max-width:220px;
|
| 303 |
+
overflow:hidden;
|
| 304 |
+
text-overflow:ellipsis;
|
| 305 |
+
transition:background .12s ease, color .12s ease, border-color .12s ease, box-shadow .12s ease;
|
| 306 |
+
line-height:1;
|
| 307 |
+
}
|
| 308 |
+
.chip:hover{ background:var(--paper-2); color:var(--ink); border-color:var(--rule); }
|
| 309 |
+
.chip[aria-pressed="true"]{
|
| 310 |
+
background:var(--ink);
|
| 311 |
+
color:var(--paper);
|
| 312 |
+
border-color:var(--ink);
|
| 313 |
+
box-shadow: inset 3px 0 0 var(--accent);
|
| 314 |
+
}
|
| 315 |
+
.chip .glyph-wrap{ display:inline-flex; align-items:center; gap:7px; }
|
| 316 |
+
.chip svg{ width:11px; height:11px; }
|
| 317 |
+
.chip[aria-pressed="true"] svg *{ stroke:var(--paper); fill:var(--paper); }
|
| 318 |
+
.chip[data-eco="Claude"][aria-pressed="true"]{
|
| 319 |
+
background:var(--accent); border-color:var(--accent); box-shadow:none;
|
| 320 |
+
}
|
| 321 |
+
.chip[data-eco="Claude"][aria-pressed="true"] svg *{ stroke:var(--paper); fill:var(--paper); }
|
| 322 |
+
|
| 323 |
+
/* Search */
|
| 324 |
+
.search-wrap{
|
| 325 |
+
display:flex; align-items:center; gap:14px;
|
| 326 |
+
min-width:0;
|
| 327 |
+
border:1px solid var(--rule);
|
| 328 |
+
padding:16px 20px;
|
| 329 |
+
background:var(--paper);
|
| 330 |
+
transition: border-color .15s ease, box-shadow .15s ease;
|
| 331 |
+
}
|
| 332 |
+
.search-wrap:focus-within{
|
| 333 |
+
border-color:var(--accent);
|
| 334 |
+
box-shadow: 0 0 0 3px rgba(199,64,30,.12), 4px 4px 0 var(--accent);
|
| 335 |
+
}
|
| 336 |
+
.search-wrap .lbl{
|
| 337 |
+
min-width:auto; margin:0;
|
| 338 |
+
color:var(--accent); font-size:12px; letter-spacing:.12em;
|
| 339 |
+
}
|
| 340 |
+
.search-wrap input{
|
| 341 |
+
flex:1;
|
| 342 |
+
min-width:0;
|
| 343 |
+
font:inherit;
|
| 344 |
+
font-family:var(--serif-body);
|
| 345 |
+
font-size:21px;
|
| 346 |
+
border:0;
|
| 347 |
+
background:transparent;
|
| 348 |
+
outline:0;
|
| 349 |
+
color:var(--ink);
|
| 350 |
+
}
|
| 351 |
+
.search-wrap input::placeholder{ color:var(--ink-mute); font-style:italic; }
|
| 352 |
+
.search-wrap .count{
|
| 353 |
+
font-family:var(--mono);
|
| 354 |
+
font-size:11px;
|
| 355 |
+
text-transform:uppercase;
|
| 356 |
+
letter-spacing:.1em;
|
| 357 |
+
color:var(--ink-mute);
|
| 358 |
+
white-space:nowrap;
|
| 359 |
+
}
|
| 360 |
+
.search-wrap .count b{ color:var(--accent); font-weight:600; }
|
| 361 |
+
@media(max-width:640px){
|
| 362 |
+
.hero-top{
|
| 363 |
+
align-items:flex-start;
|
| 364 |
+
flex-direction:column;
|
| 365 |
+
gap:12px;
|
| 366 |
+
}
|
| 367 |
+
.hero-nav{
|
| 368 |
+
width:100%;
|
| 369 |
+
min-width:0;
|
| 370 |
+
flex-wrap:wrap;
|
| 371 |
+
justify-content:flex-start;
|
| 372 |
+
gap:5px;
|
| 373 |
+
}
|
| 374 |
+
.hero-nav > a,
|
| 375 |
+
.hero-nav > button{
|
| 376 |
+
min-width:44px;
|
| 377 |
+
min-height:44px;
|
| 378 |
+
display:inline-flex;
|
| 379 |
+
align-items:center;
|
| 380 |
+
justify-content:center;
|
| 381 |
+
}
|
| 382 |
+
.hero-nav > a:not(.star-btn),
|
| 383 |
+
.hero-nav > .dark-toggle{
|
| 384 |
+
padding:0 10px;
|
| 385 |
+
border:1px solid var(--rule-soft);
|
| 386 |
+
}
|
| 387 |
+
.search-wrap{ gap:10px; padding:14px; }
|
| 388 |
+
.search-wrap .count{ font-size:10px; }
|
| 389 |
+
.contribute-grid{ grid-template-columns:1fr !important; }
|
| 390 |
+
.contribute-grid > a:first-child{
|
| 391 |
+
border-right:0 !important;
|
| 392 |
+
border-bottom:1px solid var(--rule-soft);
|
| 393 |
+
}
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
/* ββ Skill grid (asymmetric) ββββββββββββββββββββββββββββββ */
|
| 397 |
+
.grid{
|
| 398 |
+
display:grid;
|
| 399 |
+
grid-template-columns: repeat(12, 1fr);
|
| 400 |
+
gap:0;
|
| 401 |
+
border-top:1px solid var(--rule);
|
| 402 |
+
}
|
| 403 |
+
/* Per-ecosystem card accent colour β generated by data.js ECO registry */
|
| 404 |
+
|
| 405 |
+
.card{
|
| 406 |
+
grid-column: span 4;
|
| 407 |
+
border-right:1px solid var(--rule-soft);
|
| 408 |
+
border-bottom:1px solid var(--rule);
|
| 409 |
+
padding:24px 24px 26px;
|
| 410 |
+
background:var(--paper);
|
| 411 |
+
position:relative;
|
| 412 |
+
cursor:pointer;
|
| 413 |
+
z-index:0;
|
| 414 |
+
transition: background .15s ease, box-shadow .18s ease, z-index 0s;
|
| 415 |
+
display:flex; flex-direction:column;
|
| 416 |
+
min-height:248px;
|
| 417 |
+
}
|
| 418 |
+
.card:hover{
|
| 419 |
+
background:var(--paper-2);
|
| 420 |
+
box-shadow: inset 4px 0 0 var(--eco-color, var(--accent));
|
| 421 |
+
z-index:1;
|
| 422 |
+
}
|
| 423 |
+
.card:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
|
| 424 |
+
.card.span-6{ grid-column: span 6; }
|
| 425 |
+
.card.span-8{ grid-column: span 8; }
|
| 426 |
+
.card.span-12{ grid-column: span 12; }
|
| 427 |
+
.card.featured{
|
| 428 |
+
background: linear-gradient(150deg, var(--ink) 0%, #201C15 100%);
|
| 429 |
+
color:var(--paper);
|
| 430 |
+
}
|
| 431 |
+
.card.featured .id, .card.featured .cat, .card.featured .status, .card.featured .desc, .card.featured .eco-label{ color:var(--paper); }
|
| 432 |
+
.card.featured .id{ color:var(--paper); opacity:.5; }
|
| 433 |
+
.card.featured .glyph svg *{ stroke:var(--paper); }
|
| 434 |
+
.card.featured:hover{
|
| 435 |
+
background: linear-gradient(150deg, #201C15 0%, #2A2418 100%);
|
| 436 |
+
box-shadow: inset 4px 0 0 var(--highlight);
|
| 437 |
+
}
|
| 438 |
+
.card.featured .name .it{ color:var(--highlight); }
|
| 439 |
+
|
| 440 |
+
.card:nth-child(12n+0){ border-right:0; }
|
| 441 |
+
@media (max-width: 900px){
|
| 442 |
+
.card, .card.span-6, .card.span-8, .card.span-12{ grid-column: span 12; border-right:0; }
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
.card .top{
|
| 446 |
+
display:flex; justify-content:space-between; align-items:flex-start;
|
| 447 |
+
gap:12px;
|
| 448 |
+
margin-bottom:18px;
|
| 449 |
+
}
|
| 450 |
+
.card .glyph{
|
| 451 |
+
width:32px; height:32px;
|
| 452 |
+
display:flex; align-items:center; justify-content:center;
|
| 453 |
+
flex-shrink:0;
|
| 454 |
+
}
|
| 455 |
+
.card .glyph svg{ width:100%; height:100%; }
|
| 456 |
+
.card .id{
|
| 457 |
+
font-family:var(--mono);
|
| 458 |
+
font-size:10px;
|
| 459 |
+
letter-spacing:.06em;
|
| 460 |
+
color:var(--ink-mute);
|
| 461 |
+
text-transform:uppercase;
|
| 462 |
+
}
|
| 463 |
+
.card .meta-top{
|
| 464 |
+
text-align:right;
|
| 465 |
+
font-family:var(--mono);
|
| 466 |
+
font-size:10.5px;
|
| 467 |
+
letter-spacing:.08em;
|
| 468 |
+
text-transform:uppercase;
|
| 469 |
+
color:var(--ink-mute);
|
| 470 |
+
line-height:1.5;
|
| 471 |
+
}
|
| 472 |
+
.card .meta-top .eco-label{ display:block; color:var(--ink-2); word-break:break-word; max-width:130px; }
|
| 473 |
+
|
| 474 |
+
.card .name{
|
| 475 |
+
font-family:var(--serif-display);
|
| 476 |
+
font-weight:400;
|
| 477 |
+
font-size: clamp(28px, 2.6vw, 38px);
|
| 478 |
+
line-height:1;
|
| 479 |
+
letter-spacing:-.01em;
|
| 480 |
+
margin:0 0 14px;
|
| 481 |
+
text-wrap:balance;
|
| 482 |
+
}
|
| 483 |
+
.card.span-8 .name, .card.span-12 .name{ font-size: clamp(40px, 4vw, 62px); }
|
| 484 |
+
.card .name .it{ font-style:italic; color:var(--accent); }
|
| 485 |
+
|
| 486 |
+
.card .desc{
|
| 487 |
+
font-size: 16px;
|
| 488 |
+
line-height:1.45;
|
| 489 |
+
color:var(--ink-2);
|
| 490 |
+
margin:0 0 18px;
|
| 491 |
+
max-width:42ch;
|
| 492 |
+
text-wrap:pretty;
|
| 493 |
+
}
|
| 494 |
+
.card.span-8 .desc, .card.span-12 .desc{ font-size:19px; max-width:58ch; }
|
| 495 |
+
|
| 496 |
+
.card .bottom{
|
| 497 |
+
margin-top:auto;
|
| 498 |
+
display:flex; justify-content:space-between; align-items:flex-end;
|
| 499 |
+
gap:14px;
|
| 500 |
+
padding-top:14px;
|
| 501 |
+
border-top:1px dotted var(--rule-soft);
|
| 502 |
+
}
|
| 503 |
+
.card .cat{
|
| 504 |
+
font-family:var(--mono);
|
| 505 |
+
font-size:10.5px;
|
| 506 |
+
letter-spacing:.1em;
|
| 507 |
+
text-transform:uppercase;
|
| 508 |
+
color:var(--ink-soft);
|
| 509 |
+
}
|
| 510 |
+
.card .cat::before{ content:"# "; opacity:.4; }
|
| 511 |
+
.card .status{
|
| 512 |
+
font-family:var(--mono);
|
| 513 |
+
font-size:10.5px;
|
| 514 |
+
letter-spacing:.1em;
|
| 515 |
+
text-transform:uppercase;
|
| 516 |
+
color:var(--ink-soft);
|
| 517 |
+
display:inline-flex; align-items:center; gap:6px;
|
| 518 |
+
}
|
| 519 |
+
.status-dot{
|
| 520 |
+
width:6px; height:6px; display:inline-block;
|
| 521 |
+
background:var(--accent);
|
| 522 |
+
}
|
| 523 |
+
.status[data-status="Stable"] .status-dot{ background:var(--ink); }
|
| 524 |
+
.status[data-status="Beta"] .status-dot{
|
| 525 |
+
background:transparent;
|
| 526 |
+
border:1px solid var(--accent);
|
| 527 |
+
box-shadow: inset 0 0 0 2px var(--paper);
|
| 528 |
+
width:8px; height:8px;
|
| 529 |
+
transform:translateY(1px);
|
| 530 |
+
}
|
| 531 |
+
.status[data-status="Deprecated"] .status-dot{ background:var(--ink-mute); }
|
| 532 |
+
.card.featured .status-dot{ background:var(--paper); }
|
| 533 |
+
|
| 534 |
+
/* fade-in stagger */
|
| 535 |
+
.card{ opacity:0; transform:translateY(6px); transition: opacity .28s ease, transform .28s ease, background .15s ease, box-shadow .18s ease; }
|
| 536 |
+
.card.in{ opacity:1; transform:none; }
|
| 537 |
+
|
| 538 |
+
.no-results{
|
| 539 |
+
grid-column: span 12;
|
| 540 |
+
padding:80px 24px;
|
| 541 |
+
text-align:center;
|
| 542 |
+
font-family:var(--serif-display);
|
| 543 |
+
font-style:italic;
|
| 544 |
+
font-size:32px;
|
| 545 |
+
color:var(--ink-mute);
|
| 546 |
+
border-bottom:1px solid var(--rule);
|
| 547 |
+
}
|
| 548 |
+
.no-results small{
|
| 549 |
+
display:block;
|
| 550 |
+
font-family:var(--mono);
|
| 551 |
+
font-style:normal;
|
| 552 |
+
font-size:11px;
|
| 553 |
+
text-transform:uppercase;
|
| 554 |
+
letter-spacing:.12em;
|
| 555 |
+
margin-top:14px;
|
| 556 |
+
color:var(--ink-mute);
|
| 557 |
+
}
|
| 558 |
+
|
| 559 |
+
/* ββ Detail / modal βββββββββββββββββββββββββββββββββββββββ */
|
| 560 |
+
.scrim{
|
| 561 |
+
position:fixed; inset:0; background:rgba(21,19,14,.62);
|
| 562 |
+
z-index:50;
|
| 563 |
+
display:none;
|
| 564 |
+
align-items:flex-start;
|
| 565 |
+
justify-content:center;
|
| 566 |
+
padding:48px 24px;
|
| 567 |
+
overflow-y:auto;
|
| 568 |
+
}
|
| 569 |
+
.scrim.open{
|
| 570 |
+
display:flex;
|
| 571 |
+
animation: scrim-in .22s ease-out both;
|
| 572 |
+
}
|
| 573 |
+
@keyframes scrim-in{ from{ opacity:0; } to{ opacity:1; } }
|
| 574 |
+
|
| 575 |
+
.sheet{
|
| 576 |
+
background:var(--paper);
|
| 577 |
+
width:100%;
|
| 578 |
+
max-width:880px;
|
| 579 |
+
padding:48px 56px 48px;
|
| 580 |
+
position:relative;
|
| 581 |
+
border:1px solid var(--ink);
|
| 582 |
+
box-shadow: 8px 8px 0 var(--accent), 16px 16px 0 -2px var(--ink);
|
| 583 |
+
animation: sheet-in .26s cubic-bezier(0.16,1,0.3,1) both;
|
| 584 |
+
}
|
| 585 |
+
@keyframes sheet-in{
|
| 586 |
+
from{ opacity:0; transform: translateY(-18px) scale(.975); }
|
| 587 |
+
to{ opacity:1; transform: none; }
|
| 588 |
+
}
|
| 589 |
+
@media (max-width: 720px){
|
| 590 |
+
.sheet{ padding:36px 24px; box-shadow: 4px 4px 0 var(--accent), 8px 8px 0 -2px var(--ink); }
|
| 591 |
+
}
|
| 592 |
+
.sheet .close{
|
| 593 |
+
position:absolute; top:18px; right:18px;
|
| 594 |
+
font-family:var(--mono);
|
| 595 |
+
font-size:11px;
|
| 596 |
+
text-transform:uppercase;
|
| 597 |
+
letter-spacing:.12em;
|
| 598 |
+
border:1px solid var(--rule);
|
| 599 |
+
padding:6px 10px;
|
| 600 |
+
}
|
| 601 |
+
.sheet .close:hover{ background:var(--ink); color:var(--paper); }
|
| 602 |
+
.sheet .sheet-top{
|
| 603 |
+
display:flex; align-items:flex-start; gap:18px; margin-bottom:24px;
|
| 604 |
+
padding-bottom:18px; border-bottom:1px solid var(--rule);
|
| 605 |
+
}
|
| 606 |
+
.sheet .glyph-lg{ width:54px; height:54px; flex-shrink:0; border:1px solid var(--rule); display:flex; align-items:center; justify-content:center; }
|
| 607 |
+
.sheet .glyph-lg svg{ width:32px; height:32px; }
|
| 608 |
+
.sheet .top-meta{
|
| 609 |
+
font-family:var(--mono);
|
| 610 |
+
font-size:11px;
|
| 611 |
+
letter-spacing:.08em;
|
| 612 |
+
text-transform:uppercase;
|
| 613 |
+
color:var(--ink-mute);
|
| 614 |
+
line-height:1.7;
|
| 615 |
+
}
|
| 616 |
+
.sheet .top-meta b{ color:var(--ink); font-weight:500; }
|
| 617 |
+
.sheet h3{
|
| 618 |
+
font-family:var(--serif-display);
|
| 619 |
+
font-weight:400;
|
| 620 |
+
font-size:64px;
|
| 621 |
+
line-height:1;
|
| 622 |
+
letter-spacing:-.015em;
|
| 623 |
+
margin:0 0 8px;
|
| 624 |
+
}
|
| 625 |
+
.sheet h3 .it{ font-style:italic; color:var(--accent); }
|
| 626 |
+
.sheet .lede{
|
| 627 |
+
font-family:var(--serif-body);
|
| 628 |
+
font-size:21px;
|
| 629 |
+
line-height:1.45;
|
| 630 |
+
color:var(--ink-2);
|
| 631 |
+
margin:0 0 28px;
|
| 632 |
+
max-width:60ch;
|
| 633 |
+
}
|
| 634 |
+
.sheet h4{
|
| 635 |
+
font-family:var(--mono);
|
| 636 |
+
font-size:10.5px;
|
| 637 |
+
letter-spacing:.16em;
|
| 638 |
+
text-transform:uppercase;
|
| 639 |
+
color:var(--ink-mute);
|
| 640 |
+
margin:28px 0 10px;
|
| 641 |
+
}
|
| 642 |
+
.sheet .field{
|
| 643 |
+
border-left:1px solid var(--accent);
|
| 644 |
+
padding:4px 0 4px 16px;
|
| 645 |
+
margin:0;
|
| 646 |
+
font-family:var(--mono);
|
| 647 |
+
font-size:14px;
|
| 648 |
+
line-height:1.55;
|
| 649 |
+
color:var(--ink);
|
| 650 |
+
background: linear-gradient(transparent, transparent);
|
| 651 |
+
overflow-wrap:break-word;
|
| 652 |
+
word-break:break-word;
|
| 653 |
+
}
|
| 654 |
+
.sheet .field.serif{
|
| 655 |
+
font-family:var(--serif-body);
|
| 656 |
+
font-size:18px;
|
| 657 |
+
border-left-color:var(--ink);
|
| 658 |
+
}
|
| 659 |
+
.sheet .src{
|
| 660 |
+
font-family:var(--mono);
|
| 661 |
+
font-size:12px;
|
| 662 |
+
border:1px solid var(--rule);
|
| 663 |
+
padding:10px 14px;
|
| 664 |
+
display:inline-flex;
|
| 665 |
+
align-items:center;
|
| 666 |
+
gap:10px;
|
| 667 |
+
margin-top:6px;
|
| 668 |
+
}
|
| 669 |
+
.sheet .src:hover{ background:var(--ink); color:var(--paper); }
|
| 670 |
+
.sheet .src::before{ content:"β"; color:var(--accent); }
|
| 671 |
+
.sheet .src:hover::before{ color:var(--highlight); }
|
| 672 |
+
|
| 673 |
+
/* ββ Comparison matrix βββββββββββββββββββββββββββββββββββ */
|
| 674 |
+
.matrix-wrap{
|
| 675 |
+
max-width:100%;
|
| 676 |
+
border:1px solid var(--rule);
|
| 677 |
+
background:var(--paper);
|
| 678 |
+
overflow-x:auto;
|
| 679 |
+
}
|
| 680 |
+
table.matrix{
|
| 681 |
+
width:100%;
|
| 682 |
+
min-width:1680px;
|
| 683 |
+
border-collapse:collapse;
|
| 684 |
+
font-family:var(--serif-body);
|
| 685 |
+
}
|
| 686 |
+
table.matrix caption{
|
| 687 |
+
text-align:left;
|
| 688 |
+
font-family:var(--mono);
|
| 689 |
+
font-size:11px;
|
| 690 |
+
letter-spacing:.14em;
|
| 691 |
+
text-transform:uppercase;
|
| 692 |
+
color:var(--ink-soft);
|
| 693 |
+
padding:14px 18px;
|
| 694 |
+
border-bottom:1px solid var(--rule);
|
| 695 |
+
background:var(--paper-2);
|
| 696 |
+
}
|
| 697 |
+
table.matrix caption b{ color:var(--ink); font-weight:500; }
|
| 698 |
+
table.matrix thead th{
|
| 699 |
+
font-family:var(--mono);
|
| 700 |
+
font-size:11px;
|
| 701 |
+
letter-spacing:.06em;
|
| 702 |
+
text-transform:uppercase;
|
| 703 |
+
color:var(--ink);
|
| 704 |
+
text-align:center;
|
| 705 |
+
padding:18px 14px 16px;
|
| 706 |
+
border-bottom:1px solid var(--rule);
|
| 707 |
+
background:var(--paper);
|
| 708 |
+
vertical-align:bottom;
|
| 709 |
+
font-weight:500;
|
| 710 |
+
}
|
| 711 |
+
table.matrix thead th:first-child,
|
| 712 |
+
table.matrix tbody th{
|
| 713 |
+
position:sticky;
|
| 714 |
+
left:0;
|
| 715 |
+
width:360px;
|
| 716 |
+
min-width:360px;
|
| 717 |
+
background:var(--paper);
|
| 718 |
+
z-index:1;
|
| 719 |
+
}
|
| 720 |
+
table.matrix thead th:first-child{
|
| 721 |
+
z-index:2;
|
| 722 |
+
text-align:left;
|
| 723 |
+
padding-left:22px;
|
| 724 |
+
}
|
| 725 |
+
table.matrix thead .head-glyph{
|
| 726 |
+
display:flex; flex-direction:column; align-items:center; gap:8px;
|
| 727 |
+
}
|
| 728 |
+
table.matrix thead .head-glyph svg{ width:22px; height:22px; }
|
| 729 |
+
table.matrix tbody td{
|
| 730 |
+
font-size:16px;
|
| 731 |
+
padding:16px 14px;
|
| 732 |
+
text-align:center;
|
| 733 |
+
border-bottom:1px solid var(--rule-soft);
|
| 734 |
+
vertical-align:middle;
|
| 735 |
+
}
|
| 736 |
+
table.matrix tbody th{
|
| 737 |
+
padding-left:22px;
|
| 738 |
+
text-align:left;
|
| 739 |
+
font-family:var(--serif-body);
|
| 740 |
+
font-size:18px;
|
| 741 |
+
font-weight:400;
|
| 742 |
+
color:var(--ink);
|
| 743 |
+
border-bottom:1px solid var(--rule-soft);
|
| 744 |
+
vertical-align:middle;
|
| 745 |
+
}
|
| 746 |
+
table.matrix tbody th .row-num{
|
| 747 |
+
display:inline-block;
|
| 748 |
+
min-width:24px;
|
| 749 |
+
margin-right:14px;
|
| 750 |
+
font-family:var(--mono);
|
| 751 |
+
font-size:10px;
|
| 752 |
+
letter-spacing:.1em;
|
| 753 |
+
color:var(--ink-soft);
|
| 754 |
+
}
|
| 755 |
+
table.matrix tbody tr:hover{ background:var(--paper-2); }
|
| 756 |
+
table.matrix tbody tr:hover th{ background:var(--paper-2); }
|
| 757 |
+
table.matrix tbody tr:last-child td,
|
| 758 |
+
table.matrix tbody tr:last-child th{ border-bottom:0; }
|
| 759 |
+
.mark{
|
| 760 |
+
display:inline-flex; align-items:center; justify-content:center;
|
| 761 |
+
width:34px; height:34px;
|
| 762 |
+
font-family:var(--mono);
|
| 763 |
+
font-size:14px;
|
| 764 |
+
font-weight:500;
|
| 765 |
+
}
|
| 766 |
+
.mark.yes{ color:var(--accent-deep); font-size:22px; font-family:var(--serif-display); }
|
| 767 |
+
.mark.no{ color:var(--ink-soft); font-size:18px; }
|
| 768 |
+
.mark.partial{
|
| 769 |
+
width:auto; height:auto;
|
| 770 |
+
padding:4px 8px;
|
| 771 |
+
border:1px solid var(--rule);
|
| 772 |
+
background:var(--paper-2);
|
| 773 |
+
color:var(--ink);
|
| 774 |
+
font-size:10px;
|
| 775 |
+
text-transform:uppercase;
|
| 776 |
+
letter-spacing:.08em;
|
| 777 |
+
}
|
| 778 |
+
[data-theme="dark"] .mark.yes{ color:#F07855; }
|
| 779 |
+
@media(max-width:700px){
|
| 780 |
+
table.matrix thead th:first-child,
|
| 781 |
+
table.matrix tbody th{
|
| 782 |
+
width:210px;
|
| 783 |
+
min-width:210px;
|
| 784 |
+
}
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
/* ββ Colophon / footer βββββββββββββββββββββββοΏ½οΏ½ββββββββββββ */
|
| 788 |
+
.colophon{
|
| 789 |
+
padding:64px 0 80px;
|
| 790 |
+
display:grid;
|
| 791 |
+
grid-template-columns: 1fr 1fr 1fr;
|
| 792 |
+
gap:48px;
|
| 793 |
+
border-top:1px solid var(--rule);
|
| 794 |
+
margin-top:0;
|
| 795 |
+
}
|
| 796 |
+
@media (max-width: 800px){ .colophon{ grid-template-columns:1fr; gap:32px; } }
|
| 797 |
+
.colophon h5{
|
| 798 |
+
font-family:var(--mono);
|
| 799 |
+
font-size:10.5px;
|
| 800 |
+
letter-spacing:.18em;
|
| 801 |
+
text-transform:uppercase;
|
| 802 |
+
color:var(--ink-mute);
|
| 803 |
+
margin:0 0 12px;
|
| 804 |
+
font-weight:500;
|
| 805 |
+
}
|
| 806 |
+
.colophon p, .colophon ul{
|
| 807 |
+
font-family:var(--serif-body);
|
| 808 |
+
font-size:15px;
|
| 809 |
+
line-height:1.55;
|
| 810 |
+
color:var(--ink-2);
|
| 811 |
+
margin:0;
|
| 812 |
+
padding:0;
|
| 813 |
+
list-style:none;
|
| 814 |
+
}
|
| 815 |
+
.colophon ul li{ padding:4px 0; }
|
| 816 |
+
.colophon ul li a{ border-bottom:1px solid var(--rule-soft); }
|
| 817 |
+
.colophon ul li a:hover{ color:var(--accent); border-bottom-color:var(--accent); }
|
| 818 |
+
.colophon .end{
|
| 819 |
+
grid-column:1/-1;
|
| 820 |
+
margin-top:24px;
|
| 821 |
+
padding-top:18px;
|
| 822 |
+
border-top:1px solid var(--rule);
|
| 823 |
+
display:flex; justify-content:space-between; gap:24px; flex-wrap:wrap;
|
| 824 |
+
font-family:var(--mono);
|
| 825 |
+
font-size:10.5px;
|
| 826 |
+
letter-spacing:.1em;
|
| 827 |
+
text-transform:uppercase;
|
| 828 |
+
color:var(--ink-mute);
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
/* focus */
|
| 832 |
+
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
|
| 833 |
+
|
| 834 |
+
/* ββ Card trigger line + deep-link anchor (v1.1) βββ */
|
| 835 |
+
.card .trigger{
|
| 836 |
+
font-family:var(--mono);
|
| 837 |
+
font-size:11px;
|
| 838 |
+
line-height:1.4;
|
| 839 |
+
color:var(--ink-mute);
|
| 840 |
+
margin:0 0 14px;
|
| 841 |
+
white-space:nowrap;
|
| 842 |
+
overflow:hidden;
|
| 843 |
+
text-overflow:ellipsis;
|
| 844 |
+
max-width:100%;
|
| 845 |
+
padding:6px 10px;
|
| 846 |
+
background: var(--paper-edge);
|
| 847 |
+
margin-left:-4px;
|
| 848 |
+
transition: background .14s ease, color .14s ease;
|
| 849 |
+
}
|
| 850 |
+
.card .trigger::before{ content:"β "; color:var(--accent); }
|
| 851 |
+
.card:hover .trigger{ background:var(--paper-2); }
|
| 852 |
+
.card.featured .trigger{
|
| 853 |
+
color:rgba(242,239,230,.55);
|
| 854 |
+
background:rgba(255,255,255,.06);
|
| 855 |
+
}
|
| 856 |
+
.card.featured:hover .trigger{ background:rgba(255,255,255,.1); }
|
| 857 |
+
|
| 858 |
+
/* Copy-hint badge that appears on trigger hover */
|
| 859 |
+
.copy-hint{
|
| 860 |
+
float:right; font-family:var(--mono); font-size:9px; letter-spacing:.06em;
|
| 861 |
+
text-transform:uppercase; color:var(--accent); opacity:0;
|
| 862 |
+
transition:opacity .15s ease; pointer-events:none; margin-left:8px;
|
| 863 |
+
white-space:nowrap;
|
| 864 |
+
}
|
| 865 |
+
.card .trigger:hover .copy-hint{ opacity:1; }
|
| 866 |
+
|
| 867 |
+
.card .top .id-wrap{ display:flex; align-items:baseline; gap:6px; }
|
| 868 |
+
.card .anchor{
|
| 869 |
+
font-family:var(--mono);
|
| 870 |
+
font-size:13px;
|
| 871 |
+
line-height:1;
|
| 872 |
+
color:var(--ink-mute);
|
| 873 |
+
padding:2px 4px;
|
| 874 |
+
border:1px solid transparent;
|
| 875 |
+
cursor:pointer;
|
| 876 |
+
opacity:0;
|
| 877 |
+
transition: opacity .14s ease, color .14s ease, background .14s ease;
|
| 878 |
+
}
|
| 879 |
+
.card:hover .anchor, .card:focus-within .anchor{ opacity:1; }
|
| 880 |
+
.card .anchor:hover{ color:var(--accent); border-color:var(--rule-soft); }
|
| 881 |
+
.card.featured .anchor{ color:rgba(242,239,230,.55); }
|
| 882 |
+
.card.featured .anchor:hover{ color:var(--highlight); border-color:rgba(242,239,230,.25); }
|
| 883 |
+
|
| 884 |
+
/* ββ Toast (deep-link copied) βββ */
|
| 885 |
+
.toast{
|
| 886 |
+
position:fixed; left:50%; bottom:36px; transform:translateX(-50%) translateY(20px);
|
| 887 |
+
background:var(--ink); color:var(--paper);
|
| 888 |
+
font-family:var(--mono); font-size:11px;
|
| 889 |
+
letter-spacing:.12em; text-transform:uppercase;
|
| 890 |
+
padding:12px 18px;
|
| 891 |
+
border:1px solid var(--ink);
|
| 892 |
+
box-shadow: 6px 6px 0 -1px var(--accent);
|
| 893 |
+
z-index:80;
|
| 894 |
+
opacity:0;
|
| 895 |
+
pointer-events:none;
|
| 896 |
+
transition: opacity .2s ease, transform .25s ease;
|
| 897 |
+
}
|
| 898 |
+
.toast.show{ opacity:1; transform:translateX(-50%) translateY(0); }
|
| 899 |
+
|
| 900 |
+
/* ββ Ecosystem deep-dive strip (v1.1) βββ */
|
| 901 |
+
.eco-strip{
|
| 902 |
+
display:grid;
|
| 903 |
+
grid-template-columns: repeat(4, 1fr);
|
| 904 |
+
border-top:1px solid var(--rule);
|
| 905 |
+
border-bottom:1px solid var(--rule);
|
| 906 |
+
margin-bottom:0;
|
| 907 |
+
}
|
| 908 |
+
@media (max-width: 900px){ .eco-strip{ grid-template-columns: repeat(2, 1fr); } }
|
| 909 |
+
@media (max-width: 540px){ .eco-strip{ grid-template-columns: 1fr; } }
|
| 910 |
+
|
| 911 |
+
/* Per-ecosystem colours on cells β generated by data.js ECO registry */
|
| 912 |
+
|
| 913 |
+
.eco-cell{
|
| 914 |
+
padding:26px 22px 22px;
|
| 915 |
+
border-right:1px solid var(--rule-soft);
|
| 916 |
+
background:var(--paper);
|
| 917 |
+
cursor:pointer;
|
| 918 |
+
display:flex; flex-direction:column;
|
| 919 |
+
min-height:200px;
|
| 920 |
+
transition: background .15s ease, box-shadow .18s ease;
|
| 921 |
+
position:relative;
|
| 922 |
+
box-shadow: inset 0 3px 0 var(--eco-color, var(--rule-soft));
|
| 923 |
+
}
|
| 924 |
+
.eco-cell:last-child{ border-right:0; }
|
| 925 |
+
.eco-cell:hover{
|
| 926 |
+
background:var(--paper-2);
|
| 927 |
+
box-shadow: inset 0 4px 0 var(--eco-color, var(--accent));
|
| 928 |
+
}
|
| 929 |
+
.eco-cell .eco-head{
|
| 930 |
+
display:flex; justify-content:space-between; align-items:flex-start;
|
| 931 |
+
margin-bottom:18px;
|
| 932 |
+
}
|
| 933 |
+
.eco-cell .eco-glyph{ width:44px; height:44px; }
|
| 934 |
+
.eco-cell .eco-glyph svg{ width:100%; height:100%; }
|
| 935 |
+
.eco-cell .eco-tag{
|
| 936 |
+
font-family:var(--mono);
|
| 937 |
+
font-size:10px;
|
| 938 |
+
letter-spacing:.12em;
|
| 939 |
+
text-transform:uppercase;
|
| 940 |
+
color:var(--ink-mute);
|
| 941 |
+
text-align:right;
|
| 942 |
+
line-height:1.5;
|
| 943 |
+
}
|
| 944 |
+
.eco-cell .eco-tag b{ color:var(--accent); font-weight:500; font-family:var(--serif-display); font-size:34px; letter-spacing:-.02em; display:block; line-height:.9; margin-bottom:4px; }
|
| 945 |
+
.eco-cell .eco-name{
|
| 946 |
+
font-family:var(--serif-display);
|
| 947 |
+
font-weight:400;
|
| 948 |
+
font-size: clamp(22px, 2.8vw, 34px);
|
| 949 |
+
line-height:1.05;
|
| 950 |
+
letter-spacing:-.01em;
|
| 951 |
+
margin:0 0 8px;
|
| 952 |
+
overflow-wrap:break-word;
|
| 953 |
+
hyphens:auto;
|
| 954 |
+
}
|
| 955 |
+
.eco-cell .eco-name .it{ font-style:italic; color:var(--accent); }
|
| 956 |
+
.eco-cell .eco-blurb{
|
| 957 |
+
font-family:var(--serif-body);
|
| 958 |
+
font-size:14.5px;
|
| 959 |
+
line-height:1.45;
|
| 960 |
+
color:var(--ink-2);
|
| 961 |
+
margin:0 0 16px;
|
| 962 |
+
text-wrap:pretty;
|
| 963 |
+
}
|
| 964 |
+
.eco-cell .eco-link{
|
| 965 |
+
margin-top:auto;
|
| 966 |
+
font-family:var(--mono);
|
| 967 |
+
font-size:10.5px;
|
| 968 |
+
letter-spacing:.1em;
|
| 969 |
+
text-transform:uppercase;
|
| 970 |
+
color:var(--ink);
|
| 971 |
+
padding-top:12px;
|
| 972 |
+
border-top:1px dotted var(--rule-soft);
|
| 973 |
+
}
|
| 974 |
+
.eco-cell:hover .eco-link{ color:var(--accent); }
|
| 975 |
+
|
| 976 |
+
/* inline code / backtick styling */
|
| 977 |
+
.inline-code{
|
| 978 |
+
font-family:var(--mono);
|
| 979 |
+
font-size:.88em;
|
| 980 |
+
background:var(--paper-2);
|
| 981 |
+
padding:1px 6px;
|
| 982 |
+
border-radius:3px;
|
| 983 |
+
color:var(--ink);
|
| 984 |
+
}
|
| 985 |
+
.trigger-sep{ color:var(--ink-mute); }
|
| 986 |
+
|
| 987 |
+
/* ββ Sort toggle (v1.1) βββ */
|
| 988 |
+
.sort-toggle{
|
| 989 |
+
display:inline-flex; gap:6px; align-items:center;
|
| 990 |
+
font-family:var(--mono);
|
| 991 |
+
font-size:10.5px;
|
| 992 |
+
letter-spacing:.1em;
|
| 993 |
+
text-transform:uppercase;
|
| 994 |
+
color:var(--ink-mute);
|
| 995 |
+
}
|
| 996 |
+
.sort-toggle a{
|
| 997 |
+
padding:2px 6px;
|
| 998 |
+
border:1px solid transparent;
|
| 999 |
+
cursor:pointer;
|
| 1000 |
+
color:var(--ink-mute);
|
| 1001 |
+
}
|
| 1002 |
+
.sort-toggle a.on{
|
| 1003 |
+
color:var(--accent);
|
| 1004 |
+
border-color:var(--rule-soft);
|
| 1005 |
+
}
|
| 1006 |
+
.sort-toggle a:hover{ color:var(--ink); }
|
| 1007 |
+
.sort-toggle a.on:hover{ color:var(--accent); }
|
| 1008 |
+
|
| 1009 |
+
/* ββ Shortcut modal (v1.1) β styled like a footnote card βββ */
|
| 1010 |
+
.shortcuts{
|
| 1011 |
+
position:fixed; right:24px; bottom:60px;
|
| 1012 |
+
z-index:60;
|
| 1013 |
+
width:340px; max-width:calc(100vw - 48px);
|
| 1014 |
+
background:var(--paper);
|
| 1015 |
+
border:1px solid var(--ink);
|
| 1016 |
+
box-shadow: 6px 6px 0 var(--accent), 10px 10px 0 -2px var(--ink);
|
| 1017 |
+
padding:22px 24px 20px;
|
| 1018 |
+
display:none;
|
| 1019 |
+
transform-origin: bottom right;
|
| 1020 |
+
}
|
| 1021 |
+
.shortcuts.open{ display:block; animation: pop .2s cubic-bezier(0.16,1,0.3,1); }
|
| 1022 |
+
@keyframes pop{ from{ opacity:0; transform: translateY(10px) scale(.96); } to{ opacity:1; transform:none; } }
|
| 1023 |
+
.shortcuts h6{
|
| 1024 |
+
font-family:var(--mono);
|
| 1025 |
+
font-size:10.5px;
|
| 1026 |
+
letter-spacing:.16em;
|
| 1027 |
+
text-transform:uppercase;
|
| 1028 |
+
color:var(--ink-mute);
|
| 1029 |
+
margin:0 0 4px;
|
| 1030 |
+
font-weight:500;
|
| 1031 |
+
}
|
| 1032 |
+
.shortcuts .ftitle{
|
| 1033 |
+
font-family:var(--serif-display);
|
| 1034 |
+
font-style:italic;
|
| 1035 |
+
font-size:24px;
|
| 1036 |
+
line-height:1;
|
| 1037 |
+
margin:0 0 16px;
|
| 1038 |
+
color:var(--ink);
|
| 1039 |
+
padding-bottom:12px;
|
| 1040 |
+
border-bottom:1px solid var(--rule);
|
| 1041 |
+
}
|
| 1042 |
+
.shortcuts .ftitle::before{ content:"ΒΉ "; color:var(--accent); }
|
| 1043 |
+
.shortcuts dl{ margin:0; display:grid; grid-template-columns: auto 1fr; gap:10px 14px; font-family:var(--serif-body); font-size:14.5px; color:var(--ink-2); }
|
| 1044 |
+
.shortcuts dt{ font-family:var(--mono); font-size:11px; border:1px solid var(--rule); padding:2px 8px; color:var(--ink); align-self:start; white-space:nowrap; }
|
| 1045 |
+
.shortcuts dd{ margin:0; line-height:1.35; align-self:center; }
|
| 1046 |
+
.shortcuts .closeFn{
|
| 1047 |
+
position:absolute; top:8px; right:10px;
|
| 1048 |
+
font-family:var(--mono); font-size:11px;
|
| 1049 |
+
color:var(--ink-mute);
|
| 1050 |
+
padding:4px 6px;
|
| 1051 |
+
}
|
| 1052 |
+
.shortcuts .closeFn:hover{ color:var(--accent); }
|
| 1053 |
+
.hint-key{
|
| 1054 |
+
position:fixed; right:18px; bottom:18px;
|
| 1055 |
+
z-index:55;
|
| 1056 |
+
font-family:var(--mono);
|
| 1057 |
+
font-size:11px;
|
| 1058 |
+
letter-spacing:.1em;
|
| 1059 |
+
text-transform:uppercase;
|
| 1060 |
+
color:var(--ink-mute);
|
| 1061 |
+
border:1px solid var(--rule);
|
| 1062 |
+
background:var(--paper);
|
| 1063 |
+
padding:6px 10px;
|
| 1064 |
+
cursor:pointer;
|
| 1065 |
+
}
|
| 1066 |
+
.hint-key:hover{ background:var(--ink); color:var(--paper); border-color:var(--ink); }
|
| 1067 |
+
.hint-key kbd{
|
| 1068 |
+
font:inherit;
|
| 1069 |
+
color:var(--accent);
|
| 1070 |
+
margin-right:4px;
|
| 1071 |
+
}
|
| 1072 |
+
.hint-key:hover kbd{ color:var(--highlight); }
|
| 1073 |
+
|
| 1074 |
+
/* ββ Hash-targeted card highlight βββ */
|
| 1075 |
+
.card.hashed{
|
| 1076 |
+
outline:2px solid var(--accent);
|
| 1077 |
+
outline-offset:-2px;
|
| 1078 |
+
}
|
| 1079 |
+
|
| 1080 |
+
/* ββ Print stylesheet (v1.1) βββ */
|
| 1081 |
+
@media print {
|
| 1082 |
+
@page { size: A4; margin: 18mm 16mm 20mm; }
|
| 1083 |
+
@page :left { @bottom-left { content: "SkillsAllYouNeed"; font-family: "JetBrains Mono", monospace; font-size:9pt; color:#666; } @bottom-right { content: counter(page) " / " counter(pages); font-family: "JetBrains Mono", monospace; font-size:9pt; color:#666; } }
|
| 1084 |
+
@page :right { @bottom-left { content: "kishormorol.github.io/SkillsAllYouNeed"; font-family: "JetBrains Mono", monospace; font-size:9pt; color:#666; } @bottom-right { content: counter(page) " / " counter(pages); font-family: "JetBrains Mono", monospace; font-size:9pt; color:#666; } }
|
| 1085 |
+
|
| 1086 |
+
html, body{ background:#fff !important; color:#111 !important; }
|
| 1087 |
+
body::before, body{ background-image: none !important; }
|
| 1088 |
+
.hero-nav, .filters, .hint-key, .shortcuts, .scrim, .toast, .eco-strip, .sort-toggle, .grid-toolbar, .active-filters{ display:none !important; }
|
| 1089 |
+
.section{ border-bottom:1px solid #111 !important; padding:18pt 0 !important; }
|
| 1090 |
+
.section-head{ break-after:avoid; }
|
| 1091 |
+
.grid{ display:block !important; border:0 !important; }
|
| 1092 |
+
.card{
|
| 1093 |
+
grid-column: 1 / -1 !important;
|
| 1094 |
+
display:block !important;
|
| 1095 |
+
break-inside: avoid;
|
| 1096 |
+
page-break-inside: avoid;
|
| 1097 |
+
border:0 !important;
|
| 1098 |
+
border-bottom:1px solid #111 !important;
|
| 1099 |
+
padding:14pt 0 !important;
|
| 1100 |
+
background:#fff !important;
|
| 1101 |
+
color:#111 !important;
|
| 1102 |
+
min-height:0 !important;
|
| 1103 |
+
opacity:1 !important; transform:none !important;
|
| 1104 |
+
}
|
| 1105 |
+
.card.featured, .card.featured *{ background:#fff !important; color:#111 !important; }
|
| 1106 |
+
.card .top{ margin-bottom:8pt; }
|
| 1107 |
+
.card .name{ font-size:24pt !important; margin-bottom:6pt; }
|
| 1108 |
+
.card .desc{ font-size:11pt !important; max-width:none !important; color:#222 !important; }
|
| 1109 |
+
.card .trigger{ white-space:normal !important; overflow:visible !important; font-size:10pt !important; color:#444 !important; margin-bottom:8pt; }
|
| 1110 |
+
.card::after{
|
| 1111 |
+
content: "Trigger: " attr(data-trigger) "\A Example: " attr(data-example) "\A Source: " attr(data-source);
|
| 1112 |
+
white-space: pre-line;
|
| 1113 |
+
display:block;
|
| 1114 |
+
font-family:"JetBrains Mono", monospace;
|
| 1115 |
+
font-size:9pt;
|
| 1116 |
+
line-height:1.45;
|
| 1117 |
+
color:#222;
|
| 1118 |
+
margin-top:8pt;
|
| 1119 |
+
padding-top:6pt;
|
| 1120 |
+
border-top:1px dotted #999;
|
| 1121 |
+
}
|
| 1122 |
+
.card .anchor, .card .bottom .status-dot{ display:none !important; }
|
| 1123 |
+
table.matrix{ min-width:0; table-layout:fixed; break-inside:avoid; font-size:6pt; }
|
| 1124 |
+
table.matrix thead th:first-child,
|
| 1125 |
+
table.matrix tbody th{ position:static; width:28%; min-width:0; }
|
| 1126 |
+
table.matrix thead th{ padding:4pt 2pt !important; font-size:5pt !important; }
|
| 1127 |
+
table.matrix tbody td,
|
| 1128 |
+
table.matrix tbody th{ padding:4pt 2pt !important; font-size:6pt !important; }
|
| 1129 |
+
table.matrix .mark.partial{ padding:1pt 2pt; font-size:5pt; }
|
| 1130 |
+
a{ color:#111 !important; }
|
| 1131 |
+
a[href]:after{ content: " (" attr(href) ")"; font-family:"JetBrains Mono", monospace; font-size:8pt; color:#666; }
|
| 1132 |
+
.colophon{ break-before: page; }
|
| 1133 |
+
}
|
| 1134 |
+
|
| 1135 |
+
@media (max-width: 800px){
|
| 1136 |
+
.section-head{ grid-template-columns: 1fr; }
|
| 1137 |
+
.section-head .right{ display:none; }
|
| 1138 |
+
.hero-stats{ gap:28px; }
|
| 1139 |
+
}
|
| 1140 |
+
|
| 1141 |
+
/* ββ v1.2: Favorites Β· Counts Β· Nav Β· Export Β· Scroll-top βββ */
|
| 1142 |
+
|
| 1143 |
+
/* Chip count badge */
|
| 1144 |
+
.chip .badge{
|
| 1145 |
+
font-size:9px; font-family:var(--mono); color:var(--ink-mute);
|
| 1146 |
+
margin-left:5px; letter-spacing:0; vertical-align:middle; opacity:.75;
|
| 1147 |
+
}
|
| 1148 |
+
.chip[aria-pressed="true"] .badge{ color:rgba(242,239,230,.6); }
|
| 1149 |
+
|
| 1150 |
+
/* Favorite button on card */
|
| 1151 |
+
.card .fav-btn{
|
| 1152 |
+
font-size:15px; color:var(--ink-mute); padding:0 2px; line-height:1;
|
| 1153 |
+
flex-shrink:0; background:none; border:0; cursor:pointer;
|
| 1154 |
+
transition: color .14s ease, transform .15s ease;
|
| 1155 |
+
}
|
| 1156 |
+
.card .fav-btn:hover{ color:var(--accent); transform:scale(1.2); }
|
| 1157 |
+
.card .fav-btn.saved{ color:var(--accent); }
|
| 1158 |
+
.card.featured .fav-btn{ color:rgba(242,239,230,.4); }
|
| 1159 |
+
.card.featured .fav-btn.saved{ color:var(--highlight); }
|
| 1160 |
+
|
| 1161 |
+
/* Trigger line: click-to-copy hint */
|
| 1162 |
+
.card .trigger{ cursor:pointer; }
|
| 1163 |
+
.card .trigger:active{ opacity:.6; }
|
| 1164 |
+
|
| 1165 |
+
/* Active filters bar */
|
| 1166 |
+
.active-filters{
|
| 1167 |
+
display:flex; flex-wrap:wrap; gap:6px; align-items:center;
|
| 1168 |
+
padding:10px 0 0; font-family:var(--mono); font-size:10.5px;
|
| 1169 |
+
}
|
| 1170 |
+
.active-filters .af-label{
|
| 1171 |
+
color:var(--ink-mute); text-transform:uppercase; letter-spacing:.1em;
|
| 1172 |
+
white-space:nowrap; flex-shrink:0;
|
| 1173 |
+
}
|
| 1174 |
+
.active-filter-tag{
|
| 1175 |
+
display:inline-flex; align-items:center; gap:4px;
|
| 1176 |
+
padding:3px 9px 3px 10px; border:1px solid var(--accent); color:var(--accent);
|
| 1177 |
+
font-family:var(--mono); font-size:10px; letter-spacing:.06em;
|
| 1178 |
+
text-transform:uppercase; cursor:pointer; background:transparent;
|
| 1179 |
+
transition: background .12s ease, color .12s ease;
|
| 1180 |
+
}
|
| 1181 |
+
.active-filter-tag:hover{ background:var(--accent); color:var(--paper); }
|
| 1182 |
+
|
| 1183 |
+
/* Grid toolbar (surprise Β· saved Β· export) */
|
| 1184 |
+
.grid-toolbar{
|
| 1185 |
+
display:flex; gap:8px; align-items:center; flex-wrap:wrap;
|
| 1186 |
+
padding:14px 0; border-bottom:1px solid var(--rule-soft);
|
| 1187 |
+
}
|
| 1188 |
+
.grid-toolbar .spacer{ flex:1; min-width:8px; }
|
| 1189 |
+
|
| 1190 |
+
/* Sheet action buttons */
|
| 1191 |
+
.sheet-actions{
|
| 1192 |
+
display:flex; gap:8px; flex-wrap:wrap; margin-top:8px;
|
| 1193 |
+
}
|
| 1194 |
+
.sheet-actions button{
|
| 1195 |
+
font-family:var(--mono); font-size:10.5px; letter-spacing:.1em;
|
| 1196 |
+
text-transform:uppercase; border:1px solid var(--rule);
|
| 1197 |
+
padding:5px 11px; color:var(--ink-soft); cursor:pointer;
|
| 1198 |
+
background:transparent; transition: background .12s ease, color .12s ease;
|
| 1199 |
+
}
|
| 1200 |
+
.sheet-actions button:hover{ background:var(--ink); color:var(--paper); }
|
| 1201 |
+
.sheet-actions button.is-saved{ color:var(--accent); border-color:var(--accent); }
|
| 1202 |
+
.sheet-actions button.is-saved:hover{ background:var(--accent); color:var(--paper); }
|
| 1203 |
+
|
| 1204 |
+
/* Sheet prev/next navigation */
|
| 1205 |
+
.sheet-nav{
|
| 1206 |
+
display:flex; gap:8px; align-items:center;
|
| 1207 |
+
margin-top:24px; padding-top:14px; border-top:1px solid var(--rule);
|
| 1208 |
+
}
|
| 1209 |
+
.sheet-nav button{
|
| 1210 |
+
font-family:var(--mono); font-size:10.5px; letter-spacing:.1em;
|
| 1211 |
+
text-transform:uppercase; border:1px solid var(--rule);
|
| 1212 |
+
padding:5px 11px; color:var(--ink); cursor:pointer; background:transparent;
|
| 1213 |
+
transition: background .12s ease, color .12s ease;
|
| 1214 |
+
}
|
| 1215 |
+
.sheet-nav button:hover:not(:disabled){ background:var(--ink); color:var(--paper); }
|
| 1216 |
+
.sheet-nav button:disabled{ opacity:.25; cursor:not-allowed; }
|
| 1217 |
+
.sheet-nav .nav-pos{
|
| 1218 |
+
flex:1; text-align:center; font-family:var(--mono); font-size:10px;
|
| 1219 |
+
text-transform:uppercase; letter-spacing:.08em; color:var(--ink-mute);
|
| 1220 |
+
}
|
| 1221 |
+
|
| 1222 |
+
/* Related skills chips */
|
| 1223 |
+
.related-list{
|
| 1224 |
+
display:flex; flex-wrap:wrap; gap:8px; margin-top:6px;
|
| 1225 |
+
}
|
| 1226 |
+
.related-chip{
|
| 1227 |
+
font-family:var(--mono); font-size:10px; text-transform:uppercase;
|
| 1228 |
+
letter-spacing:.06em; padding:5px 10px;
|
| 1229 |
+
border:1px solid var(--rule); background:transparent;
|
| 1230 |
+
color:var(--ink-mute); cursor:pointer; transition:all .15s ease;
|
| 1231 |
+
border-radius:2px;
|
| 1232 |
+
}
|
| 1233 |
+
.related-chip:hover{
|
| 1234 |
+
background:var(--ink); color:var(--paper); border-color:var(--ink);
|
| 1235 |
+
}
|
| 1236 |
+
|
| 1237 |
+
/* Scroll-to-top (bottom-left, mirrors hint-key) */
|
| 1238 |
+
.scroll-top{
|
| 1239 |
+
position:fixed; left:18px; bottom:18px; z-index:55;
|
| 1240 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.1em;
|
| 1241 |
+
text-transform:uppercase; color:var(--ink-mute);
|
| 1242 |
+
border:1px solid var(--rule); background:var(--paper);
|
| 1243 |
+
padding:6px 10px; cursor:pointer;
|
| 1244 |
+
opacity:0; pointer-events:none; transition: opacity .2s ease;
|
| 1245 |
+
}
|
| 1246 |
+
.scroll-top.visible{ opacity:1; pointer-events:auto; }
|
| 1247 |
+
.scroll-top:hover{ background:var(--ink); color:var(--paper); border-color:var(--ink); }
|
| 1248 |
+
|
| 1249 |
+
@media print{
|
| 1250 |
+
.grid-toolbar, .scroll-top, .active-filters,
|
| 1251 |
+
.sheet-nav, .sheet-actions{ display:none !important; }
|
| 1252 |
+
}
|
| 1253 |
+
|
| 1254 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1255 |
+
DARK MODE
|
| 1256 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1257 |
+
[data-theme="dark"]{
|
| 1258 |
+
--paper: #17140F;
|
| 1259 |
+
--paper-rgb: 23, 20, 15;
|
| 1260 |
+
--paper-2: #1F1C14;
|
| 1261 |
+
--paper-edge:#252019;
|
| 1262 |
+
--ink: #F0EDE3;
|
| 1263 |
+
--ink-2: #D5D0C4;
|
| 1264 |
+
--ink-soft: #A8A296;
|
| 1265 |
+
--ink-mute: #6E6860;
|
| 1266 |
+
--rule: rgba(240,237,227,.28);
|
| 1267 |
+
--rule-soft: rgba(240,237,227,.10);
|
| 1268 |
+
--accent: #E05830;
|
| 1269 |
+
--highlight: #F5D77A;
|
| 1270 |
+
--eco-claude-code: #d97757;
|
| 1271 |
+
--eco-chatgpt: #3AAA6A;
|
| 1272 |
+
--eco-gemini: #7A5AE0;
|
| 1273 |
+
--eco-perplexity: #2DC4A8;
|
| 1274 |
+
--eco-copilot: #3B9FE8;
|
| 1275 |
+
--eco-opencode: #38C96E;
|
| 1276 |
+
--eco-cursor: #EDECEC;
|
| 1277 |
+
--eco-codex: #F59E0B;
|
| 1278 |
+
--eco-github-copilot: #8B949E;
|
| 1279 |
+
--eco-antigravity: #8AB4F8;
|
| 1280 |
+
--eco-kiro: #B76BFF;
|
| 1281 |
+
--eco-pi: #9BA4AE;
|
| 1282 |
+
}
|
| 1283 |
+
[data-theme="dark"] .card.featured{
|
| 1284 |
+
background: linear-gradient(150deg, #1F1C14 0%, #0D0B08 100%);
|
| 1285 |
+
color: var(--ink);
|
| 1286 |
+
}
|
| 1287 |
+
[data-theme="dark"] .card.featured .desc,
|
| 1288 |
+
[data-theme="dark"] .card.featured .id,
|
| 1289 |
+
[data-theme="dark"] .card.featured .eco-label{ color: var(--ink); }
|
| 1290 |
+
[data-theme="dark"] .card.featured .id{ opacity: .55; }
|
| 1291 |
+
[data-theme="dark"] .card.featured .trigger{ color: rgba(240,237,227,.55); }
|
| 1292 |
+
[data-theme="dark"] .card.featured .anchor{ color: rgba(240,237,227,.55); }
|
| 1293 |
+
[data-theme="dark"] .card.featured .meta-top{ color: var(--ink-soft); }
|
| 1294 |
+
[data-theme="dark"] .card.featured .cat{ color: rgba(240,237,227,.6); }
|
| 1295 |
+
[data-theme="dark"] .card.featured .status{ color: var(--ink-soft); }
|
| 1296 |
+
[data-theme="dark"] .card.featured .fav-btn{ color: rgba(240,237,227,.4); }
|
| 1297 |
+
[data-theme="dark"] .card.featured .glyph svg *{ stroke: var(--ink); }
|
| 1298 |
+
[data-theme="dark"] .search-wrap:focus-within{
|
| 1299 |
+
box-shadow: 0 0 0 3px rgba(224,88,48,.18), 4px 4px 0 var(--accent);
|
| 1300 |
+
}
|
| 1301 |
+
[data-theme="dark"] body{
|
| 1302 |
+
background-image: radial-gradient(rgba(240,237,227,.025) 1px, transparent 1px);
|
| 1303 |
+
}
|
| 1304 |
+
[data-theme="dark"] body::before{
|
| 1305 |
+
background:
|
| 1306 |
+
repeating-linear-gradient(0deg, rgba(240,237,227,.01) 0 1px, transparent 1px 3px),
|
| 1307 |
+
repeating-linear-gradient(90deg, rgba(240,237,227,.007) 0 1px, transparent 1px 4px);
|
| 1308 |
+
}
|
| 1309 |
+
[data-theme="dark"] .hero-body::before{
|
| 1310 |
+
background: radial-gradient(ellipse at 30% 50%, rgba(217,119,87,.12) 0%, transparent 70%);
|
| 1311 |
+
}
|
| 1312 |
+
/* dark-mode toggle button */
|
| 1313 |
+
.dark-toggle{
|
| 1314 |
+
font-size:15px; line-height:1; letter-spacing:0;
|
| 1315 |
+
color:var(--ink-soft); padding:1px 4px;
|
| 1316 |
+
border:none; background:none; cursor:pointer;
|
| 1317 |
+
transition:color .15s ease, transform .2s ease;
|
| 1318 |
+
font-family:inherit;
|
| 1319 |
+
}
|
| 1320 |
+
.dark-toggle:hover{ color:var(--accent); transform:rotate(18deg); }
|
| 1321 |
+
|
| 1322 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1323 |
+
ONBOARDING STRIP
|
| 1324 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1325 |
+
.onboarding-strip{
|
| 1326 |
+
background:var(--ink); color:var(--paper);
|
| 1327 |
+
border-bottom:1px solid var(--rule);
|
| 1328 |
+
display:none; /* shown by JS the first visit */
|
| 1329 |
+
position:relative; overflow:hidden;
|
| 1330 |
+
transition: opacity 180ms cubic-bezier(0.4, 0, 0.2, 1);
|
| 1331 |
+
}
|
| 1332 |
+
.onboarding-strip.is-leaving{ opacity:0; }
|
| 1333 |
+
/* vermillion hairline on the top edge of the dark band */
|
| 1334 |
+
.onboarding-strip::before{
|
| 1335 |
+
content:""; position:absolute; inset:0 0 auto 0; height:2px;
|
| 1336 |
+
background:var(--accent); opacity:.9;
|
| 1337 |
+
}
|
| 1338 |
+
.onboarding-inner{
|
| 1339 |
+
display:flex; align-items:center; gap:28px; flex-wrap:wrap;
|
| 1340 |
+
max-width:var(--grid-max); margin:0 auto;
|
| 1341 |
+
padding:20px var(--gutter);
|
| 1342 |
+
}
|
| 1343 |
+
.onboarding-title{
|
| 1344 |
+
font-family:var(--serif-display); font-style:italic;
|
| 1345 |
+
font-size:19px; white-space:nowrap; flex-shrink:0; line-height:1;
|
| 1346 |
+
}
|
| 1347 |
+
.onboarding-steps{
|
| 1348 |
+
display:flex; gap:22px; flex-wrap:wrap; flex:1;
|
| 1349 |
+
align-items:flex-start; min-width:0;
|
| 1350 |
+
}
|
| 1351 |
+
.onboarding-step{
|
| 1352 |
+
display:flex; align-items:baseline; gap:8px;
|
| 1353 |
+
font-family:var(--serif-body); font-size:14px;
|
| 1354 |
+
line-height:1.5; max-width:340px;
|
| 1355 |
+
color:rgba(var(--paper-rgb), .74);
|
| 1356 |
+
animation: onboarding-fade-up 360ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
| 1357 |
+
}
|
| 1358 |
+
.onboarding-step:nth-child(1){ animation-delay:60ms; }
|
| 1359 |
+
.onboarding-step:nth-child(2){ animation-delay:130ms; }
|
| 1360 |
+
.onboarding-step:nth-child(3){ animation-delay:200ms; }
|
| 1361 |
+
.step-num{
|
| 1362 |
+
font-family:var(--mono); font-size:10px; font-weight:600;
|
| 1363 |
+
background:var(--accent); color:var(--paper);
|
| 1364 |
+
width:18px; height:18px; flex-shrink:0;
|
| 1365 |
+
display:inline-flex; align-items:center; justify-content:center;
|
| 1366 |
+
transition: transform 220ms cubic-bezier(0.34, 1.45, 0.64, 1);
|
| 1367 |
+
}
|
| 1368 |
+
.onboarding-step:hover .step-num{ transform: scale(1.1) rotate(-4deg); }
|
| 1369 |
+
.onboarding-dismiss{
|
| 1370 |
+
font-family:var(--mono); font-size:10px; letter-spacing:.1em;
|
| 1371 |
+
text-transform:uppercase; color:rgba(var(--paper-rgb), .5);
|
| 1372 |
+
border:1px solid rgba(var(--paper-rgb), .22); padding:6px 12px;
|
| 1373 |
+
background:transparent; cursor:pointer; white-space:nowrap; flex-shrink:0;
|
| 1374 |
+
transition: color 180ms cubic-bezier(0.22, 1, 0.36, 1),
|
| 1375 |
+
border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
|
| 1376 |
+
background 180ms cubic-bezier(0.22, 1, 0.36, 1),
|
| 1377 |
+
transform 120ms cubic-bezier(0.22, 1, 0.36, 1);
|
| 1378 |
+
}
|
| 1379 |
+
.onboarding-dismiss:hover{
|
| 1380 |
+
color:rgba(var(--paper-rgb), .95);
|
| 1381 |
+
border-color:rgba(var(--paper-rgb), .55);
|
| 1382 |
+
background:rgba(var(--paper-rgb), .08);
|
| 1383 |
+
}
|
| 1384 |
+
.onboarding-dismiss:active{ transform: scale(0.96); }
|
| 1385 |
+
.onboarding-dismiss:focus-visible{
|
| 1386 |
+
outline:1px solid var(--accent); outline-offset:2px;
|
| 1387 |
+
}
|
| 1388 |
+
@keyframes onboarding-fade-up{
|
| 1389 |
+
from{ opacity:0; transform:translateY(6px); }
|
| 1390 |
+
to { opacity:1; transform:translateY(0); }
|
| 1391 |
+
}
|
| 1392 |
+
@media (prefers-reduced-motion: reduce){
|
| 1393 |
+
.onboarding-strip{ transition:none; }
|
| 1394 |
+
.onboarding-step{ animation:none !important; }
|
| 1395 |
+
.onboarding-step:hover .step-num{ transform:none; }
|
| 1396 |
+
.onboarding-dismiss:active{ transform:none; }
|
| 1397 |
+
}
|
| 1398 |
+
@media(max-width:700px){
|
| 1399 |
+
.onboarding-inner{
|
| 1400 |
+
align-items:stretch;
|
| 1401 |
+
flex-direction:column;
|
| 1402 |
+
gap:16px;
|
| 1403 |
+
}
|
| 1404 |
+
.onboarding-steps{
|
| 1405 |
+
flex-direction:column;
|
| 1406 |
+
gap:12px;
|
| 1407 |
+
}
|
| 1408 |
+
.onboarding-step{ max-width:none; }
|
| 1409 |
+
.onboarding-steps .onboarding-step:last-child{ display:none; }
|
| 1410 |
+
.onboarding-dismiss{ align-self:flex-start; }
|
| 1411 |
+
}
|
| 1412 |
+
|
| 1413 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1414 |
+
QUICK PRESET FILTERS
|
| 1415 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1416 |
+
.preset-row{
|
| 1417 |
+
padding-bottom:14px;
|
| 1418 |
+
border-bottom:1px solid var(--rule-soft);
|
| 1419 |
+
}
|
| 1420 |
+
.preset-btn{
|
| 1421 |
+
font-family:var(--mono); font-size:10.5px; letter-spacing:.08em;
|
| 1422 |
+
text-transform:uppercase; padding:5px 13px;
|
| 1423 |
+
border:1px solid var(--accent); color:var(--accent);
|
| 1424 |
+
background:transparent; cursor:pointer; border-radius:0;
|
| 1425 |
+
transition:background .12s ease, color .12s ease;
|
| 1426 |
+
}
|
| 1427 |
+
.preset-btn:hover, .preset-btn.active{
|
| 1428 |
+
background:var(--accent); color:var(--paper);
|
| 1429 |
+
}
|
| 1430 |
+
.preset-btn.preset-clear{
|
| 1431 |
+
border-color:var(--rule); color:var(--ink-mute);
|
| 1432 |
+
}
|
| 1433 |
+
.preset-btn.preset-clear:hover{
|
| 1434 |
+
background:var(--ink); color:var(--paper); border-color:var(--ink);
|
| 1435 |
+
}
|
| 1436 |
+
|
| 1437 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1438 |
+
NEW BADGE
|
| 1439 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1440 |
+
.new-badge{
|
| 1441 |
+
font-family:var(--mono); font-size:8.5px; text-transform:uppercase;
|
| 1442 |
+
letter-spacing:.05em; color:var(--paper); background:var(--accent);
|
| 1443 |
+
padding:1px 5px; margin-left:5px; vertical-align:middle;
|
| 1444 |
+
animation:pulse-new 2.6s ease-in-out infinite;
|
| 1445 |
+
}
|
| 1446 |
+
.card.featured .new-badge{ background:var(--highlight); color:var(--ink); }
|
| 1447 |
+
@keyframes pulse-new{
|
| 1448 |
+
0%,100%{ opacity:1; } 50%{ opacity:.6; }
|
| 1449 |
+
}
|
| 1450 |
+
|
| 1451 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1452 |
+
CATEGORY COLOR ACCENTS
|
| 1453 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1454 |
+
.cat[data-cat="Code"] { color:#2D7A4F; }
|
| 1455 |
+
.cat[data-cat="Web"] { color:#1A5F96; }
|
| 1456 |
+
.cat[data-cat="Visual"] { color:#7030A0; }
|
| 1457 |
+
.cat[data-cat="Agentic"] { color:var(--accent); }
|
| 1458 |
+
.cat[data-cat="Integration"] { color:#A0600A; }
|
| 1459 |
+
.cat[data-cat="API"] { color:#0A7A7A; }
|
| 1460 |
+
.cat[data-cat="Data"] { color:#1A6090; }
|
| 1461 |
+
.card.featured .cat{ color:rgba(242,239,230,.6) !important; }
|
| 1462 |
+
[data-theme="dark"] .cat[data-cat="Code"] { color:#5CB880; }
|
| 1463 |
+
[data-theme="dark"] .cat[data-cat="Web"] { color:#5AA8DC; }
|
| 1464 |
+
[data-theme="dark"] .cat[data-cat="Visual"] { color:#B07ACC; }
|
| 1465 |
+
[data-theme="dark"] .cat[data-cat="Integration"] { color:#CC9840; }
|
| 1466 |
+
[data-theme="dark"] .cat[data-cat="API"] { color:#40C0C0; }
|
| 1467 |
+
[data-theme="dark"] .cat[data-cat="Data"] { color:#5AAAD0; }
|
| 1468 |
+
|
| 1469 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1470 |
+
IMPROVED EMPTY STATE
|
| 1471 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1472 |
+
.no-results{
|
| 1473 |
+
grid-column:span 12; padding:72px 24px;
|
| 1474 |
+
text-align:center;
|
| 1475 |
+
font-family:var(--serif-display); font-style:italic;
|
| 1476 |
+
font-size:32px; color:var(--ink-mute);
|
| 1477 |
+
border-bottom:1px solid var(--rule);
|
| 1478 |
+
}
|
| 1479 |
+
.no-results small{
|
| 1480 |
+
display:block; font-family:var(--mono); font-style:normal;
|
| 1481 |
+
font-size:11px; text-transform:uppercase; letter-spacing:.12em;
|
| 1482 |
+
margin-top:12px; color:var(--ink-mute);
|
| 1483 |
+
}
|
| 1484 |
+
.no-results .nr-reset{
|
| 1485 |
+
display:inline-block; margin-top:20px;
|
| 1486 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.1em;
|
| 1487 |
+
text-transform:uppercase; padding:9px 18px;
|
| 1488 |
+
border:1px solid var(--rule); color:var(--ink-soft);
|
| 1489 |
+
background:transparent; cursor:pointer;
|
| 1490 |
+
transition:background .12s ease, color .12s ease;
|
| 1491 |
+
}
|
| 1492 |
+
.no-results .nr-reset:hover{ background:var(--ink); color:var(--paper); }
|
| 1493 |
+
|
| 1494 |
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1495 |
+
CARD HOVER GLYPH ANIMATION
|
| 1496 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1497 |
+
.card .glyph{ transition: transform .18s ease; }
|
| 1498 |
+
.card:hover .glyph{ transform: scale(1.12); }
|
| 1499 |
+
.card.featured:hover .glyph{ transform: scale(1.12); }
|
| 1500 |
+
|
| 1501 |
+
/* ββ Add Skill form βββ */
|
| 1502 |
+
.add-scrim{
|
| 1503 |
+
position:fixed; inset:0; background:rgba(21,19,14,.62);
|
| 1504 |
+
z-index:50; display:none; align-items:flex-start;
|
| 1505 |
+
justify-content:center; padding:48px 24px; overflow-y:auto;
|
| 1506 |
+
}
|
| 1507 |
+
.add-scrim.open{
|
| 1508 |
+
display:flex;
|
| 1509 |
+
animation: scrim-in .22s ease-out both;
|
| 1510 |
+
}
|
| 1511 |
+
.add-sheet{
|
| 1512 |
+
background:var(--paper); width:100%; max-width:680px;
|
| 1513 |
+
padding:48px 56px 48px; position:relative;
|
| 1514 |
+
border:1px solid var(--ink);
|
| 1515 |
+
box-shadow:8px 8px 0 var(--accent), 16px 16px 0 -2px var(--ink);
|
| 1516 |
+
animation: sheet-in .26s cubic-bezier(0.16,1,0.3,1) both;
|
| 1517 |
+
}
|
| 1518 |
+
@media(max-width:720px){ .add-sheet{ padding:36px 24px; box-shadow:4px 4px 0 var(--accent), 8px 8px 0 -2px var(--ink); } }
|
| 1519 |
+
.add-sheet h3{
|
| 1520 |
+
font-family:var(--serif-display); font-weight:400;
|
| 1521 |
+
font-size:clamp(36px,4vw,56px); line-height:1; letter-spacing:-.015em;
|
| 1522 |
+
margin:0 0 6px;
|
| 1523 |
+
}
|
| 1524 |
+
.add-sheet h3 .it{ font-style:italic; color:var(--accent); }
|
| 1525 |
+
.add-sheet .form-sub{
|
| 1526 |
+
font-family:var(--mono); font-size:11px; text-transform:uppercase;
|
| 1527 |
+
letter-spacing:.1em; color:var(--ink-mute); margin-bottom:28px;
|
| 1528 |
+
padding-bottom:18px; border-bottom:1px solid var(--rule);
|
| 1529 |
+
}
|
| 1530 |
+
.form-row{ display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; }
|
| 1531 |
+
.form-row.full{ grid-template-columns:1fr; }
|
| 1532 |
+
@media(max-width:540px){ .form-row{ grid-template-columns:1fr; } }
|
| 1533 |
+
.form-group{ display:flex; flex-direction:column; gap:5px; }
|
| 1534 |
+
.form-group label{
|
| 1535 |
+
font-family:var(--mono); font-size:10.5px; text-transform:uppercase;
|
| 1536 |
+
letter-spacing:.12em; color:var(--ink-mute);
|
| 1537 |
+
}
|
| 1538 |
+
.form-group input,.form-group select,.form-group textarea{
|
| 1539 |
+
font-family:var(--serif-body); font-size:16px;
|
| 1540 |
+
border:1px solid var(--rule); background:var(--paper);
|
| 1541 |
+
color:var(--ink); padding:10px 12px; outline:none;
|
| 1542 |
+
border-radius:0; -webkit-appearance:none; resize:vertical;
|
| 1543 |
+
}
|
| 1544 |
+
.form-group input:focus,.form-group select:focus,.form-group textarea:focus{
|
| 1545 |
+
border-color:var(--ink); box-shadow:3px 3px 0 -1px var(--ink);
|
| 1546 |
+
}
|
| 1547 |
+
.form-group .id-preview{
|
| 1548 |
+
font-family:var(--mono); font-size:11px; color:var(--ink-mute); margin-top:2px;
|
| 1549 |
+
}
|
| 1550 |
+
.form-group .id-preview b{ color:var(--accent); }
|
| 1551 |
+
.form-actions{ display:flex; gap:10px; margin-top:24px; padding-top:18px; border-top:1px solid var(--rule); flex-wrap:wrap; }
|
| 1552 |
+
.btn-primary{
|
| 1553 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.1em;
|
| 1554 |
+
text-transform:uppercase; padding:10px 20px;
|
| 1555 |
+
background:var(--ink); color:var(--paper); border:1px solid var(--ink);
|
| 1556 |
+
cursor:pointer; transition:background .12s ease, border-color .12s ease;
|
| 1557 |
+
}
|
| 1558 |
+
.btn-primary:hover{ background:var(--accent); border-color:var(--accent); }
|
| 1559 |
+
.btn-ghost{
|
| 1560 |
+
font-family:var(--mono); font-size:11px; letter-spacing:.1em;
|
| 1561 |
+
text-transform:uppercase; padding:10px 20px;
|
| 1562 |
+
background:transparent; color:var(--ink-soft); border:1px solid var(--rule);
|
| 1563 |
+
cursor:pointer; transition:background .12s ease, color .12s ease;
|
| 1564 |
+
}
|
| 1565 |
+
.btn-ghost:hover{ background:var(--ink); color:var(--paper); }
|
| 1566 |
+
.custom-badge{
|
| 1567 |
+
font-family:var(--mono); font-size:9px; text-transform:uppercase;
|
| 1568 |
+
letter-spacing:.06em; color:var(--paper); background:var(--accent);
|
| 1569 |
+
padding:1px 5px; margin-left:6px; vertical-align:middle;
|
| 1570 |
+
}
|
| 1571 |
+
.card.featured .custom-badge{ background:var(--highlight); color:var(--ink); }
|
| 1572 |
+
.sheet-actions button.is-delete{ color:var(--ink-mute); }
|
| 1573 |
+
.sheet-actions button.is-delete:hover{ background:var(--accent); color:var(--paper); border-color:var(--accent); }
|