fernwell 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ /*! fernwell v0.1.0 | MIT | https://github.com/JacobKnaack/fernwell */
2
+ var Me=Object.defineProperty;var E=(e,t)=>{for(var n in t)Me(e,n,{get:t[n],enumerable:!0})};var N={};E(N,{get:()=>B,getToken:()=>Ce,init:()=>C,resetTokens:()=>Be,set:()=>M,setTokens:()=>Se,toggle:()=>ue});var O="fw-theme",He="fw:themechange",Ae="--fw-",le="data-fw-tokens";function S(){try{return window.localStorage}catch{return null}}function B(){var t;let e=document.documentElement.getAttribute("data-theme");return e==="dark"||e==="light"?e:(t=window.matchMedia)!=null&&t.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light"}function M(e,{persist:t=!0}={}){var n;document.documentElement.setAttribute("data-theme",e),t&&((n=S())==null||n.setItem(O,e)),document.querySelectorAll("[data-fw-theme-toggle]").forEach(o=>fe(o,e)),document.dispatchEvent(new CustomEvent(He,{detail:e}))}function ue(){let e=B()==="dark"?"light":"dark";return M(e),e}function fe(e,t){e.setAttribute("aria-pressed",String(t==="dark"));let n=t==="dark"?e.dataset.fwThemeLabelDark:e.dataset.fwThemeLabelLight;n!==void 0&&(e.textContent=n)}function C(e=document){var o,s,i,a;let t=(o=S())==null?void 0:o.getItem(O),n=t==="dark"||t==="light"?t:B();M(n,{persist:!1}),e.querySelectorAll("[data-fw-theme-toggle]").forEach(u=>{u.dataset.fwBound||(u.dataset.fwBound="1",fe(u,n),u.addEventListener("click",()=>ue()))}),(a=(s=window.matchMedia)==null?void 0:(i=s.call(window,"(prefers-color-scheme: dark)")).addEventListener)==null||a.call(i,"change",u=>{var w;(w=S())!=null&&w.getItem(O)||M(u.matches?"dark":"light",{persist:!1})})}var L=new Map;function me(e){return e.startsWith("--")?e:`${Ae}${e}`}function Oe(e){return Object.values(e).some(t=>t!==null&&typeof t=="object")}function ce(e){return Object.entries(e).map(([t,n])=>`${me(t)}:${n};`).join("")}function de(e){let t=document.head.querySelector(`style[${le}]`);if(t||!e)return t;let n=document.createElement("style");return n.setAttribute(le,""),document.head.appendChild(n),n}function pe(){var t;if(L.size===0){(t=de(!1))==null||t.remove();return}let e=[];L.forEach(({light:n,dark:o},s)=>{if(Object.keys(n).length&&e.push(`${s}{${ce(n)}}`),Object.keys(o).length){let i=s===":root"?'[data-theme="dark"]':`[data-theme="dark"] ${s}, ${s}[data-theme="dark"]`;e.push(`${i}{${ce(o)}}`)}}),de(!0).textContent=e.join(`
3
+ `)}function Se(e,t={}){var s,i;let n=(s=t.scope)!=null?s:":root",o=(i=L.get(n))!=null?i:{light:{},dark:{}};Oe(e)?(Object.assign(o.light,e.light),Object.assign(o.dark,e.dark)):(Object.assign(o.light,e),Object.assign(o.dark,e)),L.set(n,o),pe()}function Be(e){e?L.delete(e):L.clear(),pe()}function Ce(e,t=document.documentElement){return getComputedStyle(t).getPropertyValue(me(e)).trim()}var q={};E(q,{combobox:()=>ve,init:()=>$});var Ne=0;function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function ve(e,t={}){var se,re,ie,ae;let n=(se=t.filter)!=null?se:((r,l)=>r.toLowerCase().includes(l)),o=(re=t.emptyText)!=null?re:"No matches",s=(ie=t.options)!=null?ie:$e(e),i=[],a=-1,u=!1,w=e.getAttribute("list");w&&(e.dataset.fwList=w,e.removeAttribute("list"));let X=(ae=e.closest(".fw-combobox"))!=null?ae:qe(e),c=document.createElement("ul"),A=`fw-combobox-${++Ne}`;c.className="fw-combobox-list",c.id=A,c.setAttribute("role","listbox"),X.appendChild(c),e.setAttribute("role","combobox"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("aria-expanded","false"),e.setAttribute("aria-controls",A),e.autocomplete="off";function ke(r){i=r,a=-1;let l=e.value.trim().toLowerCase();if(r.length===0){c.innerHTML=`<li class="fw-combobox-empty">${x(o)}</li>`;return}c.innerHTML=r.map((f,b)=>{let g=l?f.toLowerCase().indexOf(l):-1,ye=g>-1?`${x(f.slice(0,g))}<b>${x(f.slice(g,g+l.length))}</b>${x(f.slice(g+l.length))}`:x(f);return`<li class="fw-combobox-option" role="option" id="${A}-${b}" data-index="${b}" aria-selected="false">${ye}</li>`}).join("")}function h(){let r=e.value.trim().toLowerCase();ke(r?s.filter(l=>n(l,r)):s),c.classList.add("is-open"),e.setAttribute("aria-expanded","true")}function y(){c.classList.remove("is-open"),e.setAttribute("aria-expanded","false"),e.removeAttribute("aria-activedescendant"),a=-1}function J(r){let l=c.querySelectorAll(".fw-combobox-option");l.forEach(b=>{b.classList.remove("is-active"),b.setAttribute("aria-selected","false")});let f=l[r];f&&(f.classList.add("is-active"),f.setAttribute("aria-selected","true"),f.scrollIntoView({block:"nearest"}),e.setAttribute("aria-activedescendant",f.id)),a=r}function Q(r){var l;e.value=r,y(),u=!0,e.focus(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),u=!1,(l=t.onSelect)==null||l.call(t,r)}let Z=()=>{u||h()},ee=()=>{u||h()},te=r=>{r.key==="ArrowDown"?(r.preventDefault(),c.classList.contains("is-open")||h(),J(Math.min(a+1,i.length-1))):r.key==="ArrowUp"?(r.preventDefault(),J(Math.max(a-1,0))):r.key==="Enter"?a>-1&&i[a]!==void 0&&(r.preventDefault(),Q(i[a])):r.key==="Escape"&&y()},ne=r=>{let l=r.target.closest(".fw-combobox-option");l&&(r.preventDefault(),Q(i[Number(l.dataset.index)]))},oe=r=>{X.contains(r.target)||y()};return e.addEventListener("input",Z),e.addEventListener("focus",ee),e.addEventListener("keydown",te),c.addEventListener("mousedown",ne),document.addEventListener("click",oe),{open:h,close:y,setOptions(r){s=r,c.classList.contains("is-open")&&h()},destroy(){e.removeEventListener("input",Z),e.removeEventListener("focus",ee),e.removeEventListener("keydown",te),c.removeEventListener("mousedown",ne),document.removeEventListener("click",oe),c.remove(),e.dataset.fwList&&e.setAttribute("list",e.dataset.fwList),delete e.dataset.fwBound}}}function $e(e){var o;let t=(o=e.getAttribute("list"))!=null?o:e.dataset.fwList,n=t?document.getElementById(t):null;return n?Array.from(n.querySelectorAll("option")).map(s=>s.value||s.textContent||""):[]}function qe(e){var n;let t=document.createElement("div");return t.className="fw-combobox",(n=e.parentNode)==null||n.insertBefore(t,e),t.appendChild(e),t}function $(e=document){e.querySelectorAll("input[data-fw-combobox]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",ve(t))})}var V={};E(V,{bindOutsideClickToClose:()=>j,close:()=>m,init:()=>K,open:()=>F,toggle:()=>je});var p="is-open",Le="fw-scroll-lock",v=[],I=new WeakMap,Ie='a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function P(e){return typeof e=="string"?document.getElementById(e):e}function D(e){if(e.classList.contains("fw-modal-overlay"))return e;let t=e.id?document.querySelector(`[data-fw-drawer-overlay="${e.id}"]`):null;if(t)return t;let n=e.previousElementSibling;return n instanceof HTMLElement&&n.classList.contains("fw-drawer-overlay")?n:null}function F(e,t=(n=>(n=document.activeElement)!=null?n:null)()){var i;let o=P(e);if(!o||o.classList.contains(p))return;o.classList.add(p),(i=D(o))==null||i.classList.add(p),I.set(o,t),v.push(o),document.body.classList.add(Le),o.dispatchEvent(new CustomEvent("fw:open",{bubbles:!0}));let s=o.querySelector(Ie);s?s.focus({preventScroll:!0}):(o.hasAttribute("tabindex")||o.setAttribute("tabindex","-1"),o.focus({preventScroll:!0}))}function m(e){var o,s,i;let t=P(e);if(!t||!t.classList.contains(p))return;t.classList.remove(p),(o=D(t))==null||o.classList.remove(p);let n=v.indexOf(t);n>-1&&v.splice(n,1),v.length===0&&document.body.classList.remove(Le),t.dispatchEvent(new CustomEvent("fw:close",{bubbles:!0})),(i=(s=I.get(t))==null?void 0:s.focus)==null||i.call(s,{preventScroll:!0}),I.delete(t)}function je(e){let t=P(e);t&&(t.classList.contains(p)?m:F)(t)}function j(e,t){let n=!1;e.addEventListener("mousedown",o=>{n=o.target===e}),e.addEventListener("click",o=>{o.target===e&&n&&t()})}var Ee=!1;function K(e=document){e.querySelectorAll("[data-fw-open-modal], [data-fw-open-drawer]").forEach(t=>{var o,s;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=(s=(o=t.dataset.fwOpenModal)!=null?o:t.dataset.fwOpenDrawer)!=null?s:"";t.addEventListener("click",()=>F(n,t))}),e.querySelectorAll(".fw-modal-overlay").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",j(t,()=>m(t)),t.querySelectorAll("[data-fw-close-modal]").forEach(n=>n.addEventListener("click",()=>m(t))))}),e.querySelectorAll(".fw-drawer").forEach(t=>{if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=D(t);n&&j(n,()=>m(t)),t.querySelectorAll("[data-fw-close-drawer]").forEach(o=>o.addEventListener("click",()=>m(t)))}),Ee||(Ee=!0,document.addEventListener("keydown",t=>{t.key==="Escape"&&v.length&&m(v[v.length-1])}))}var z={};E(z,{close:()=>H,init:()=>W,open:()=>Te});var R="is-open";function Te(e){let t=_(e);t&&(t.classList.add(R),e.setAttribute("aria-expanded","true"))}function H(e){let t=_(e);t&&(t.classList.remove(R),e.setAttribute("aria-expanded","false"))}function _(e){let t=e.getAttribute("aria-controls");return t?document.getElementById(t):null}function W(e=document){e.querySelectorAll("[data-fw-nav-toggle]").forEach(t=>{var s,i;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=_(t);if(!n)return;let o=(i=(s=t.closest(".fw-nav"))!=null?s:t.parentElement)!=null?i:t;t.addEventListener("click",a=>{a.stopPropagation(),(n.classList.contains(R)?H:Te)(t)}),document.addEventListener("click",a=>{!o.contains(a.target)&&!n.contains(a.target)&&H(t)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&H(t)})})}var U={};E(U,{init:()=>G,resetAll:()=>ge,resetButtonLoading:()=>be,setButtonLoading:()=>he});var k="fw-btn-loading";function he(e,t){var o,s;if(!e||e.classList.contains(k))return;e.dataset.fwOriginalHtml=e.innerHTML,e.disabled=!0,e.setAttribute("aria-busy","true"),e.classList.add(k);let n=(s=(o=t!=null?t:e.dataset.fwLoadingText)!=null?o:e.textContent)!=null?s:"";e.innerHTML='<span class="fw-spinner fw-spinner-sm" aria-hidden="true"></span>',e.appendChild(document.createTextNode(n))}function be(e){!e||!e.classList.contains(k)||(e.disabled=!1,e.removeAttribute("aria-busy"),e.classList.remove(k),e.dataset.fwOriginalHtml!==void 0&&(e.innerHTML=e.dataset.fwOriginalHtml,delete e.dataset.fwOriginalHtml))}function ge(e=document){e.querySelectorAll(`.${k}`).forEach(be)}var we=!1;function G(e=document){e.querySelectorAll("form[data-fw-loading]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",t.addEventListener("submit",()=>{let n=t.querySelector('button[type="submit"], button:not([type])');he(n)}))}),we||(we=!0,window.addEventListener("pageshow",t=>{t.persisted&&ge()}))}var Y={};E(Y,{hide:()=>xe,show:()=>De});var d=null,T=null;function Pe(){return d&&d.isConnected||(d=document.createElement("div"),d.className="fw-toast",d.setAttribute("role","status"),d.setAttribute("aria-live","polite"),d.innerHTML='<span class="fw-toast-dot" aria-hidden="true"></span><span class="fw-toast-text"></span>',document.body.appendChild(d)),d}function De(e,{variant:t="success",duration:n=4e3}={}){let o=Pe();return o.className=`fw-toast${t==="success"?"":` fw-toast-${t}`}`,o.querySelector(".fw-toast-text").textContent=e,T&&clearTimeout(T),o.classList.remove("is-show"),o.offsetWidth,o.classList.add("is-show"),n>0&&(T=setTimeout(xe,n)),o}function xe(){d==null||d.classList.remove("is-show"),T&&clearTimeout(T),T=null}var Fe="0.1.0";function Ke(e=document){C(e),$(e),K(e),W(e),G(e)}var Ve={version:Fe,init:Ke,theme:N,combobox:q,modal:V,nav:z,loading:U,toast:Y},_e=Ve;export{q as combobox,_e as default,Ke as init,U as loading,V as modal,z as nav,N as theme,Y as toast,Fe as version};
4
+ //# sourceMappingURL=fernwell.esm.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/js/theme.ts", "../src/js/combobox.ts", "../src/js/modal.ts", "../src/js/nav.ts", "../src/js/loading.ts", "../src/js/toast.ts", "../src/js/index.ts"],
4
+ "sourcesContent": ["/**\n * Theme \u2014 toggles `data-theme=\"dark\"` on <html>, remembers the choice, and\n * falls back to the OS preference. Also carries the runtime token API\n * (`setTokens` / `resetTokens` / `getToken`) for retheming Fernwell's colour\n * tokens on the fly \u2014 per-tenant branding, a user-picked accent, a live\n * preview \u2014 without touching a stylesheet.\n *\n * <button class=\"fw-btn fw-btn-ghost\" data-fw-theme-toggle\n * data-fw-theme-label-dark=\"\u2600\uFE0F Light\" data-fw-theme-label-light=\"\uD83C\uDF19 Dark\">\uD83C\uDF19 Dark</button>\n *\n * To avoid a flash of the wrong theme on load, inline this before your CSS:\n * <script>document.documentElement.dataset.theme=localStorage.getItem('fw-theme')||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light')</script>\n */\nexport type Theme = 'light' | 'dark';\n\nconst STORAGE_KEY = 'fw-theme';\nconst EVENT = 'fw:themechange';\nconst TOKEN_PREFIX = '--fw-';\nconst TOKEN_STYLE_ATTR = 'data-fw-tokens';\n\nfunction store(): Storage | null {\n try {\n return window.localStorage;\n } catch {\n return null;\n }\n}\n\n/** The theme currently applied to <html>, or the system preference if none is set. */\nexport function get(): Theme {\n const attr = document.documentElement.getAttribute('data-theme');\n if (attr === 'dark' || attr === 'light') return attr;\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\n/** Apply a theme, persist it, and update every toggle button on the page. */\nexport function set(theme: Theme, { persist = true }: { persist?: boolean } = {}): void {\n document.documentElement.setAttribute('data-theme', theme);\n if (persist) store()?.setItem(STORAGE_KEY, theme);\n document.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => syncToggle(btn, theme));\n document.dispatchEvent(new CustomEvent<Theme>(EVENT, { detail: theme }));\n}\n\nexport function toggle(): Theme {\n const next: Theme = get() === 'dark' ? 'light' : 'dark';\n set(next);\n return next;\n}\n\nfunction syncToggle(btn: HTMLElement, theme: Theme): void {\n btn.setAttribute('aria-pressed', String(theme === 'dark'));\n const label = theme === 'dark' ? btn.dataset.fwThemeLabelDark : btn.dataset.fwThemeLabelLight;\n if (label !== undefined) btn.textContent = label;\n}\n\n/** Apply the stored / system theme and wire every `[data-fw-theme-toggle]` under `root`. */\nexport function init(root: ParentNode = document): void {\n const stored = store()?.getItem(STORAGE_KEY);\n const current: Theme = stored === 'dark' || stored === 'light' ? stored : get();\n set(current, { persist: false });\n\n root.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n syncToggle(btn, current);\n btn.addEventListener('click', () => toggle());\n });\n\n // Follow the OS only while the user hasn't chosen explicitly.\n window.matchMedia?.('(prefers-color-scheme: dark)').addEventListener?.('change', (e) => {\n if (!store()?.getItem(STORAGE_KEY)) set(e.matches ? 'dark' : 'light', { persist: false });\n });\n}\n\n/* ---------------------------------------------------------------------- *\n * Runtime tokens \u2014 override any --fw-* custom property from JS, in both\n * themes or per-theme, scoped to :root or to any selector. Overrides render\n * into one <style data-fw-tokens> appended to <head>: being unlayered and\n * last, it wins over Fernwell's own @layer fw-tokens *and* any earlier\n * static override in the consumer's stylesheet.\n * ---------------------------------------------------------------------- */\n\n/** Token name \u2192 CSS value. Bare names (`primary`) and full names (`--fw-primary`) both work. */\nexport type TokenOverrides = Record<string, string>;\n\n/** Split form: set different values per theme instead of both at once. */\nexport interface TokenThemeOverrides {\n light?: TokenOverrides;\n dark?: TokenOverrides;\n}\n\ninterface ScopeTokens {\n light: TokenOverrides;\n dark: TokenOverrides;\n}\n\nconst tokenScopes = new Map<string, ScopeTokens>();\n\nfunction normalizeTokenName(name: string): string {\n return name.startsWith('--') ? name : `${TOKEN_PREFIX}${name}`;\n}\n\nfunction isThemeSplit(tokens: TokenOverrides | TokenThemeOverrides): tokens is TokenThemeOverrides {\n // A token's own value is always a CSS string \u2014 so any object-valued entry\n // means this is the { light, dark } split form, not a flat token map.\n return Object.values(tokens).some((v) => v !== null && typeof v === 'object');\n}\n\nfunction declBlock(tokens: TokenOverrides): string {\n return Object.entries(tokens)\n .map(([name, value]) => `${normalizeTokenName(name)}:${value};`)\n .join('');\n}\n\nfunction tokenStyleEl(create: boolean): HTMLStyleElement | null {\n const existing = document.head.querySelector<HTMLStyleElement>(`style[${TOKEN_STYLE_ATTR}]`);\n if (existing || !create) return existing;\n const el = document.createElement('style');\n el.setAttribute(TOKEN_STYLE_ATTR, '');\n document.head.appendChild(el);\n return el;\n}\n\nfunction renderTokens(): void {\n if (tokenScopes.size === 0) {\n tokenStyleEl(false)?.remove();\n return;\n }\n const rules: string[] = [];\n tokenScopes.forEach(({ light, dark }, scope) => {\n if (Object.keys(light).length) rules.push(`${scope}{${declBlock(light)}}`);\n if (Object.keys(dark).length) {\n const darkSelector =\n scope === ':root' ? '[data-theme=\"dark\"]' : `[data-theme=\"dark\"] ${scope}, ${scope}[data-theme=\"dark\"]`;\n rules.push(`${darkSelector}{${declBlock(dark)}}`);\n }\n });\n tokenStyleEl(true)!.textContent = rules.join('\\n');\n}\n\n/**\n * Override Fernwell design tokens at runtime \u2014 every derived token (hovers,\n * tints, focus ring, glows) follows automatically, in both themes:\n *\n * theme.setTokens({ primary: '#2266ff' });\n *\n * Pass `{ light, dark }` to set different values per theme, and `scope` to\n * theme a subtree instead of the whole page:\n *\n * theme.setTokens({ light: { primary: '#2266ff' }, dark: { primary: '#5c9dff' } });\n * theme.setTokens({ secondary: '#a33' }, { scope: '.tenant-acme' });\n *\n * Calls accumulate (merge into whatever overrides are already set for that\n * scope) \u2014 call `resetTokens()` to clear them.\n */\nexport function setTokens(tokens: TokenOverrides | TokenThemeOverrides, opts: { scope?: string } = {}): void {\n const scope = opts.scope ?? ':root';\n const entry = tokenScopes.get(scope) ?? { light: {}, dark: {} };\n if (isThemeSplit(tokens)) {\n Object.assign(entry.light, tokens.light);\n Object.assign(entry.dark, tokens.dark);\n } else {\n Object.assign(entry.light, tokens);\n Object.assign(entry.dark, tokens);\n }\n tokenScopes.set(scope, entry);\n renderTokens();\n}\n\n/** Clear runtime token overrides \u2014 for one `scope`, or every scope if omitted. */\nexport function resetTokens(scope?: string): void {\n if (scope) tokenScopes.delete(scope);\n else tokenScopes.clear();\n renderTokens();\n}\n\n/** The live, resolved value of a token (e.g. `getToken('primary')` \u2192 `'#ffc145'`), including runtime overrides. */\nexport function getToken(name: string, el: Element = document.documentElement): string {\n return getComputedStyle(el).getPropertyValue(normalizeTokenName(name)).trim();\n}\n", "/**\n * Combobox / typeahead \u2014 progressive enhancement over an <input> + <datalist>.\n *\n * <div class=\"fw-combobox\">\n * <input class=\"fw-input\" data-fw-combobox list=\"cities\" placeholder=\"Start typing\u2026\">\n * <datalist id=\"cities\"><option value=\"Seattle\"></option>\u2026</datalist>\n * </div>\n *\n * Or programmatically: combobox(input, { options: ['Seattle', \u2026], onSelect })\n */\nexport interface ComboboxOptions {\n /** Static option list. Defaults to the <datalist> the input's `list` attribute points at. */\n options?: string[];\n /** Filter function; default is case-insensitive substring match. */\n filter?: (option: string, query: string) => boolean;\n /** Text shown when nothing matches. */\n emptyText?: string;\n onSelect?: (value: string) => void;\n}\n\nexport interface ComboboxInstance {\n open(): void;\n close(): void;\n setOptions(options: string[]): void;\n destroy(): void;\n}\n\nlet uid = 0;\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c] as string);\n}\n\nexport function combobox(input: HTMLInputElement, opts: ComboboxOptions = {}): ComboboxInstance {\n const filter = opts.filter ?? ((o, q) => o.toLowerCase().includes(q));\n const emptyText = opts.emptyText ?? 'No matches';\n let options = opts.options ?? readDatalist(input);\n let current: string[] = [];\n let activeIndex = -1;\n let selecting = false;\n\n // The native datalist would double up with our list \u2014 detach it but keep\n // the options readable for setOptions()/no-JS fallbacks.\n const listId = input.getAttribute('list');\n if (listId) {\n input.dataset.fwList = listId;\n input.removeAttribute('list');\n }\n\n const wrap = input.closest('.fw-combobox') ?? wrapInput(input);\n const list = document.createElement('ul');\n const id = `fw-combobox-${++uid}`;\n list.className = 'fw-combobox-list';\n list.id = id;\n list.setAttribute('role', 'listbox');\n wrap.appendChild(list);\n\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', id);\n input.autocomplete = 'off';\n\n function render(matches: string[]): void {\n current = matches;\n activeIndex = -1;\n const q = input.value.trim().toLowerCase();\n if (matches.length === 0) {\n list.innerHTML = `<li class=\"fw-combobox-empty\">${escapeHtml(emptyText)}</li>`;\n return;\n }\n list.innerHTML = matches\n .map((opt, i) => {\n const idx = q ? opt.toLowerCase().indexOf(q) : -1;\n const label =\n idx > -1\n ? `${escapeHtml(opt.slice(0, idx))}<b>${escapeHtml(opt.slice(idx, idx + q.length))}</b>${escapeHtml(opt.slice(idx + q.length))}`\n : escapeHtml(opt);\n return `<li class=\"fw-combobox-option\" role=\"option\" id=\"${id}-${i}\" data-index=\"${i}\" aria-selected=\"false\">${label}</li>`;\n })\n .join('');\n }\n\n function open(): void {\n const q = input.value.trim().toLowerCase();\n render(q ? options.filter((o) => filter(o, q)) : options);\n list.classList.add('is-open');\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close(): void {\n list.classList.remove('is-open');\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n activeIndex = -1;\n }\n\n function highlight(i: number): void {\n const items = list.querySelectorAll<HTMLElement>('.fw-combobox-option');\n items.forEach((el) => {\n el.classList.remove('is-active');\n el.setAttribute('aria-selected', 'false');\n });\n const el = items[i];\n if (el) {\n el.classList.add('is-active');\n el.setAttribute('aria-selected', 'true');\n el.scrollIntoView({ block: 'nearest' });\n input.setAttribute('aria-activedescendant', el.id);\n }\n activeIndex = i;\n }\n\n function select(value: string): void {\n input.value = value;\n close();\n // The synthetic events below would re-open the list via onInput/onFocus.\n selecting = true;\n input.focus();\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n selecting = false;\n opts.onSelect?.(value);\n }\n\n const onInput = () => {\n if (!selecting) open();\n };\n const onFocus = () => {\n if (!selecting) open();\n };\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (!list.classList.contains('is-open')) open();\n highlight(Math.min(activeIndex + 1, current.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n highlight(Math.max(activeIndex - 1, 0));\n } else if (e.key === 'Enter') {\n if (activeIndex > -1 && current[activeIndex] !== undefined) {\n e.preventDefault();\n select(current[activeIndex]);\n }\n } else if (e.key === 'Escape') {\n close();\n }\n };\n const onListMousedown = (e: MouseEvent) => {\n const opt = (e.target as HTMLElement).closest<HTMLElement>('.fw-combobox-option');\n if (opt) {\n e.preventDefault(); // keep focus on the input\n select(current[Number(opt.dataset.index)]);\n }\n };\n const onDocClick = (e: MouseEvent) => {\n if (!wrap.contains(e.target as Node)) close();\n };\n\n input.addEventListener('input', onInput);\n input.addEventListener('focus', onFocus);\n input.addEventListener('keydown', onKeydown);\n list.addEventListener('mousedown', onListMousedown);\n document.addEventListener('click', onDocClick);\n\n return {\n open,\n close,\n setOptions(next) {\n options = next;\n if (list.classList.contains('is-open')) open();\n },\n destroy() {\n input.removeEventListener('input', onInput);\n input.removeEventListener('focus', onFocus);\n input.removeEventListener('keydown', onKeydown);\n list.removeEventListener('mousedown', onListMousedown);\n document.removeEventListener('click', onDocClick);\n list.remove();\n if (input.dataset.fwList) input.setAttribute('list', input.dataset.fwList);\n delete input.dataset.fwBound;\n },\n };\n}\n\nfunction readDatalist(input: HTMLInputElement): string[] {\n const id = input.getAttribute('list') ?? input.dataset.fwList;\n const dl = id ? document.getElementById(id) : null;\n return dl ? Array.from(dl.querySelectorAll('option')).map((o) => o.value || o.textContent || '') : [];\n}\n\nfunction wrapInput(input: HTMLInputElement): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'fw-combobox';\n input.parentNode?.insertBefore(wrap, input);\n wrap.appendChild(input);\n return wrap;\n}\n\n/** Enhance every `[data-fw-combobox]` input under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLInputElement>('input[data-fw-combobox]').forEach((input) => {\n if (input.dataset.fwBound) return;\n input.dataset.fwBound = '1';\n combobox(input);\n });\n}\n", "/**\n * Modal & drawer overlays.\n *\n * <button data-fw-open-modal=\"confirm\">\u2026</button>\n * <div class=\"fw-modal-overlay\" id=\"confirm\" role=\"dialog\" aria-modal=\"true\"><div class=\"fw-modal\">\u2026 <button data-fw-close-modal>Cancel</button></div></div>\n *\n * <button data-fw-open-drawer=\"details\">\u2026</button>\n * <div class=\"fw-drawer-overlay\" data-fw-drawer-overlay=\"details\"></div>\n * <aside class=\"fw-drawer\" id=\"details\" role=\"dialog\" aria-modal=\"true\">\u2026 <button data-fw-close-drawer>\u00D7</button></aside>\n *\n * Closes on backdrop click (guarded \u2014 a text-selection drag that ends on the\n * backdrop does NOT close it), on Escape, and returns focus to the opener.\n */\nconst OPEN = 'is-open';\nconst LOCK = 'fw-scroll-lock';\nconst openStack: HTMLElement[] = [];\nconst openers = new WeakMap<HTMLElement, HTMLElement | null>();\n\nconst FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction resolve(target: string | HTMLElement): HTMLElement | null {\n return typeof target === 'string' ? document.getElementById(target) : target;\n}\n\n/** The backdrop element paired with a drawer (via `data-fw-drawer-overlay=\"<id>\"`), if any. */\nfunction backdropFor(el: HTMLElement): HTMLElement | null {\n if (el.classList.contains('fw-modal-overlay')) return el;\n const explicit = el.id ? document.querySelector<HTMLElement>(`[data-fw-drawer-overlay=\"${el.id}\"]`) : null;\n if (explicit) return explicit;\n const prev = el.previousElementSibling;\n return prev instanceof HTMLElement && prev.classList.contains('fw-drawer-overlay') ? prev : null;\n}\n\nexport function open(target: string | HTMLElement, opener: HTMLElement | null = (document.activeElement as HTMLElement) ?? null): void {\n const el = resolve(target);\n if (!el || el.classList.contains(OPEN)) return;\n el.classList.add(OPEN);\n backdropFor(el)?.classList.add(OPEN);\n openers.set(el, opener);\n openStack.push(el);\n document.body.classList.add(LOCK);\n el.dispatchEvent(new CustomEvent('fw:open', { bubbles: true }));\n // Focus the first control inside; fall back to the panel itself.\n const first = el.querySelector<HTMLElement>(FOCUSABLE);\n if (first) first.focus({ preventScroll: true });\n else {\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n el.focus({ preventScroll: true });\n }\n}\n\nexport function close(target: string | HTMLElement): void {\n const el = resolve(target);\n if (!el || !el.classList.contains(OPEN)) return;\n el.classList.remove(OPEN);\n backdropFor(el)?.classList.remove(OPEN);\n const i = openStack.indexOf(el);\n if (i > -1) openStack.splice(i, 1);\n if (openStack.length === 0) document.body.classList.remove(LOCK);\n el.dispatchEvent(new CustomEvent('fw:close', { bubbles: true }));\n openers.get(el)?.focus?.({ preventScroll: true });\n openers.delete(el);\n}\n\nexport function toggle(target: string | HTMLElement): void {\n const el = resolve(target);\n if (el) (el.classList.contains(OPEN) ? close : open)(el);\n}\n\n/**\n * Click-outside-to-close, guarded against a classic false positive: a\n * browser's `click` fires on the nearest common ancestor of mousedown and\n * mouseup. A drag that starts inside the panel and ends on the backdrop has\n * the overlay as that ancestor, so a naive `e.target === overlay` check would\n * close the modal mid-selection. Close only when BOTH landed on the backdrop.\n */\nexport function bindOutsideClickToClose(backdrop: HTMLElement, onClose: () => void): void {\n let downOnBackdrop = false;\n backdrop.addEventListener('mousedown', (e) => {\n downOnBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && downOnBackdrop) onClose();\n });\n}\n\nlet keyBound = false;\n\n/** Wire every trigger, overlay and close button under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-open-modal], [data-fw-open-drawer]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n const id = btn.dataset.fwOpenModal ?? btn.dataset.fwOpenDrawer ?? '';\n btn.addEventListener('click', () => open(id, btn));\n });\n\n root.querySelectorAll<HTMLElement>('.fw-modal-overlay').forEach((overlay) => {\n if (overlay.dataset.fwBound) return;\n overlay.dataset.fwBound = '1';\n bindOutsideClickToClose(overlay, () => close(overlay));\n overlay.querySelectorAll<HTMLElement>('[data-fw-close-modal]').forEach((btn) =>\n btn.addEventListener('click', () => close(overlay)),\n );\n });\n\n root.querySelectorAll<HTMLElement>('.fw-drawer').forEach((drawer) => {\n if (drawer.dataset.fwBound) return;\n drawer.dataset.fwBound = '1';\n const backdrop = backdropFor(drawer);\n if (backdrop) bindOutsideClickToClose(backdrop, () => close(drawer));\n drawer.querySelectorAll<HTMLElement>('[data-fw-close-drawer]').forEach((btn) =>\n btn.addEventListener('click', () => close(drawer)),\n );\n });\n\n if (!keyBound) {\n keyBound = true;\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && openStack.length) close(openStack[openStack.length - 1]);\n });\n }\n}\n", "/**\n * Nav dropdown \u2014 the hamburger toggle in `.fw-nav` (and any other\n * button-controls-panel pair).\n *\n * <button data-fw-nav-toggle aria-controls=\"menu\" aria-expanded=\"false\">\u2026</button>\n * <div class=\"fw-nav-dropdown\" id=\"menu\">\u2026</div>\n *\n * Closes on outside click and Escape.\n */\nconst OPEN = 'is-open';\n\nexport function open(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.add(OPEN);\n toggle.setAttribute('aria-expanded', 'true');\n}\n\nexport function close(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.remove(OPEN);\n toggle.setAttribute('aria-expanded', 'false');\n}\n\nfunction panelFor(toggle: HTMLElement): HTMLElement | null {\n const id = toggle.getAttribute('aria-controls');\n return id ? document.getElementById(id) : null;\n}\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-nav-toggle]').forEach((toggle) => {\n if (toggle.dataset.fwBound) return;\n toggle.dataset.fwBound = '1';\n const panel = panelFor(toggle);\n if (!panel) return;\n const container = toggle.closest<HTMLElement>('.fw-nav') ?? toggle.parentElement ?? toggle;\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n (panel.classList.contains(OPEN) ? close : open)(toggle);\n });\n document.addEventListener('click', (e) => {\n if (!container.contains(e.target as Node) && !panel.contains(e.target as Node)) close(toggle);\n });\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') close(toggle);\n });\n });\n}\n", "/**\n * Loading states.\n *\n * loading.setButtonLoading(btn, 'Sending\u2026'); // disables, swaps in a spinner\n * loading.resetButtonLoading(btn); // restores original markup\n *\n * Or declaratively: any <form data-fw-loading> puts its submit button into the\n * loading state on submit (label from `data-fw-loading-text` on the button).\n */\nconst LOADING = 'fw-btn-loading';\n\nexport function setButtonLoading(btn: HTMLButtonElement | null, loadingText?: string): void {\n if (!btn || btn.classList.contains(LOADING)) return;\n btn.dataset.fwOriginalHtml = btn.innerHTML;\n btn.disabled = true;\n btn.setAttribute('aria-busy', 'true');\n btn.classList.add(LOADING);\n const label = loadingText ?? btn.dataset.fwLoadingText ?? btn.textContent ?? '';\n btn.innerHTML = '<span class=\"fw-spinner fw-spinner-sm\" aria-hidden=\"true\"></span>';\n btn.appendChild(document.createTextNode(label));\n}\n\nexport function resetButtonLoading(btn: HTMLButtonElement | null): void {\n if (!btn || !btn.classList.contains(LOADING)) return;\n btn.disabled = false;\n btn.removeAttribute('aria-busy');\n btn.classList.remove(LOADING);\n // Restore markup, not just text, so buttons with an icon keep it.\n if (btn.dataset.fwOriginalHtml !== undefined) {\n btn.innerHTML = btn.dataset.fwOriginalHtml;\n delete btn.dataset.fwOriginalHtml;\n }\n}\n\n/** Reset every loading button \u2014 e.g. after a bfcache restore. */\nexport function resetAll(root: ParentNode = document): void {\n root.querySelectorAll<HTMLButtonElement>(`.${LOADING}`).forEach(resetButtonLoading);\n}\n\nlet pageshowBound = false;\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLFormElement>('form[data-fw-loading]').forEach((form) => {\n if (form.dataset.fwBound) return;\n form.dataset.fwBound = '1';\n form.addEventListener('submit', () => {\n const btn = form.querySelector<HTMLButtonElement>('button[type=\"submit\"], button:not([type])');\n setButtonLoading(btn);\n });\n });\n\n // Browsers restore pages from the back-forward cache without re-running JS,\n // so a spinner painted right before navigating away would come back stuck.\n if (!pageshowBound) {\n pageshowBound = true;\n window.addEventListener('pageshow', (e) => {\n if (e.persisted) resetAll();\n });\n }\n}\n", "/**\n * Toast \u2014 a single, reused, bottom-right notice.\n *\n * toast.show('Invoice sent');\n * toast.show('That card was declined', { variant: 'error', duration: 6000 });\n */\nexport type ToastVariant = 'success' | 'error' | 'info' | 'pending';\n\nexport interface ToastOptions {\n variant?: ToastVariant;\n /** ms before it hides; 0 keeps it until `hide()` or the next `show()`. */\n duration?: number;\n}\n\nlet el: HTMLElement | null = null;\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensure(): HTMLElement {\n if (el && el.isConnected) return el;\n el = document.createElement('div');\n el.className = 'fw-toast';\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n el.innerHTML = '<span class=\"fw-toast-dot\" aria-hidden=\"true\"></span><span class=\"fw-toast-text\"></span>';\n document.body.appendChild(el);\n return el;\n}\n\nexport function show(message: string, { variant = 'success', duration = 4000 }: ToastOptions = {}): HTMLElement {\n const node = ensure();\n node.className = `fw-toast${variant === 'success' ? '' : ` fw-toast-${variant}`}`;\n (node.querySelector('.fw-toast-text') as HTMLElement).textContent = message;\n if (timer) clearTimeout(timer);\n // Re-trigger the transition even if it's already showing.\n node.classList.remove('is-show');\n void node.offsetWidth;\n node.classList.add('is-show');\n if (duration > 0) timer = setTimeout(hide, duration);\n return node;\n}\n\nexport function hide(): void {\n el?.classList.remove('is-show');\n if (timer) clearTimeout(timer);\n timer = null;\n}\n", "/**\n * Fernwell \u2014 vanilla JS enhancers for the Fernwell design system.\n *\n * ESM / CJS: import { init, theme, toast } from 'fernwell'; init();\n * <script>: <script src=\"https://unpkg.com/fernwell/dist/fernwell.iife.js\"></script>\n * \u2192 window.Fernwell, auto-initialised on DOMContentLoaded\n * (add data-fw-no-init to the <script> tag to opt out).\n */\nimport * as theme from './theme';\nimport * as combobox from './combobox';\nimport * as modal from './modal';\nimport * as nav from './nav';\nimport * as loading from './loading';\nimport * as toast from './toast';\n\nexport { theme, combobox, modal, nav, loading, toast };\nexport type { Theme, TokenOverrides, TokenThemeOverrides } from './theme';\nexport type { ComboboxOptions, ComboboxInstance } from './combobox';\nexport type { ToastVariant, ToastOptions } from './toast';\n\nexport const version = \"0.1.0\";\n\n/**\n * Wire every `data-fw-*` hook under `root`. Safe to call more than once \u2014\n * already-bound elements are skipped \u2014 so call it again after injecting\n * markup (e.g. after an HTMX / Turbo swap).\n */\nexport function init(root: ParentNode = document): void {\n theme.init(root);\n combobox.init(root);\n modal.init(root);\n nav.init(root);\n loading.init(root);\n}\n\nconst Fernwell = { version, init, theme, combobox, modal, nav, loading, toast };\nexport default Fernwell;\n"],
5
+ "mappings": "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",
6
+ "names": ["theme_exports", "__export", "get", "getToken", "init", "resetTokens", "set", "setTokens", "toggle", "STORAGE_KEY", "EVENT", "TOKEN_PREFIX", "TOKEN_STYLE_ATTR", "store", "_a", "attr", "theme", "persist", "btn", "syncToggle", "next", "label", "root", "_b", "_c", "_d", "stored", "current", "e", "tokenScopes", "normalizeTokenName", "name", "isThemeSplit", "tokens", "v", "declBlock", "value", "tokenStyleEl", "create", "existing", "el", "renderTokens", "rules", "light", "dark", "scope", "darkSelector", "opts", "entry", "combobox_exports", "__export", "combobox", "init", "uid", "escapeHtml", "s", "c", "input", "opts", "_a", "_b", "_c", "_d", "filter", "o", "q", "emptyText", "options", "readDatalist", "current", "activeIndex", "selecting", "listId", "wrap", "wrapInput", "list", "id", "render", "matches", "opt", "i", "idx", "label", "open", "close", "highlight", "items", "el", "select", "value", "onInput", "onFocus", "onKeydown", "e", "onListMousedown", "onDocClick", "next", "dl", "root", "modal_exports", "__export", "bindOutsideClickToClose", "close", "init", "open", "toggle", "OPEN", "LOCK", "openStack", "openers", "FOCUSABLE", "resolve", "target", "backdropFor", "el", "explicit", "prev", "opener", "_a", "first", "_b", "_c", "i", "backdrop", "onClose", "downOnBackdrop", "e", "keyBound", "root", "btn", "id", "overlay", "drawer", "nav_exports", "__export", "close", "init", "open", "OPEN", "toggle", "panel", "panelFor", "id", "root", "_a", "_b", "container", "e", "loading_exports", "__export", "init", "resetAll", "resetButtonLoading", "setButtonLoading", "LOADING", "btn", "loadingText", "_a", "_b", "label", "root", "pageshowBound", "form", "e", "toast_exports", "__export", "hide", "show", "el", "timer", "ensure", "message", "variant", "duration", "node", "version", "init", "root", "Fernwell", "theme_exports", "combobox_exports", "modal_exports", "nav_exports", "loading_exports", "toast_exports", "index_default"]
7
+ }
@@ -0,0 +1,5 @@
1
+ /*! fernwell v0.1.0 | MIT | https://github.com/JacobKnaack/fernwell */
2
+ "use strict";var Fernwell=(()=>{var I=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var Ne=Object.prototype.hasOwnProperty;var m=(e,t)=>{for(var n in t)I(e,n,{get:t[n],enumerable:!0})},$e=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Be(t))!Ne.call(e,s)&&s!==n&&I(e,s,{get:()=>t[s],enumerable:!(o=Ce(t,s))||o.enumerable});return e};var qe=e=>$e(I({},"__esModule",{value:!0}),e);var Xe={};m(Xe,{combobox:()=>O,default:()=>k,init:()=>He,loading:()=>N,modal:()=>S,nav:()=>B,theme:()=>A,toast:()=>$,version:()=>Me});var A={};m(A,{get:()=>D,getToken:()=>Ke,init:()=>F,resetTokens:()=>Fe,set:()=>H,setTokens:()=>De,toggle:()=>me});var j="fw-theme",Ie="fw:themechange",je="--fw-",ce="data-fw-tokens";function P(){try{return window.localStorage}catch{return null}}function D(){var t;let e=document.documentElement.getAttribute("data-theme");return e==="dark"||e==="light"?e:(t=window.matchMedia)!=null&&t.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light"}function H(e,{persist:t=!0}={}){var n;document.documentElement.setAttribute("data-theme",e),t&&((n=P())==null||n.setItem(j,e)),document.querySelectorAll("[data-fw-theme-toggle]").forEach(o=>pe(o,e)),document.dispatchEvent(new CustomEvent(Ie,{detail:e}))}function me(){let e=D()==="dark"?"light":"dark";return H(e),e}function pe(e,t){e.setAttribute("aria-pressed",String(t==="dark"));let n=t==="dark"?e.dataset.fwThemeLabelDark:e.dataset.fwThemeLabelLight;n!==void 0&&(e.textContent=n)}function F(e=document){var o,s,i,a;let t=(o=P())==null?void 0:o.getItem(j),n=t==="dark"||t==="light"?t:D();H(n,{persist:!1}),e.querySelectorAll("[data-fw-theme-toggle]").forEach(u=>{u.dataset.fwBound||(u.dataset.fwBound="1",pe(u,n),u.addEventListener("click",()=>me()))}),(a=(s=window.matchMedia)==null?void 0:(i=s.call(window,"(prefers-color-scheme: dark)")).addEventListener)==null||a.call(i,"change",u=>{var w;(w=P())!=null&&w.getItem(j)||H(u.matches?"dark":"light",{persist:!1})})}var L=new Map;function ve(e){return e.startsWith("--")?e:`${je}${e}`}function Pe(e){return Object.values(e).some(t=>t!==null&&typeof t=="object")}function ue(e){return Object.entries(e).map(([t,n])=>`${ve(t)}:${n};`).join("")}function fe(e){let t=document.head.querySelector(`style[${ce}]`);if(t||!e)return t;let n=document.createElement("style");return n.setAttribute(ce,""),document.head.appendChild(n),n}function Ee(){var t;if(L.size===0){(t=fe(!1))==null||t.remove();return}let e=[];L.forEach(({light:n,dark:o},s)=>{if(Object.keys(n).length&&e.push(`${s}{${ue(n)}}`),Object.keys(o).length){let i=s===":root"?'[data-theme="dark"]':`[data-theme="dark"] ${s}, ${s}[data-theme="dark"]`;e.push(`${i}{${ue(o)}}`)}}),fe(!0).textContent=e.join(`
3
+ `)}function De(e,t={}){var s,i;let n=(s=t.scope)!=null?s:":root",o=(i=L.get(n))!=null?i:{light:{},dark:{}};Pe(e)?(Object.assign(o.light,e.light),Object.assign(o.dark,e.dark)):(Object.assign(o.light,e),Object.assign(o.dark,e)),L.set(n,o),Ee()}function Fe(e){e?L.delete(e):L.clear(),Ee()}function Ke(e,t=document.documentElement){return getComputedStyle(t).getPropertyValue(ve(e)).trim()}var O={};m(O,{combobox:()=>Le,init:()=>K});var Ve=0;function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function Le(e,t={}){var ie,ae,le,de;let n=(ie=t.filter)!=null?ie:((r,l)=>r.toLowerCase().includes(l)),o=(ae=t.emptyText)!=null?ae:"No matches",s=(le=t.options)!=null?le:Re(e),i=[],a=-1,u=!1,w=e.getAttribute("list");w&&(e.dataset.fwList=w,e.removeAttribute("list"));let Q=(de=e.closest(".fw-combobox"))!=null?de:_e(e),d=document.createElement("ul"),q=`fw-combobox-${++Ve}`;d.className="fw-combobox-list",d.id=q,d.setAttribute("role","listbox"),Q.appendChild(d),e.setAttribute("role","combobox"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("aria-expanded","false"),e.setAttribute("aria-controls",q),e.autocomplete="off";function Oe(r){i=r,a=-1;let l=e.value.trim().toLowerCase();if(r.length===0){d.innerHTML=`<li class="fw-combobox-empty">${x(o)}</li>`;return}d.innerHTML=r.map((f,b)=>{let g=l?f.toLowerCase().indexOf(l):-1,Se=g>-1?`${x(f.slice(0,g))}<b>${x(f.slice(g,g+l.length))}</b>${x(f.slice(g+l.length))}`:x(f);return`<li class="fw-combobox-option" role="option" id="${q}-${b}" data-index="${b}" aria-selected="false">${Se}</li>`}).join("")}function h(){let r=e.value.trim().toLowerCase();Oe(r?s.filter(l=>n(l,r)):s),d.classList.add("is-open"),e.setAttribute("aria-expanded","true")}function M(){d.classList.remove("is-open"),e.setAttribute("aria-expanded","false"),e.removeAttribute("aria-activedescendant"),a=-1}function Z(r){let l=d.querySelectorAll(".fw-combobox-option");l.forEach(b=>{b.classList.remove("is-active"),b.setAttribute("aria-selected","false")});let f=l[r];f&&(f.classList.add("is-active"),f.setAttribute("aria-selected","true"),f.scrollIntoView({block:"nearest"}),e.setAttribute("aria-activedescendant",f.id)),a=r}function ee(r){var l;e.value=r,M(),u=!0,e.focus(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),u=!1,(l=t.onSelect)==null||l.call(t,r)}let te=()=>{u||h()},ne=()=>{u||h()},oe=r=>{r.key==="ArrowDown"?(r.preventDefault(),d.classList.contains("is-open")||h(),Z(Math.min(a+1,i.length-1))):r.key==="ArrowUp"?(r.preventDefault(),Z(Math.max(a-1,0))):r.key==="Enter"?a>-1&&i[a]!==void 0&&(r.preventDefault(),ee(i[a])):r.key==="Escape"&&M()},se=r=>{let l=r.target.closest(".fw-combobox-option");l&&(r.preventDefault(),ee(i[Number(l.dataset.index)]))},re=r=>{Q.contains(r.target)||M()};return e.addEventListener("input",te),e.addEventListener("focus",ne),e.addEventListener("keydown",oe),d.addEventListener("mousedown",se),document.addEventListener("click",re),{open:h,close:M,setOptions(r){s=r,d.classList.contains("is-open")&&h()},destroy(){e.removeEventListener("input",te),e.removeEventListener("focus",ne),e.removeEventListener("keydown",oe),d.removeEventListener("mousedown",se),document.removeEventListener("click",re),d.remove(),e.dataset.fwList&&e.setAttribute("list",e.dataset.fwList),delete e.dataset.fwBound}}}function Re(e){var o;let t=(o=e.getAttribute("list"))!=null?o:e.dataset.fwList,n=t?document.getElementById(t):null;return n?Array.from(n.querySelectorAll("option")).map(s=>s.value||s.textContent||""):[]}function _e(e){var n;let t=document.createElement("div");return t.className="fw-combobox",(n=e.parentNode)==null||n.insertBefore(t,e),t.appendChild(e),t}function K(e=document){e.querySelectorAll("input[data-fw-combobox]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",Le(t))})}var S={};m(S,{bindOutsideClickToClose:()=>R,close:()=>p,init:()=>G,open:()=>z,toggle:()=>ze});var v="is-open",we="fw-scroll-lock",E=[],V=new WeakMap,We='a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function _(e){return typeof e=="string"?document.getElementById(e):e}function W(e){if(e.classList.contains("fw-modal-overlay"))return e;let t=e.id?document.querySelector(`[data-fw-drawer-overlay="${e.id}"]`):null;if(t)return t;let n=e.previousElementSibling;return n instanceof HTMLElement&&n.classList.contains("fw-drawer-overlay")?n:null}function z(e,t=(n=>(n=document.activeElement)!=null?n:null)()){var i;let o=_(e);if(!o||o.classList.contains(v))return;o.classList.add(v),(i=W(o))==null||i.classList.add(v),V.set(o,t),E.push(o),document.body.classList.add(we),o.dispatchEvent(new CustomEvent("fw:open",{bubbles:!0}));let s=o.querySelector(We);s?s.focus({preventScroll:!0}):(o.hasAttribute("tabindex")||o.setAttribute("tabindex","-1"),o.focus({preventScroll:!0}))}function p(e){var o,s,i;let t=_(e);if(!t||!t.classList.contains(v))return;t.classList.remove(v),(o=W(t))==null||o.classList.remove(v);let n=E.indexOf(t);n>-1&&E.splice(n,1),E.length===0&&document.body.classList.remove(we),t.dispatchEvent(new CustomEvent("fw:close",{bubbles:!0})),(i=(s=V.get(t))==null?void 0:s.focus)==null||i.call(s,{preventScroll:!0}),V.delete(t)}function ze(e){let t=_(e);t&&(t.classList.contains(v)?p:z)(t)}function R(e,t){let n=!1;e.addEventListener("mousedown",o=>{n=o.target===e}),e.addEventListener("click",o=>{o.target===e&&n&&t()})}var Te=!1;function G(e=document){e.querySelectorAll("[data-fw-open-modal], [data-fw-open-drawer]").forEach(t=>{var o,s;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=(s=(o=t.dataset.fwOpenModal)!=null?o:t.dataset.fwOpenDrawer)!=null?s:"";t.addEventListener("click",()=>z(n,t))}),e.querySelectorAll(".fw-modal-overlay").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",R(t,()=>p(t)),t.querySelectorAll("[data-fw-close-modal]").forEach(n=>n.addEventListener("click",()=>p(t))))}),e.querySelectorAll(".fw-drawer").forEach(t=>{if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=W(t);n&&R(n,()=>p(t)),t.querySelectorAll("[data-fw-close-drawer]").forEach(o=>o.addEventListener("click",()=>p(t)))}),Te||(Te=!0,document.addEventListener("keydown",t=>{t.key==="Escape"&&E.length&&p(E[E.length-1])}))}var B={};m(B,{close:()=>C,init:()=>X,open:()=>he});var U="is-open";function he(e){let t=Y(e);t&&(t.classList.add(U),e.setAttribute("aria-expanded","true"))}function C(e){let t=Y(e);t&&(t.classList.remove(U),e.setAttribute("aria-expanded","false"))}function Y(e){let t=e.getAttribute("aria-controls");return t?document.getElementById(t):null}function X(e=document){e.querySelectorAll("[data-fw-nav-toggle]").forEach(t=>{var s,i;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=Y(t);if(!n)return;let o=(i=(s=t.closest(".fw-nav"))!=null?s:t.parentElement)!=null?i:t;t.addEventListener("click",a=>{a.stopPropagation(),(n.classList.contains(U)?C:he)(t)}),document.addEventListener("click",a=>{!o.contains(a.target)&&!n.contains(a.target)&&C(t)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&C(t)})})}var N={};m(N,{init:()=>J,resetAll:()=>ye,resetButtonLoading:()=>xe,setButtonLoading:()=>ge});var y="fw-btn-loading";function ge(e,t){var o,s;if(!e||e.classList.contains(y))return;e.dataset.fwOriginalHtml=e.innerHTML,e.disabled=!0,e.setAttribute("aria-busy","true"),e.classList.add(y);let n=(s=(o=t!=null?t:e.dataset.fwLoadingText)!=null?o:e.textContent)!=null?s:"";e.innerHTML='<span class="fw-spinner fw-spinner-sm" aria-hidden="true"></span>',e.appendChild(document.createTextNode(n))}function xe(e){!e||!e.classList.contains(y)||(e.disabled=!1,e.removeAttribute("aria-busy"),e.classList.remove(y),e.dataset.fwOriginalHtml!==void 0&&(e.innerHTML=e.dataset.fwOriginalHtml,delete e.dataset.fwOriginalHtml))}function ye(e=document){e.querySelectorAll(`.${y}`).forEach(xe)}var be=!1;function J(e=document){e.querySelectorAll("form[data-fw-loading]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",t.addEventListener("submit",()=>{let n=t.querySelector('button[type="submit"], button:not([type])');ge(n)}))}),be||(be=!0,window.addEventListener("pageshow",t=>{t.persisted&&ye()}))}var $={};m($,{hide:()=>ke,show:()=>Ue});var c=null,T=null;function Ge(){return c&&c.isConnected||(c=document.createElement("div"),c.className="fw-toast",c.setAttribute("role","status"),c.setAttribute("aria-live","polite"),c.innerHTML='<span class="fw-toast-dot" aria-hidden="true"></span><span class="fw-toast-text"></span>',document.body.appendChild(c)),c}function Ue(e,{variant:t="success",duration:n=4e3}={}){let o=Ge();return o.className=`fw-toast${t==="success"?"":` fw-toast-${t}`}`,o.querySelector(".fw-toast-text").textContent=e,T&&clearTimeout(T),o.classList.remove("is-show"),o.offsetWidth,o.classList.add("is-show"),n>0&&(T=setTimeout(ke,n)),o}function ke(){c==null||c.classList.remove("is-show"),T&&clearTimeout(T),T=null}var Me="0.1.0";function He(e=document){F(e),K(e),G(e),X(e),J(e)}var Ye={version:Me,init:He,theme:A,combobox:O,modal:S,nav:B,loading:N,toast:$},k=Ye;var Ae=typeof document!="undefined"?document.currentScript:null;typeof document!="undefined"&&!(Ae&&Ae.hasAttribute("data-fw-no-init"))&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>k.init()):k.init());return qe(Xe);})();
4
+ Fernwell=Fernwell.default;
5
+ //# sourceMappingURL=fernwell.iife.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/js/iife.ts", "../src/js/theme.ts", "../src/js/combobox.ts", "../src/js/modal.ts", "../src/js/nav.ts", "../src/js/loading.ts", "../src/js/toast.ts", "../src/js/index.ts"],
4
+ "sourcesContent": ["// Entry for the <script>-tag build: exposes window.Fernwell and auto-inits.\nimport Fernwell from './index';\n\nexport * from './index';\nexport { default } from './index';\n\nconst script = typeof document !== 'undefined' ? document.currentScript : null;\nif (typeof document !== 'undefined' && !(script && script.hasAttribute('data-fw-no-init'))) {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => Fernwell.init());\n } else {\n Fernwell.init();\n }\n}\n", "/**\n * Theme \u2014 toggles `data-theme=\"dark\"` on <html>, remembers the choice, and\n * falls back to the OS preference. Also carries the runtime token API\n * (`setTokens` / `resetTokens` / `getToken`) for retheming Fernwell's colour\n * tokens on the fly \u2014 per-tenant branding, a user-picked accent, a live\n * preview \u2014 without touching a stylesheet.\n *\n * <button class=\"fw-btn fw-btn-ghost\" data-fw-theme-toggle\n * data-fw-theme-label-dark=\"\u2600\uFE0F Light\" data-fw-theme-label-light=\"\uD83C\uDF19 Dark\">\uD83C\uDF19 Dark</button>\n *\n * To avoid a flash of the wrong theme on load, inline this before your CSS:\n * <script>document.documentElement.dataset.theme=localStorage.getItem('fw-theme')||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light')</script>\n */\nexport type Theme = 'light' | 'dark';\n\nconst STORAGE_KEY = 'fw-theme';\nconst EVENT = 'fw:themechange';\nconst TOKEN_PREFIX = '--fw-';\nconst TOKEN_STYLE_ATTR = 'data-fw-tokens';\n\nfunction store(): Storage | null {\n try {\n return window.localStorage;\n } catch {\n return null;\n }\n}\n\n/** The theme currently applied to <html>, or the system preference if none is set. */\nexport function get(): Theme {\n const attr = document.documentElement.getAttribute('data-theme');\n if (attr === 'dark' || attr === 'light') return attr;\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\n/** Apply a theme, persist it, and update every toggle button on the page. */\nexport function set(theme: Theme, { persist = true }: { persist?: boolean } = {}): void {\n document.documentElement.setAttribute('data-theme', theme);\n if (persist) store()?.setItem(STORAGE_KEY, theme);\n document.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => syncToggle(btn, theme));\n document.dispatchEvent(new CustomEvent<Theme>(EVENT, { detail: theme }));\n}\n\nexport function toggle(): Theme {\n const next: Theme = get() === 'dark' ? 'light' : 'dark';\n set(next);\n return next;\n}\n\nfunction syncToggle(btn: HTMLElement, theme: Theme): void {\n btn.setAttribute('aria-pressed', String(theme === 'dark'));\n const label = theme === 'dark' ? btn.dataset.fwThemeLabelDark : btn.dataset.fwThemeLabelLight;\n if (label !== undefined) btn.textContent = label;\n}\n\n/** Apply the stored / system theme and wire every `[data-fw-theme-toggle]` under `root`. */\nexport function init(root: ParentNode = document): void {\n const stored = store()?.getItem(STORAGE_KEY);\n const current: Theme = stored === 'dark' || stored === 'light' ? stored : get();\n set(current, { persist: false });\n\n root.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n syncToggle(btn, current);\n btn.addEventListener('click', () => toggle());\n });\n\n // Follow the OS only while the user hasn't chosen explicitly.\n window.matchMedia?.('(prefers-color-scheme: dark)').addEventListener?.('change', (e) => {\n if (!store()?.getItem(STORAGE_KEY)) set(e.matches ? 'dark' : 'light', { persist: false });\n });\n}\n\n/* ---------------------------------------------------------------------- *\n * Runtime tokens \u2014 override any --fw-* custom property from JS, in both\n * themes or per-theme, scoped to :root or to any selector. Overrides render\n * into one <style data-fw-tokens> appended to <head>: being unlayered and\n * last, it wins over Fernwell's own @layer fw-tokens *and* any earlier\n * static override in the consumer's stylesheet.\n * ---------------------------------------------------------------------- */\n\n/** Token name \u2192 CSS value. Bare names (`primary`) and full names (`--fw-primary`) both work. */\nexport type TokenOverrides = Record<string, string>;\n\n/** Split form: set different values per theme instead of both at once. */\nexport interface TokenThemeOverrides {\n light?: TokenOverrides;\n dark?: TokenOverrides;\n}\n\ninterface ScopeTokens {\n light: TokenOverrides;\n dark: TokenOverrides;\n}\n\nconst tokenScopes = new Map<string, ScopeTokens>();\n\nfunction normalizeTokenName(name: string): string {\n return name.startsWith('--') ? name : `${TOKEN_PREFIX}${name}`;\n}\n\nfunction isThemeSplit(tokens: TokenOverrides | TokenThemeOverrides): tokens is TokenThemeOverrides {\n // A token's own value is always a CSS string \u2014 so any object-valued entry\n // means this is the { light, dark } split form, not a flat token map.\n return Object.values(tokens).some((v) => v !== null && typeof v === 'object');\n}\n\nfunction declBlock(tokens: TokenOverrides): string {\n return Object.entries(tokens)\n .map(([name, value]) => `${normalizeTokenName(name)}:${value};`)\n .join('');\n}\n\nfunction tokenStyleEl(create: boolean): HTMLStyleElement | null {\n const existing = document.head.querySelector<HTMLStyleElement>(`style[${TOKEN_STYLE_ATTR}]`);\n if (existing || !create) return existing;\n const el = document.createElement('style');\n el.setAttribute(TOKEN_STYLE_ATTR, '');\n document.head.appendChild(el);\n return el;\n}\n\nfunction renderTokens(): void {\n if (tokenScopes.size === 0) {\n tokenStyleEl(false)?.remove();\n return;\n }\n const rules: string[] = [];\n tokenScopes.forEach(({ light, dark }, scope) => {\n if (Object.keys(light).length) rules.push(`${scope}{${declBlock(light)}}`);\n if (Object.keys(dark).length) {\n const darkSelector =\n scope === ':root' ? '[data-theme=\"dark\"]' : `[data-theme=\"dark\"] ${scope}, ${scope}[data-theme=\"dark\"]`;\n rules.push(`${darkSelector}{${declBlock(dark)}}`);\n }\n });\n tokenStyleEl(true)!.textContent = rules.join('\\n');\n}\n\n/**\n * Override Fernwell design tokens at runtime \u2014 every derived token (hovers,\n * tints, focus ring, glows) follows automatically, in both themes:\n *\n * theme.setTokens({ primary: '#2266ff' });\n *\n * Pass `{ light, dark }` to set different values per theme, and `scope` to\n * theme a subtree instead of the whole page:\n *\n * theme.setTokens({ light: { primary: '#2266ff' }, dark: { primary: '#5c9dff' } });\n * theme.setTokens({ secondary: '#a33' }, { scope: '.tenant-acme' });\n *\n * Calls accumulate (merge into whatever overrides are already set for that\n * scope) \u2014 call `resetTokens()` to clear them.\n */\nexport function setTokens(tokens: TokenOverrides | TokenThemeOverrides, opts: { scope?: string } = {}): void {\n const scope = opts.scope ?? ':root';\n const entry = tokenScopes.get(scope) ?? { light: {}, dark: {} };\n if (isThemeSplit(tokens)) {\n Object.assign(entry.light, tokens.light);\n Object.assign(entry.dark, tokens.dark);\n } else {\n Object.assign(entry.light, tokens);\n Object.assign(entry.dark, tokens);\n }\n tokenScopes.set(scope, entry);\n renderTokens();\n}\n\n/** Clear runtime token overrides \u2014 for one `scope`, or every scope if omitted. */\nexport function resetTokens(scope?: string): void {\n if (scope) tokenScopes.delete(scope);\n else tokenScopes.clear();\n renderTokens();\n}\n\n/** The live, resolved value of a token (e.g. `getToken('primary')` \u2192 `'#ffc145'`), including runtime overrides. */\nexport function getToken(name: string, el: Element = document.documentElement): string {\n return getComputedStyle(el).getPropertyValue(normalizeTokenName(name)).trim();\n}\n", "/**\n * Combobox / typeahead \u2014 progressive enhancement over an <input> + <datalist>.\n *\n * <div class=\"fw-combobox\">\n * <input class=\"fw-input\" data-fw-combobox list=\"cities\" placeholder=\"Start typing\u2026\">\n * <datalist id=\"cities\"><option value=\"Seattle\"></option>\u2026</datalist>\n * </div>\n *\n * Or programmatically: combobox(input, { options: ['Seattle', \u2026], onSelect })\n */\nexport interface ComboboxOptions {\n /** Static option list. Defaults to the <datalist> the input's `list` attribute points at. */\n options?: string[];\n /** Filter function; default is case-insensitive substring match. */\n filter?: (option: string, query: string) => boolean;\n /** Text shown when nothing matches. */\n emptyText?: string;\n onSelect?: (value: string) => void;\n}\n\nexport interface ComboboxInstance {\n open(): void;\n close(): void;\n setOptions(options: string[]): void;\n destroy(): void;\n}\n\nlet uid = 0;\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c] as string);\n}\n\nexport function combobox(input: HTMLInputElement, opts: ComboboxOptions = {}): ComboboxInstance {\n const filter = opts.filter ?? ((o, q) => o.toLowerCase().includes(q));\n const emptyText = opts.emptyText ?? 'No matches';\n let options = opts.options ?? readDatalist(input);\n let current: string[] = [];\n let activeIndex = -1;\n let selecting = false;\n\n // The native datalist would double up with our list \u2014 detach it but keep\n // the options readable for setOptions()/no-JS fallbacks.\n const listId = input.getAttribute('list');\n if (listId) {\n input.dataset.fwList = listId;\n input.removeAttribute('list');\n }\n\n const wrap = input.closest('.fw-combobox') ?? wrapInput(input);\n const list = document.createElement('ul');\n const id = `fw-combobox-${++uid}`;\n list.className = 'fw-combobox-list';\n list.id = id;\n list.setAttribute('role', 'listbox');\n wrap.appendChild(list);\n\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', id);\n input.autocomplete = 'off';\n\n function render(matches: string[]): void {\n current = matches;\n activeIndex = -1;\n const q = input.value.trim().toLowerCase();\n if (matches.length === 0) {\n list.innerHTML = `<li class=\"fw-combobox-empty\">${escapeHtml(emptyText)}</li>`;\n return;\n }\n list.innerHTML = matches\n .map((opt, i) => {\n const idx = q ? opt.toLowerCase().indexOf(q) : -1;\n const label =\n idx > -1\n ? `${escapeHtml(opt.slice(0, idx))}<b>${escapeHtml(opt.slice(idx, idx + q.length))}</b>${escapeHtml(opt.slice(idx + q.length))}`\n : escapeHtml(opt);\n return `<li class=\"fw-combobox-option\" role=\"option\" id=\"${id}-${i}\" data-index=\"${i}\" aria-selected=\"false\">${label}</li>`;\n })\n .join('');\n }\n\n function open(): void {\n const q = input.value.trim().toLowerCase();\n render(q ? options.filter((o) => filter(o, q)) : options);\n list.classList.add('is-open');\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close(): void {\n list.classList.remove('is-open');\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n activeIndex = -1;\n }\n\n function highlight(i: number): void {\n const items = list.querySelectorAll<HTMLElement>('.fw-combobox-option');\n items.forEach((el) => {\n el.classList.remove('is-active');\n el.setAttribute('aria-selected', 'false');\n });\n const el = items[i];\n if (el) {\n el.classList.add('is-active');\n el.setAttribute('aria-selected', 'true');\n el.scrollIntoView({ block: 'nearest' });\n input.setAttribute('aria-activedescendant', el.id);\n }\n activeIndex = i;\n }\n\n function select(value: string): void {\n input.value = value;\n close();\n // The synthetic events below would re-open the list via onInput/onFocus.\n selecting = true;\n input.focus();\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n selecting = false;\n opts.onSelect?.(value);\n }\n\n const onInput = () => {\n if (!selecting) open();\n };\n const onFocus = () => {\n if (!selecting) open();\n };\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (!list.classList.contains('is-open')) open();\n highlight(Math.min(activeIndex + 1, current.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n highlight(Math.max(activeIndex - 1, 0));\n } else if (e.key === 'Enter') {\n if (activeIndex > -1 && current[activeIndex] !== undefined) {\n e.preventDefault();\n select(current[activeIndex]);\n }\n } else if (e.key === 'Escape') {\n close();\n }\n };\n const onListMousedown = (e: MouseEvent) => {\n const opt = (e.target as HTMLElement).closest<HTMLElement>('.fw-combobox-option');\n if (opt) {\n e.preventDefault(); // keep focus on the input\n select(current[Number(opt.dataset.index)]);\n }\n };\n const onDocClick = (e: MouseEvent) => {\n if (!wrap.contains(e.target as Node)) close();\n };\n\n input.addEventListener('input', onInput);\n input.addEventListener('focus', onFocus);\n input.addEventListener('keydown', onKeydown);\n list.addEventListener('mousedown', onListMousedown);\n document.addEventListener('click', onDocClick);\n\n return {\n open,\n close,\n setOptions(next) {\n options = next;\n if (list.classList.contains('is-open')) open();\n },\n destroy() {\n input.removeEventListener('input', onInput);\n input.removeEventListener('focus', onFocus);\n input.removeEventListener('keydown', onKeydown);\n list.removeEventListener('mousedown', onListMousedown);\n document.removeEventListener('click', onDocClick);\n list.remove();\n if (input.dataset.fwList) input.setAttribute('list', input.dataset.fwList);\n delete input.dataset.fwBound;\n },\n };\n}\n\nfunction readDatalist(input: HTMLInputElement): string[] {\n const id = input.getAttribute('list') ?? input.dataset.fwList;\n const dl = id ? document.getElementById(id) : null;\n return dl ? Array.from(dl.querySelectorAll('option')).map((o) => o.value || o.textContent || '') : [];\n}\n\nfunction wrapInput(input: HTMLInputElement): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'fw-combobox';\n input.parentNode?.insertBefore(wrap, input);\n wrap.appendChild(input);\n return wrap;\n}\n\n/** Enhance every `[data-fw-combobox]` input under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLInputElement>('input[data-fw-combobox]').forEach((input) => {\n if (input.dataset.fwBound) return;\n input.dataset.fwBound = '1';\n combobox(input);\n });\n}\n", "/**\n * Modal & drawer overlays.\n *\n * <button data-fw-open-modal=\"confirm\">\u2026</button>\n * <div class=\"fw-modal-overlay\" id=\"confirm\" role=\"dialog\" aria-modal=\"true\"><div class=\"fw-modal\">\u2026 <button data-fw-close-modal>Cancel</button></div></div>\n *\n * <button data-fw-open-drawer=\"details\">\u2026</button>\n * <div class=\"fw-drawer-overlay\" data-fw-drawer-overlay=\"details\"></div>\n * <aside class=\"fw-drawer\" id=\"details\" role=\"dialog\" aria-modal=\"true\">\u2026 <button data-fw-close-drawer>\u00D7</button></aside>\n *\n * Closes on backdrop click (guarded \u2014 a text-selection drag that ends on the\n * backdrop does NOT close it), on Escape, and returns focus to the opener.\n */\nconst OPEN = 'is-open';\nconst LOCK = 'fw-scroll-lock';\nconst openStack: HTMLElement[] = [];\nconst openers = new WeakMap<HTMLElement, HTMLElement | null>();\n\nconst FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction resolve(target: string | HTMLElement): HTMLElement | null {\n return typeof target === 'string' ? document.getElementById(target) : target;\n}\n\n/** The backdrop element paired with a drawer (via `data-fw-drawer-overlay=\"<id>\"`), if any. */\nfunction backdropFor(el: HTMLElement): HTMLElement | null {\n if (el.classList.contains('fw-modal-overlay')) return el;\n const explicit = el.id ? document.querySelector<HTMLElement>(`[data-fw-drawer-overlay=\"${el.id}\"]`) : null;\n if (explicit) return explicit;\n const prev = el.previousElementSibling;\n return prev instanceof HTMLElement && prev.classList.contains('fw-drawer-overlay') ? prev : null;\n}\n\nexport function open(target: string | HTMLElement, opener: HTMLElement | null = (document.activeElement as HTMLElement) ?? null): void {\n const el = resolve(target);\n if (!el || el.classList.contains(OPEN)) return;\n el.classList.add(OPEN);\n backdropFor(el)?.classList.add(OPEN);\n openers.set(el, opener);\n openStack.push(el);\n document.body.classList.add(LOCK);\n el.dispatchEvent(new CustomEvent('fw:open', { bubbles: true }));\n // Focus the first control inside; fall back to the panel itself.\n const first = el.querySelector<HTMLElement>(FOCUSABLE);\n if (first) first.focus({ preventScroll: true });\n else {\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n el.focus({ preventScroll: true });\n }\n}\n\nexport function close(target: string | HTMLElement): void {\n const el = resolve(target);\n if (!el || !el.classList.contains(OPEN)) return;\n el.classList.remove(OPEN);\n backdropFor(el)?.classList.remove(OPEN);\n const i = openStack.indexOf(el);\n if (i > -1) openStack.splice(i, 1);\n if (openStack.length === 0) document.body.classList.remove(LOCK);\n el.dispatchEvent(new CustomEvent('fw:close', { bubbles: true }));\n openers.get(el)?.focus?.({ preventScroll: true });\n openers.delete(el);\n}\n\nexport function toggle(target: string | HTMLElement): void {\n const el = resolve(target);\n if (el) (el.classList.contains(OPEN) ? close : open)(el);\n}\n\n/**\n * Click-outside-to-close, guarded against a classic false positive: a\n * browser's `click` fires on the nearest common ancestor of mousedown and\n * mouseup. A drag that starts inside the panel and ends on the backdrop has\n * the overlay as that ancestor, so a naive `e.target === overlay` check would\n * close the modal mid-selection. Close only when BOTH landed on the backdrop.\n */\nexport function bindOutsideClickToClose(backdrop: HTMLElement, onClose: () => void): void {\n let downOnBackdrop = false;\n backdrop.addEventListener('mousedown', (e) => {\n downOnBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && downOnBackdrop) onClose();\n });\n}\n\nlet keyBound = false;\n\n/** Wire every trigger, overlay and close button under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-open-modal], [data-fw-open-drawer]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n const id = btn.dataset.fwOpenModal ?? btn.dataset.fwOpenDrawer ?? '';\n btn.addEventListener('click', () => open(id, btn));\n });\n\n root.querySelectorAll<HTMLElement>('.fw-modal-overlay').forEach((overlay) => {\n if (overlay.dataset.fwBound) return;\n overlay.dataset.fwBound = '1';\n bindOutsideClickToClose(overlay, () => close(overlay));\n overlay.querySelectorAll<HTMLElement>('[data-fw-close-modal]').forEach((btn) =>\n btn.addEventListener('click', () => close(overlay)),\n );\n });\n\n root.querySelectorAll<HTMLElement>('.fw-drawer').forEach((drawer) => {\n if (drawer.dataset.fwBound) return;\n drawer.dataset.fwBound = '1';\n const backdrop = backdropFor(drawer);\n if (backdrop) bindOutsideClickToClose(backdrop, () => close(drawer));\n drawer.querySelectorAll<HTMLElement>('[data-fw-close-drawer]').forEach((btn) =>\n btn.addEventListener('click', () => close(drawer)),\n );\n });\n\n if (!keyBound) {\n keyBound = true;\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && openStack.length) close(openStack[openStack.length - 1]);\n });\n }\n}\n", "/**\n * Nav dropdown \u2014 the hamburger toggle in `.fw-nav` (and any other\n * button-controls-panel pair).\n *\n * <button data-fw-nav-toggle aria-controls=\"menu\" aria-expanded=\"false\">\u2026</button>\n * <div class=\"fw-nav-dropdown\" id=\"menu\">\u2026</div>\n *\n * Closes on outside click and Escape.\n */\nconst OPEN = 'is-open';\n\nexport function open(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.add(OPEN);\n toggle.setAttribute('aria-expanded', 'true');\n}\n\nexport function close(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.remove(OPEN);\n toggle.setAttribute('aria-expanded', 'false');\n}\n\nfunction panelFor(toggle: HTMLElement): HTMLElement | null {\n const id = toggle.getAttribute('aria-controls');\n return id ? document.getElementById(id) : null;\n}\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-nav-toggle]').forEach((toggle) => {\n if (toggle.dataset.fwBound) return;\n toggle.dataset.fwBound = '1';\n const panel = panelFor(toggle);\n if (!panel) return;\n const container = toggle.closest<HTMLElement>('.fw-nav') ?? toggle.parentElement ?? toggle;\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n (panel.classList.contains(OPEN) ? close : open)(toggle);\n });\n document.addEventListener('click', (e) => {\n if (!container.contains(e.target as Node) && !panel.contains(e.target as Node)) close(toggle);\n });\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') close(toggle);\n });\n });\n}\n", "/**\n * Loading states.\n *\n * loading.setButtonLoading(btn, 'Sending\u2026'); // disables, swaps in a spinner\n * loading.resetButtonLoading(btn); // restores original markup\n *\n * Or declaratively: any <form data-fw-loading> puts its submit button into the\n * loading state on submit (label from `data-fw-loading-text` on the button).\n */\nconst LOADING = 'fw-btn-loading';\n\nexport function setButtonLoading(btn: HTMLButtonElement | null, loadingText?: string): void {\n if (!btn || btn.classList.contains(LOADING)) return;\n btn.dataset.fwOriginalHtml = btn.innerHTML;\n btn.disabled = true;\n btn.setAttribute('aria-busy', 'true');\n btn.classList.add(LOADING);\n const label = loadingText ?? btn.dataset.fwLoadingText ?? btn.textContent ?? '';\n btn.innerHTML = '<span class=\"fw-spinner fw-spinner-sm\" aria-hidden=\"true\"></span>';\n btn.appendChild(document.createTextNode(label));\n}\n\nexport function resetButtonLoading(btn: HTMLButtonElement | null): void {\n if (!btn || !btn.classList.contains(LOADING)) return;\n btn.disabled = false;\n btn.removeAttribute('aria-busy');\n btn.classList.remove(LOADING);\n // Restore markup, not just text, so buttons with an icon keep it.\n if (btn.dataset.fwOriginalHtml !== undefined) {\n btn.innerHTML = btn.dataset.fwOriginalHtml;\n delete btn.dataset.fwOriginalHtml;\n }\n}\n\n/** Reset every loading button \u2014 e.g. after a bfcache restore. */\nexport function resetAll(root: ParentNode = document): void {\n root.querySelectorAll<HTMLButtonElement>(`.${LOADING}`).forEach(resetButtonLoading);\n}\n\nlet pageshowBound = false;\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLFormElement>('form[data-fw-loading]').forEach((form) => {\n if (form.dataset.fwBound) return;\n form.dataset.fwBound = '1';\n form.addEventListener('submit', () => {\n const btn = form.querySelector<HTMLButtonElement>('button[type=\"submit\"], button:not([type])');\n setButtonLoading(btn);\n });\n });\n\n // Browsers restore pages from the back-forward cache without re-running JS,\n // so a spinner painted right before navigating away would come back stuck.\n if (!pageshowBound) {\n pageshowBound = true;\n window.addEventListener('pageshow', (e) => {\n if (e.persisted) resetAll();\n });\n }\n}\n", "/**\n * Toast \u2014 a single, reused, bottom-right notice.\n *\n * toast.show('Invoice sent');\n * toast.show('That card was declined', { variant: 'error', duration: 6000 });\n */\nexport type ToastVariant = 'success' | 'error' | 'info' | 'pending';\n\nexport interface ToastOptions {\n variant?: ToastVariant;\n /** ms before it hides; 0 keeps it until `hide()` or the next `show()`. */\n duration?: number;\n}\n\nlet el: HTMLElement | null = null;\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensure(): HTMLElement {\n if (el && el.isConnected) return el;\n el = document.createElement('div');\n el.className = 'fw-toast';\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n el.innerHTML = '<span class=\"fw-toast-dot\" aria-hidden=\"true\"></span><span class=\"fw-toast-text\"></span>';\n document.body.appendChild(el);\n return el;\n}\n\nexport function show(message: string, { variant = 'success', duration = 4000 }: ToastOptions = {}): HTMLElement {\n const node = ensure();\n node.className = `fw-toast${variant === 'success' ? '' : ` fw-toast-${variant}`}`;\n (node.querySelector('.fw-toast-text') as HTMLElement).textContent = message;\n if (timer) clearTimeout(timer);\n // Re-trigger the transition even if it's already showing.\n node.classList.remove('is-show');\n void node.offsetWidth;\n node.classList.add('is-show');\n if (duration > 0) timer = setTimeout(hide, duration);\n return node;\n}\n\nexport function hide(): void {\n el?.classList.remove('is-show');\n if (timer) clearTimeout(timer);\n timer = null;\n}\n", "/**\n * Fernwell \u2014 vanilla JS enhancers for the Fernwell design system.\n *\n * ESM / CJS: import { init, theme, toast } from 'fernwell'; init();\n * <script>: <script src=\"https://unpkg.com/fernwell/dist/fernwell.iife.js\"></script>\n * \u2192 window.Fernwell, auto-initialised on DOMContentLoaded\n * (add data-fw-no-init to the <script> tag to opt out).\n */\nimport * as theme from './theme';\nimport * as combobox from './combobox';\nimport * as modal from './modal';\nimport * as nav from './nav';\nimport * as loading from './loading';\nimport * as toast from './toast';\n\nexport { theme, combobox, modal, nav, loading, toast };\nexport type { Theme, TokenOverrides, TokenThemeOverrides } from './theme';\nexport type { ComboboxOptions, ComboboxInstance } from './combobox';\nexport type { ToastVariant, ToastOptions } from './toast';\n\nexport const version = \"0.1.0\";\n\n/**\n * Wire every `data-fw-*` hook under `root`. Safe to call more than once \u2014\n * already-bound elements are skipped \u2014 so call it again after injecting\n * markup (e.g. after an HTMX / Turbo swap).\n */\nexport function init(root: ParentNode = document): void {\n theme.init(root);\n combobox.init(root);\n modal.init(root);\n nav.init(root);\n loading.init(root);\n}\n\nconst Fernwell = { version, init, theme, combobox, modal, nav, loading, toast };\nexport default Fernwell;\n"],
5
+ "mappings": "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",
6
+ "names": ["iife_exports", "__export", "combobox_exports", "index_default", "init", "loading_exports", "modal_exports", "nav_exports", "theme_exports", "toast_exports", "version", "theme_exports", "__export", "get", "getToken", "init", "resetTokens", "set", "setTokens", "toggle", "STORAGE_KEY", "EVENT", "TOKEN_PREFIX", "TOKEN_STYLE_ATTR", "store", "_a", "attr", "theme", "persist", "btn", "syncToggle", "next", "label", "root", "_b", "_c", "_d", "stored", "current", "e", "tokenScopes", "normalizeTokenName", "name", "isThemeSplit", "tokens", "v", "declBlock", "value", "tokenStyleEl", "create", "existing", "el", "renderTokens", "rules", "light", "dark", "scope", "darkSelector", "opts", "entry", "combobox_exports", "__export", "combobox", "init", "uid", "escapeHtml", "s", "c", "input", "opts", "_a", "_b", "_c", "_d", "filter", "o", "q", "emptyText", "options", "readDatalist", "current", "activeIndex", "selecting", "listId", "wrap", "wrapInput", "list", "id", "render", "matches", "opt", "i", "idx", "label", "open", "close", "highlight", "items", "el", "select", "value", "onInput", "onFocus", "onKeydown", "e", "onListMousedown", "onDocClick", "next", "dl", "root", "modal_exports", "__export", "bindOutsideClickToClose", "close", "init", "open", "toggle", "OPEN", "LOCK", "openStack", "openers", "FOCUSABLE", "resolve", "target", "backdropFor", "el", "explicit", "prev", "opener", "_a", "first", "_b", "_c", "i", "backdrop", "onClose", "downOnBackdrop", "e", "keyBound", "root", "btn", "id", "overlay", "drawer", "nav_exports", "__export", "close", "init", "open", "OPEN", "toggle", "panel", "panelFor", "id", "root", "_a", "_b", "container", "e", "loading_exports", "__export", "init", "resetAll", "resetButtonLoading", "setButtonLoading", "LOADING", "btn", "loadingText", "_a", "_b", "label", "root", "pageshowBound", "form", "e", "toast_exports", "__export", "hide", "show", "el", "timer", "ensure", "message", "variant", "duration", "node", "version", "init", "root", "Fernwell", "theme_exports", "combobox_exports", "modal_exports", "nav_exports", "loading_exports", "toast_exports", "index_default", "script", "index_default"]
7
+ }
@@ -0,0 +1,2 @@
1
+ /*! fernwell v0.1.0 | MIT | https://github.com/JacobKnaack/fernwell */
2
+ @layer fw-tokens{:root,[data-theme=light]{--fw-text: #1F2430;--fw-text-soft: #565D6E;--fw-bg: #F5F6F1;--fw-bg-dim: #EAEBE4;--fw-surface: #FFFFFF;--fw-primary: #FFC145;--fw-primary-hover: color-mix(in srgb, var(--fw-primary), var(--fw-text) 12%);--fw-primary-soft: color-mix(in srgb, var(--fw-primary), white 35%);--fw-secondary: #4C3A73;--fw-secondary-hover: color-mix(in srgb, var(--fw-secondary), var(--fw-text) 15%);--fw-secondary-bg: color-mix(in srgb, var(--fw-secondary) 10%, var(--fw-surface));--fw-success: #3FA672;--fw-success-bg: color-mix(in srgb, var(--fw-success) 12%, var(--fw-surface));--fw-warning: #E8A521;--fw-warning-bg: color-mix(in srgb, var(--fw-warning) 14%, var(--fw-surface));--fw-danger: #E85B4F;--fw-danger-bg: color-mix(in srgb, var(--fw-danger) 13%, var(--fw-surface));--fw-info: #3E8FD0;--fw-info-bg: color-mix(in srgb, var(--fw-info) 12%, var(--fw-surface));--fw-on-primary: #1F2430;--fw-on-secondary: #FFFFFF;--fw-on-secondary-soft: color-mix(in srgb, var(--fw-on-secondary) 72%, transparent);--fw-on-secondary-fill: color-mix(in srgb, var(--fw-on-secondary) 10%, transparent);--fw-on-secondary-line: color-mix(in srgb, var(--fw-on-secondary) 16%, transparent);--fw-overlay: rgba(31, 36, 48, .55);--fw-overlay-soft: rgba(31, 36, 48, .32);--fw-focus-ring: 0 0 0 4px color-mix(in srgb, var(--fw-primary) 25%, transparent);--fw-font-display: "Plus Jakarta Sans", system-ui, sans-serif;--fw-font-body: "Inter", system-ui, sans-serif;--fw-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;--fw-sp-1: 4px;--fw-sp-2: 8px;--fw-sp-3: 12px;--fw-sp-4: 16px;--fw-sp-5: 24px;--fw-sp-6: 32px;--fw-sp-7: 48px;--fw-sp-8: 64px;--fw-sp-9: 96px;--fw-r-sm: 10px;--fw-r-md: 16px;--fw-r-lg: 24px;--fw-r-xl: 32px;--fw-r-full: 999px;--fw-shadow-sm: 0 1px 2px rgba(31, 36, 48, .06), 0 1px 1px rgba(31, 36, 48, .04);--fw-shadow-md: 0 4px 12px rgba(31, 36, 48, .08), 0 2px 4px rgba(31, 36, 48, .04);--fw-shadow-lg: 0 12px 32px rgba(31, 36, 48, .12), 0 4px 8px rgba(31, 36, 48, .06);--fw-shadow-primary: 0 6px 16px color-mix(in srgb, var(--fw-primary) 35%, transparent);--fw-shadow-success: 0 6px 16px color-mix(in srgb, var(--fw-success) 28%, transparent);--fw-border-w: 1.5px;--fw-motion-fast: .12s;--fw-motion-base: .18s;--fw-motion-ease: ease}[data-theme=dark]{--fw-text: #F2F1EA;--fw-text-soft: #9CA1B0;--fw-bg: #14161C;--fw-bg-dim: #2B2F3B;--fw-surface: #1D2029;--fw-primary: #FFC145;--fw-primary-hover: color-mix(in srgb, var(--fw-primary), var(--fw-text) 12%);--fw-primary-soft: color-mix(in srgb, var(--fw-primary), white 35%);--fw-secondary: #6B54A3;--fw-secondary-hover: color-mix(in srgb, var(--fw-secondary), var(--fw-text) 15%);--fw-secondary-bg: color-mix(in srgb, var(--fw-secondary) 16%, transparent);--fw-success: #55D194;--fw-success-bg: color-mix(in srgb, var(--fw-success) 14%, transparent);--fw-warning: #FFD166;--fw-warning-bg: color-mix(in srgb, var(--fw-warning) 16%, transparent);--fw-danger: #FF8478;--fw-danger-bg: color-mix(in srgb, var(--fw-danger) 14%, transparent);--fw-info: #6BB3E8;--fw-info-bg: color-mix(in srgb, var(--fw-info) 14%, transparent);--fw-on-primary: #1F2430;--fw-on-secondary: #FFFFFF;--fw-on-secondary-soft: color-mix(in srgb, var(--fw-on-secondary) 72%, transparent);--fw-on-secondary-fill: color-mix(in srgb, var(--fw-on-secondary) 10%, transparent);--fw-on-secondary-line: color-mix(in srgb, var(--fw-on-secondary) 16%, transparent);--fw-overlay: rgba(0, 0, 0, .6);--fw-overlay-soft: rgba(0, 0, 0, .4);--fw-focus-ring: 0 0 0 4px color-mix(in srgb, var(--fw-primary) 25%, transparent);--fw-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);--fw-shadow-md: 0 4px 12px rgba(0, 0, 0, .35);--fw-shadow-lg: 0 12px 32px rgba(0, 0, 0, .45);--fw-shadow-primary: 0 6px 16px color-mix(in srgb, var(--fw-primary) 22%, transparent);--fw-shadow-success: 0 6px 16px color-mix(in srgb, var(--fw-success) 22%, transparent)}}.fw-root{background:var(--fw-bg);color:var(--fw-text);font-family:var(--fw-font-body);line-height:1.5;-webkit-font-smoothing:antialiased;transition:background var(--fw-motion-base) var(--fw-motion-ease),color var(--fw-motion-base) var(--fw-motion-ease)}.fw-root,.fw-root *,.fw-root *:before,.fw-root *:after{box-sizing:border-box}.fw-root :where(h1,h2,h3,h4){font-family:var(--fw-font-display);color:var(--fw-text);margin:0}.fw-root :where(p){margin:0}.fw-root :where(a){color:inherit}.fw-root :where(code){font-family:var(--fw-font-mono)}[hidden]{display:none!important}.fw-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.fw-scroll-lock{overflow:hidden}@media(prefers-reduced-motion:reduce){.fw-root{scroll-behavior:auto}.fw-btn,.fw-btn:hover,.fw-list-row,.fw-list-row:hover{transform:none}}.fw-wrap{max-width:1100px;margin:0 auto;padding:0 var(--fw-sp-5)}.fw-row{display:flex;gap:var(--fw-sp-4);flex-wrap:wrap;align-items:center}.fw-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:var(--fw-sp-5)}@media(max-width:640px){.fw-grid-2{grid-template-columns:1fr}}.fw-btn{font-family:var(--fw-font-body);font-weight:700;font-size:15px;line-height:1.2;border-radius:var(--fw-r-md);padding:12px 22px;border:none;cursor:pointer;display:inline-flex;align-items:center;gap:var(--fw-sp-2);text-decoration:none;transition:transform var(--fw-motion-fast) var(--fw-motion-ease),box-shadow var(--fw-motion-fast) var(--fw-motion-ease),background var(--fw-motion-fast) var(--fw-motion-ease),border-color var(--fw-motion-fast) var(--fw-motion-ease)}.fw-btn:hover{transform:translateY(-1px)}.fw-btn:active{transform:translateY(0)}.fw-btn:focus-visible{outline:none;box-shadow:var(--fw-focus-ring)}.fw-btn-primary{background:var(--fw-primary);color:var(--fw-on-primary);box-shadow:var(--fw-shadow-primary)}.fw-btn-primary:hover{background:var(--fw-primary-hover)}.fw-btn-secondary{background:var(--fw-secondary);color:var(--fw-on-secondary)}.fw-btn-secondary:hover{background:var(--fw-secondary-hover)}.fw-btn-ghost{background:transparent;color:var(--fw-text);border:var(--fw-border-w) solid var(--fw-bg-dim)}.fw-btn-ghost:hover{border-color:var(--fw-text-soft)}.fw-btn-danger{background:var(--fw-danger-bg);color:var(--fw-danger)}.fw-btn-lg{padding:14px 26px}.fw-btn:disabled,.fw-btn[aria-disabled=true]{opacity:.45;cursor:not-allowed;transform:none}.fw-btn-loading{cursor:progress}.fw-btn .fw-spinner{margin-right:2px}.fw-icon-btn{width:32px;height:32px;border-radius:var(--fw-r-sm);border:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:var(--fw-text-soft);flex-shrink:0;padding:0;text-decoration:none;transition:border-color var(--fw-motion-fast) var(--fw-motion-ease),color var(--fw-motion-fast) var(--fw-motion-ease)}.fw-icon-btn:hover{border-color:var(--fw-secondary);color:var(--fw-secondary)}.fw-icon-btn:focus-visible{outline:none;box-shadow:var(--fw-focus-ring)}.fw-icon-btn svg{width:15px;height:15px}.fw-card{background:var(--fw-surface);border-radius:var(--fw-r-lg);border:var(--fw-border-w) solid var(--fw-bg-dim);box-shadow:var(--fw-shadow-sm);padding:var(--fw-sp-5);color:var(--fw-text)}.fw-tag{display:inline-flex;align-items:center;gap:6px;font-family:var(--fw-font-mono);font-size:12px;font-weight:600;line-height:1.3;padding:5px 12px;border-radius:var(--fw-r-md);transform:rotate(-2deg);background:var(--fw-bg-dim);color:var(--fw-text-soft);white-space:nowrap}.fw-tag:nth-of-type(2n){transform:rotate(1.5deg)}.fw-tag:nth-of-type(3n){transform:rotate(-1deg)}.fw-tag-pill,.fw-tag-pill:nth-of-type(n){transform:none;font-size:11px;padding:4px 10px;border-radius:var(--fw-r-full)}.fw-tag-live{background:var(--fw-success-bg);color:var(--fw-success)}.fw-tag-live:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--fw-success)}.fw-tag-pending{background:var(--fw-warning-bg);color:var(--fw-warning)}.fw-tag-error{background:var(--fw-danger-bg);color:var(--fw-danger)}.fw-tag-info{background:var(--fw-info-bg);color:var(--fw-info)}.fw-tag-secondary{background:var(--fw-secondary-bg);color:var(--fw-secondary)}@media(prefers-reduced-motion:no-preference){.fw-tag{transition:transform var(--fw-motion-fast) var(--fw-motion-ease)}}.fw-eyebrow{display:inline-flex;align-items:center;gap:var(--fw-sp-2);font-family:var(--fw-font-mono);font-size:12px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--fw-secondary);background:var(--fw-surface);border:var(--fw-border-w) solid var(--fw-bg-dim);padding:7px 16px;border-radius:var(--fw-r-full);box-shadow:var(--fw-shadow-sm)}.fw-eyebrow:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--fw-primary)}[data-theme=dark] .fw-eyebrow{color:var(--fw-secondary-hover)}.fw-field{display:flex;flex-direction:column;gap:6px;max-width:320px}.fw-field-full{max-width:none}.fw-label,.fw-field>label{font-size:13px;font-weight:600;color:var(--fw-text)}.fw-hint{font-size:12px;color:var(--fw-text-soft)}.fw-error-msg{font-size:12px;color:var(--fw-danger);font-weight:600}.fw-required{color:var(--fw-danger);font-weight:700;margin-left:3px}.fw-input,.fw-field input:not([type=checkbox]):not([type=radio]),.fw-field select,.fw-field textarea{font-family:var(--fw-font-body);font-size:15px;line-height:1.4;padding:11px 14px;border-radius:var(--fw-r-sm);border:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface);color:var(--fw-text);outline:none;width:100%;transition:border-color var(--fw-motion-fast) var(--fw-motion-ease),box-shadow var(--fw-motion-fast) var(--fw-motion-ease),background var(--fw-motion-base) var(--fw-motion-ease),color var(--fw-motion-base) var(--fw-motion-ease)}textarea.fw-input,.fw-field textarea{min-height:96px;resize:vertical}.fw-input::placeholder,.fw-field input::placeholder,.fw-field textarea::placeholder{color:var(--fw-text-soft);opacity:1}.fw-input:focus,.fw-field input:focus,.fw-field select:focus,.fw-field textarea:focus{border-color:var(--fw-primary-hover);box-shadow:var(--fw-focus-ring)}.fw-input.is-error,.fw-input[aria-invalid=true],.fw-field.is-error input,.fw-field.is-error select,.fw-field.is-error textarea,.fw-field input.is-error,.fw-field textarea.is-error{border-color:var(--fw-danger)}.fw-input:disabled,.fw-field input:disabled,.fw-field select:disabled,.fw-field textarea:disabled{background:var(--fw-bg-dim);color:var(--fw-text-soft);border-color:var(--fw-bg-dim);cursor:not-allowed}.fw-field.is-disabled .fw-label,.fw-field.is-disabled>label{color:var(--fw-text-soft)}.fw-checkbox,.fw-radio,.fw-toggle{position:relative;display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-family:var(--fw-font-body);font-size:14px;font-weight:600;color:var(--fw-text)}.fw-checkbox input,.fw-radio input,.fw-toggle input{position:absolute;opacity:0;width:0;height:0;margin:0}.fw-checkbox:has(input:disabled),.fw-radio:has(input:disabled),.fw-toggle:has(input:disabled){cursor:not-allowed}.fw-checkbox input:disabled~span,.fw-radio input:disabled~span,.fw-toggle input:disabled~span{color:var(--fw-text-soft)}.fw-option-group{display:flex;flex-direction:column;gap:var(--fw-sp-3)}.fw-option-group-inline{flex-direction:row;flex-wrap:wrap;gap:var(--fw-sp-5)}.fw-checkbox .fw-box{width:20px;height:20px;border-radius:6px;border:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background var(--fw-motion-fast) var(--fw-motion-ease),border-color var(--fw-motion-fast) var(--fw-motion-ease)}.fw-checkbox .fw-box:after{content:"";width:12px;height:12px;opacity:0;background-color:var(--fw-on-primary);-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 8.5L6.2 11.5L13 4.5' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 8.5L6.2 11.5L13 4.5' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;transition:opacity .1s var(--fw-motion-ease)}.fw-checkbox input:checked+.fw-box{background:var(--fw-primary);border-color:var(--fw-primary)}.fw-checkbox input:checked+.fw-box:after{opacity:1}.fw-checkbox input:focus-visible+.fw-box{box-shadow:var(--fw-focus-ring)}.fw-checkbox input:disabled+.fw-box{background:var(--fw-bg-dim);border-color:var(--fw-bg-dim)}.fw-radio .fw-box{width:20px;height:20px;border-radius:50%;border:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:border-color var(--fw-motion-fast) var(--fw-motion-ease)}.fw-radio .fw-box:after{content:"";width:10px;height:10px;border-radius:50%;background:transparent;transition:background var(--fw-motion-fast) var(--fw-motion-ease)}.fw-radio input:checked+.fw-box{border-color:var(--fw-primary)}.fw-radio input:checked+.fw-box:after{background:var(--fw-primary)}.fw-radio input:focus-visible+.fw-box{box-shadow:var(--fw-focus-ring)}.fw-radio input:disabled+.fw-box{background:var(--fw-bg-dim);border-color:var(--fw-bg-dim)}.fw-toggle .fw-track{width:42px;height:24px;border-radius:var(--fw-r-full);background:var(--fw-bg-dim);position:relative;flex-shrink:0;transition:background .16s var(--fw-motion-ease)}.fw-toggle .fw-thumb{position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;background:var(--fw-surface);box-shadow:var(--fw-shadow-sm);transition:transform .16s var(--fw-motion-ease)}.fw-toggle input:checked+.fw-track{background:var(--fw-primary)}.fw-toggle input:checked+.fw-track .fw-thumb{transform:translate(18px)}.fw-toggle input:focus-visible+.fw-track{box-shadow:var(--fw-focus-ring)}.fw-toggle input:disabled+.fw-track{opacity:.5}.fw-combobox{position:relative}.fw-combobox-list{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:30;background:var(--fw-surface);border:var(--fw-border-w) solid var(--fw-bg-dim);border-radius:var(--fw-r-md);box-shadow:var(--fw-shadow-lg);max-height:220px;overflow-y:auto;padding:6px;margin:0;list-style:none;opacity:0;transform:translateY(-4px);pointer-events:none;transition:opacity .14s var(--fw-motion-ease),transform .14s var(--fw-motion-ease)}.fw-combobox-list.is-open{opacity:1;transform:translateY(0);pointer-events:auto}.fw-combobox-option{padding:10px 12px;border-radius:var(--fw-r-sm);font-family:var(--fw-font-body);font-size:14px;cursor:pointer;color:var(--fw-text)}.fw-combobox-option:hover,.fw-combobox-option.is-active{background:var(--fw-bg)}.fw-combobox-option b{color:var(--fw-primary-hover);font-weight:700}.fw-combobox-empty{padding:14px 12px;font-size:13px;color:var(--fw-text-soft);text-align:center}@media(prefers-reduced-motion:reduce){.fw-combobox-list{transform:none}}.fw-alert{display:flex;gap:var(--fw-sp-3);padding:var(--fw-sp-4);border-radius:var(--fw-r-md);align-items:flex-start;font-family:var(--fw-font-body);color:var(--fw-text);background:var(--fw-bg-dim)}.fw-alert-dot{width:20px;height:20px;border-radius:50%;flex-shrink:0;margin-top:2px;background:var(--fw-text-soft)}.fw-alert-title{font-weight:700;font-size:14px}.fw-alert-body{font-size:13px;color:var(--fw-text-soft);margin-top:2px}.fw-alert-success{background:var(--fw-success-bg)}.fw-alert-success .fw-alert-dot{background:var(--fw-success)}.fw-alert-error{background:var(--fw-danger-bg)}.fw-alert-error .fw-alert-dot{background:var(--fw-danger)}.fw-alert-pending{background:var(--fw-warning-bg)}.fw-alert-pending .fw-alert-dot{background:var(--fw-warning)}.fw-alert-info{background:var(--fw-info-bg)}.fw-alert-info .fw-alert-dot{background:var(--fw-info)}.fw-alert-with-action{align-items:center;justify-content:space-between;flex-wrap:wrap}.fw-alert-with-action .fw-alert-main{display:flex;align-items:center;gap:var(--fw-sp-3)}.fw-progress-label{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:6px;font-family:var(--fw-font-body);font-size:13px}.fw-progress-name{font-weight:600;color:var(--fw-text)}.fw-progress-pct{font-family:var(--fw-font-mono);color:var(--fw-text-soft)}.fw-progress{position:relative;height:10px;border-radius:var(--fw-r-full);background:var(--fw-bg-dim);overflow:hidden}.fw-progress-sm{height:8px}.fw-progress-fill{height:100%;border-radius:var(--fw-r-full);background:var(--fw-primary);transition:width .4s var(--fw-motion-ease)}.fw-progress.is-success .fw-progress-fill,.fw-progress-fill.is-success{background:var(--fw-success)}.fw-progress.is-indeterminate .fw-progress-fill{position:absolute;width:40%;left:-40%;animation:fw-indeterminate-slide 1.4s ease-in-out infinite}@keyframes fw-indeterminate-slide{0%{left:-40%;width:40%}50%{width:60%}to{left:100%;width:40%}}@media(prefers-reduced-motion:reduce){.fw-progress.is-indeterminate .fw-progress-fill{position:static;width:100%;animation:fw-pulse-opacity 1.2s ease-in-out infinite}}.fw-spinner{display:inline-block;border-radius:50%;flex-shrink:0;width:24px;height:24px;border:3px solid var(--fw-bg-dim);border-top-color:currentColor;animation:fw-spin .8s linear infinite}.fw-spinner-sm{width:16px;height:16px;border-width:2px}.fw-spinner-md{width:24px;height:24px;border-width:3px}.fw-spinner-lg{width:40px;height:40px;border-width:4px}@keyframes fw-spin{to{transform:rotate(360deg)}}@keyframes fw-pulse-opacity{0%,to{opacity:1}50%{opacity:.35}}@media(prefers-reduced-motion:reduce){.fw-spinner{animation:fw-pulse-opacity 1.2s ease-in-out infinite;border-top-color:var(--fw-bg-dim)}}.fw-nav{position:relative;background:var(--fw-secondary);border-radius:var(--fw-r-lg);padding:var(--fw-sp-4) var(--fw-sp-5);display:flex;align-items:center;justify-content:space-between;gap:var(--fw-sp-4);box-shadow:var(--fw-shadow-md);font-family:var(--fw-font-body);color:var(--fw-on-secondary)}.fw-nav-sticky{position:sticky;top:var(--fw-sp-5);z-index:100}.fw-nav-brand{color:var(--fw-on-secondary);font-family:var(--fw-font-display);font-weight:800;font-size:18px;display:flex;align-items:center;gap:var(--fw-sp-2);text-decoration:none}.fw-nav-dot{width:10px;height:10px;border-radius:50%;background:var(--fw-primary)}.fw-nav-hex{width:16px;height:16px;background:var(--fw-primary);clip-path:polygon(25% 0,75% 0,100% 50%,75% 100%,25% 100%,0 50%)}.fw-nav-links{display:flex;gap:var(--fw-sp-5);align-items:center}.fw-nav-links a{color:var(--fw-on-secondary-soft);font-size:14px;font-weight:600;text-decoration:none;transition:color var(--fw-motion-fast) var(--fw-motion-ease)}.fw-nav-links a:hover{color:var(--fw-on-secondary)}.fw-nav-links a.is-active{color:var(--fw-on-secondary);border-bottom:2px solid var(--fw-primary);padding-bottom:3px}.fw-nav-right{display:flex;align-items:center;gap:var(--fw-sp-4)}.fw-nav-avatar{width:34px;height:34px;border-radius:var(--fw-r-sm);background:var(--fw-primary);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:13px;color:var(--fw-on-primary);font-family:var(--fw-font-display);border:none;padding:0;cursor:default}.fw-nav-btn,.fw-nav-toggle{width:38px;height:38px;border-radius:var(--fw-r-sm);background:var(--fw-on-secondary-fill);border:var(--fw-border-w) solid var(--fw-on-secondary-line);color:var(--fw-on-secondary);cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;font-size:15px;transition:background var(--fw-motion-fast) var(--fw-motion-ease)}.fw-nav-btn:hover,.fw-nav-toggle:hover{background:var(--fw-on-secondary-line)}.fw-nav-btn:focus-visible,.fw-nav-toggle:focus-visible{outline:none;box-shadow:var(--fw-focus-ring)}.fw-nav-toggle{display:none;flex-direction:column;gap:4px}.fw-nav-toggle span{width:16px;height:2px;background:var(--fw-on-secondary);border-radius:2px;transition:transform var(--fw-motion-base) var(--fw-motion-ease),opacity var(--fw-motion-base) var(--fw-motion-ease)}.fw-nav-toggle[aria-expanded=true] span:nth-child(1){transform:translateY(6px) rotate(45deg)}.fw-nav-toggle[aria-expanded=true] span:nth-child(2){opacity:0}.fw-nav-toggle[aria-expanded=true] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}.fw-nav-dropdown{position:absolute;top:calc(100% + 8px);left:0;right:0;z-index:20;background:var(--fw-surface);border-radius:var(--fw-r-lg);border:var(--fw-border-w) solid var(--fw-bg-dim);box-shadow:var(--fw-shadow-lg);padding:var(--fw-sp-3);display:flex;flex-direction:column;gap:2px;opacity:0;transform:translateY(-6px) scale(.98);pointer-events:none;transition:opacity .16s var(--fw-motion-ease),transform .16s var(--fw-motion-ease)}.fw-nav-dropdown.is-open{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}.fw-nav-dropdown-menu{left:auto;min-width:200px}.fw-nav-dropdown a,.fw-nav-dropdown button{color:var(--fw-text);font-family:var(--fw-font-body);font-size:15px;font-weight:600;text-decoration:none;text-align:left;padding:12px 14px;border-radius:var(--fw-r-sm);background:none;border:none;cursor:pointer;transition:background var(--fw-motion-fast) var(--fw-motion-ease)}.fw-nav-dropdown a:hover,.fw-nav-dropdown button:hover{background:var(--fw-bg)}.fw-nav-dropdown a.is-active{background:var(--fw-primary);color:var(--fw-on-primary)}@media(max-width:600px){.fw-nav-links{display:none}.fw-nav-toggle{display:flex}}@media(prefers-reduced-motion:reduce){.fw-nav-dropdown{transform:none}}.fw-stat-label{font-family:var(--fw-font-body);font-size:13px;color:var(--fw-text-soft);font-weight:600}.fw-stat-value{font-family:var(--fw-font-display);font-size:32px;font-weight:800;line-height:1.1;color:var(--fw-text);margin-top:4px}.fw-stat-value .fw-stat-unit{font-size:18px;color:var(--fw-primary-hover)}.fw-stat-delta{font-family:var(--fw-font-mono);font-size:12px;font-weight:600;color:var(--fw-text-soft);margin-top:4px}.fw-stat-delta.is-up{color:var(--fw-success)}.fw-stat-delta.is-down{color:var(--fw-danger)}.fw-empty{text-align:center;padding:var(--fw-sp-7) var(--fw-sp-5);font-family:var(--fw-font-body)}.fw-empty-blob{width:72px;height:72px;margin:0 auto var(--fw-sp-4);border-radius:38% 62% 60% 40%/48% 42% 58% 52%;background:linear-gradient(135deg,var(--fw-primary),var(--fw-primary-soft));display:flex;align-items:center;justify-content:center;font-size:28px}.fw-empty-title{font-family:var(--fw-font-display);font-size:17px;font-weight:700;color:var(--fw-text);margin:0 0 6px}.fw-empty-body{font-size:14px;color:var(--fw-text-soft);max-width:36ch;margin:0 auto var(--fw-sp-4)}.fw-modal-overlay{position:fixed;inset:0;background:var(--fw-overlay);display:flex;align-items:center;justify-content:center;padding:var(--fw-sp-5);z-index:100;opacity:0;pointer-events:none;transition:opacity var(--fw-motion-base) var(--fw-motion-ease)}.fw-modal-overlay.is-open{opacity:1;pointer-events:auto}.fw-modal{background:var(--fw-surface);color:var(--fw-text);font-family:var(--fw-font-body);border-radius:var(--fw-r-xl);box-shadow:var(--fw-shadow-lg);width:100%;max-width:460px;max-height:88vh;overflow-y:auto;padding:var(--fw-sp-6);transform:translateY(8px) scale(.98);transition:transform var(--fw-motion-base) var(--fw-motion-ease)}.fw-modal-wide{max-width:600px}.fw-modal-overlay.is-open .fw-modal{transform:translateY(0) scale(1)}.fw-modal-head{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--fw-sp-3);margin-bottom:var(--fw-sp-5)}.fw-modal-head h2,.fw-modal-title{font-family:var(--fw-font-display);font-size:19px;font-weight:800;color:var(--fw-text);margin:0}.fw-modal-sub{font-size:13px;color:var(--fw-text-soft);margin:2px 0 0}.fw-modal-foot{display:flex;justify-content:flex-end;gap:var(--fw-sp-3);align-items:center;margin-top:var(--fw-sp-2);padding-top:var(--fw-sp-5);border-top:var(--fw-border-w) solid var(--fw-bg-dim)}@media(prefers-reduced-motion:reduce){.fw-modal{transform:none}}.fw-drawer-overlay{position:fixed;inset:0;background:var(--fw-overlay-soft);opacity:0;pointer-events:none;transition:opacity var(--fw-motion-base) var(--fw-motion-ease);z-index:90}.fw-drawer-overlay.is-open{opacity:1;pointer-events:auto}.fw-drawer{position:fixed;top:0;right:0;height:100%;width:440px;max-width:92vw;background:var(--fw-bg);color:var(--fw-text);font-family:var(--fw-font-body);box-shadow:var(--fw-shadow-lg);border-left:var(--fw-border-w) solid var(--fw-bg-dim);transform:translate(100%);transition:transform .24s var(--fw-motion-ease);z-index:91;display:flex;flex-direction:column}.fw-drawer.is-open{transform:translate(0)}.fw-drawer-head{padding:var(--fw-sp-5);border-bottom:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface);display:flex;align-items:flex-start;gap:var(--fw-sp-3);flex-shrink:0}.fw-drawer-head-text{flex:1;min-width:0}.fw-drawer-eyebrow{font-family:var(--fw-font-mono);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--fw-text-soft);margin-bottom:4px}.fw-drawer-title{font-family:var(--fw-font-display);font-size:19px;font-weight:800;color:var(--fw-text);margin:0}.fw-drawer-title-input{font-family:var(--fw-font-display);font-size:19px;font-weight:800;color:var(--fw-text);border:none;background:transparent;padding:2px 0;width:100%;outline:none;border-radius:6px}.fw-drawer-title-input:focus{background:var(--fw-bg);padding:2px 6px;margin:0 -6px}.fw-drawer>form{flex:1;min-height:0;display:flex;flex-direction:column}.fw-drawer-body{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:var(--fw-sp-5);display:flex;flex-direction:column;gap:var(--fw-sp-5)}.fw-drawer-foot{padding:var(--fw-sp-4) var(--fw-sp-5);display:flex;align-items:center;justify-content:space-between;gap:var(--fw-sp-3);flex-shrink:0;border-top:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface)}@media(max-width:560px){.fw-drawer{width:100vw;max-width:100vw}}@media(prefers-reduced-motion:reduce){.fw-drawer{transition:opacity var(--fw-motion-base) var(--fw-motion-ease);transform:none;opacity:0;pointer-events:none}.fw-drawer.is-open{opacity:1;pointer-events:auto}}.fw-toast{position:fixed;bottom:var(--fw-sp-6);right:var(--fw-sp-6);z-index:200;display:flex;align-items:center;gap:var(--fw-sp-3);max-width:min(360px,calc(100vw - 2 * var(--fw-sp-5)));background:var(--fw-success-bg);color:var(--fw-text);font-family:var(--fw-font-body);border-radius:var(--fw-r-md);padding:var(--fw-sp-3) var(--fw-sp-4);box-shadow:var(--fw-shadow-lg);font-size:13px;font-weight:600;transform:translateY(12px);opacity:0;pointer-events:none;transition:transform var(--fw-motion-base) var(--fw-motion-ease),opacity var(--fw-motion-base) var(--fw-motion-ease)}.fw-toast.is-show{transform:translateY(0);opacity:1;pointer-events:auto}.fw-toast-dot{width:8px;height:8px;border-radius:50%;background:var(--fw-success);flex-shrink:0}.fw-toast-error{background:var(--fw-danger-bg)}.fw-toast-error .fw-toast-dot{background:var(--fw-danger)}.fw-toast-info{background:var(--fw-info-bg)}.fw-toast-info .fw-toast-dot{background:var(--fw-info)}.fw-toast-pending{background:var(--fw-warning-bg)}.fw-toast-pending .fw-toast-dot{background:var(--fw-warning)}@media(prefers-reduced-motion:reduce){.fw-toast{transform:none}}.fw-list-row{display:block;background:var(--fw-surface);border-radius:var(--fw-r-lg);border:var(--fw-border-w) solid var(--fw-bg-dim);box-shadow:var(--fw-shadow-sm);padding:var(--fw-sp-4) var(--fw-sp-5);color:inherit;font-family:var(--fw-font-body);text-decoration:none;transition:transform var(--fw-motion-fast) var(--fw-motion-ease),box-shadow var(--fw-motion-fast) var(--fw-motion-ease)}.fw-list-row:hover{transform:translateY(-1px);box-shadow:var(--fw-shadow-md);text-decoration:none}.fw-list-row:focus-visible{outline:none;box-shadow:var(--fw-focus-ring)}.fw-list-row.is-locked{opacity:.6}.fw-list-row.is-locked:hover{transform:none;box-shadow:var(--fw-shadow-sm)}.fw-list-row+.fw-list-row{margin-top:var(--fw-sp-3)}.fw-list-row-main{display:flex;flex-wrap:wrap;align-items:center;gap:var(--fw-sp-2) var(--fw-sp-4)}.fw-list-row-title{font-family:var(--fw-font-display);font-weight:700;font-size:16px;color:var(--fw-text)}.fw-list-row-meta{font-size:13px;color:var(--fw-text-soft)}.fw-sub-list{margin:var(--fw-sp-2) 0 0 var(--fw-sp-5);padding-left:var(--fw-sp-4);border-left:var(--fw-border-w) solid var(--fw-bg-dim)}.fw-sub-list-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--fw-sp-2) var(--fw-sp-3);padding:var(--fw-sp-2) 0}.fw-sub-list-row+.fw-sub-list-row{border-top:1px solid var(--fw-bg-dim)}.fw-sub-list-title{font-size:13.5px;font-weight:600;color:var(--fw-text)}.fw-disclosure>summary{cursor:pointer;color:var(--fw-secondary);font-family:var(--fw-font-body);font-weight:600;font-size:13px;list-style:none;display:flex;align-items:center;gap:6px}.fw-disclosure>summary::-webkit-details-marker{display:none}.fw-disclosure>summary:hover{text-decoration:underline}.fw-disclosure>summary:focus-visible{outline:none;border-radius:4px;box-shadow:var(--fw-focus-ring)}.fw-disclosure-chevron{width:12px;height:12px;flex-shrink:0;transition:transform .15s var(--fw-motion-ease)}.fw-disclosure[open]>summary .fw-disclosure-chevron{transform:rotate(180deg)}.fw-disclosure-count{font-family:var(--fw-font-mono);font-size:10.5px;font-weight:700;color:var(--fw-secondary);background:var(--fw-surface);border:var(--fw-border-w) solid var(--fw-bg-dim);border-radius:var(--fw-r-full);padding:1px 7px}.fw-disclosure-body{margin-top:var(--fw-sp-3);border:var(--fw-border-w) solid var(--fw-bg-dim);border-radius:var(--fw-r-md);padding:var(--fw-sp-4);background:var(--fw-bg);display:flex;flex-direction:column;gap:var(--fw-sp-3)}.fw-pagination{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--fw-sp-3);font-family:var(--fw-font-body)}.fw-pag-info,.fw-pag-label{font-family:var(--fw-font-mono);font-size:12px;color:var(--fw-text-soft)}.fw-pag-controls{display:flex;align-items:center;gap:var(--fw-sp-3)}.fw-btn-page{display:inline-flex;align-items:center;height:34px;padding:0 14px;border-radius:var(--fw-r-sm);border:var(--fw-border-w) solid var(--fw-bg-dim);background:var(--fw-surface);color:var(--fw-text);font-family:var(--fw-font-body);font-size:13px;font-weight:600;text-decoration:none;cursor:pointer;transition:border-color var(--fw-motion-fast) var(--fw-motion-ease)}.fw-btn-page:hover{border-color:var(--fw-text-soft);text-decoration:none}.fw-btn-page:focus-visible{outline:none;box-shadow:var(--fw-focus-ring)}.fw-btn-page.is-disabled,.fw-btn-page[aria-disabled=true],.fw-btn-page:disabled{opacity:.35;cursor:not-allowed;pointer-events:none}
@@ -0,0 +1,105 @@
1
+ /*! fernwell v0.1.0 | MIT | https://github.com/JacobKnaack/fernwell */
2
+ /* src/css/tokens.css */
3
+ @layer fw-tokens {
4
+ :root,
5
+ [data-theme=light] {
6
+ --fw-text: #1F2430;
7
+ --fw-text-soft: #565D6E;
8
+ --fw-bg: #F5F6F1;
9
+ --fw-bg-dim: #EAEBE4;
10
+ --fw-surface: #FFFFFF;
11
+ --fw-primary: #FFC145;
12
+ --fw-primary-hover: color-mix(in srgb, var(--fw-primary), var(--fw-text) 12%);
13
+ --fw-primary-soft: color-mix(in srgb, var(--fw-primary), white 35%);
14
+ --fw-secondary: #4C3A73;
15
+ --fw-secondary-hover: color-mix(in srgb, var(--fw-secondary), var(--fw-text) 15%);
16
+ --fw-secondary-bg: color-mix(in srgb, var(--fw-secondary) 10%, var(--fw-surface));
17
+ --fw-success: #3FA672;
18
+ --fw-success-bg: color-mix(in srgb, var(--fw-success) 12%, var(--fw-surface));
19
+ --fw-warning: #E8A521;
20
+ --fw-warning-bg: color-mix(in srgb, var(--fw-warning) 14%, var(--fw-surface));
21
+ --fw-danger: #E85B4F;
22
+ --fw-danger-bg: color-mix(in srgb, var(--fw-danger) 13%, var(--fw-surface));
23
+ --fw-info: #3E8FD0;
24
+ --fw-info-bg: color-mix(in srgb, var(--fw-info) 12%, var(--fw-surface));
25
+ --fw-on-primary: #1F2430;
26
+ --fw-on-secondary: #FFFFFF;
27
+ --fw-on-secondary-soft: color-mix(in srgb, var(--fw-on-secondary) 72%, transparent);
28
+ --fw-on-secondary-fill: color-mix(in srgb, var(--fw-on-secondary) 10%, transparent);
29
+ --fw-on-secondary-line: color-mix(in srgb, var(--fw-on-secondary) 16%, transparent);
30
+ --fw-overlay: rgba(31, 36, 48, 0.55);
31
+ --fw-overlay-soft: rgba(31, 36, 48, 0.32);
32
+ --fw-focus-ring: 0 0 0 4px color-mix(in srgb, var(--fw-primary) 25%, transparent);
33
+ --fw-font-display:
34
+ "Plus Jakarta Sans",
35
+ system-ui,
36
+ sans-serif;
37
+ --fw-font-body:
38
+ "Inter",
39
+ system-ui,
40
+ sans-serif;
41
+ --fw-font-mono:
42
+ "IBM Plex Mono",
43
+ ui-monospace,
44
+ SFMono-Regular,
45
+ Menlo,
46
+ monospace;
47
+ --fw-sp-1: 4px;
48
+ --fw-sp-2: 8px;
49
+ --fw-sp-3: 12px;
50
+ --fw-sp-4: 16px;
51
+ --fw-sp-5: 24px;
52
+ --fw-sp-6: 32px;
53
+ --fw-sp-7: 48px;
54
+ --fw-sp-8: 64px;
55
+ --fw-sp-9: 96px;
56
+ --fw-r-sm: 10px;
57
+ --fw-r-md: 16px;
58
+ --fw-r-lg: 24px;
59
+ --fw-r-xl: 32px;
60
+ --fw-r-full: 999px;
61
+ --fw-shadow-sm: 0 1px 2px rgba(31, 36, 48, 0.06), 0 1px 1px rgba(31, 36, 48, 0.04);
62
+ --fw-shadow-md: 0 4px 12px rgba(31, 36, 48, 0.08), 0 2px 4px rgba(31, 36, 48, 0.04);
63
+ --fw-shadow-lg: 0 12px 32px rgba(31, 36, 48, 0.12), 0 4px 8px rgba(31, 36, 48, 0.06);
64
+ --fw-shadow-primary: 0 6px 16px color-mix(in srgb, var(--fw-primary) 35%, transparent);
65
+ --fw-shadow-success: 0 6px 16px color-mix(in srgb, var(--fw-success) 28%, transparent);
66
+ --fw-border-w: 1.5px;
67
+ --fw-motion-fast: 120ms;
68
+ --fw-motion-base: 180ms;
69
+ --fw-motion-ease: ease;
70
+ }
71
+ [data-theme=dark] {
72
+ --fw-text: #F2F1EA;
73
+ --fw-text-soft: #9CA1B0;
74
+ --fw-bg: #14161C;
75
+ --fw-bg-dim: #2B2F3B;
76
+ --fw-surface: #1D2029;
77
+ --fw-primary: #FFC145;
78
+ --fw-primary-hover: color-mix(in srgb, var(--fw-primary), var(--fw-text) 12%);
79
+ --fw-primary-soft: color-mix(in srgb, var(--fw-primary), white 35%);
80
+ --fw-secondary: #6B54A3;
81
+ --fw-secondary-hover: color-mix(in srgb, var(--fw-secondary), var(--fw-text) 15%);
82
+ --fw-secondary-bg: color-mix(in srgb, var(--fw-secondary) 16%, transparent);
83
+ --fw-success: #55D194;
84
+ --fw-success-bg: color-mix(in srgb, var(--fw-success) 14%, transparent);
85
+ --fw-warning: #FFD166;
86
+ --fw-warning-bg: color-mix(in srgb, var(--fw-warning) 16%, transparent);
87
+ --fw-danger: #FF8478;
88
+ --fw-danger-bg: color-mix(in srgb, var(--fw-danger) 14%, transparent);
89
+ --fw-info: #6BB3E8;
90
+ --fw-info-bg: color-mix(in srgb, var(--fw-info) 14%, transparent);
91
+ --fw-on-primary: #1F2430;
92
+ --fw-on-secondary: #FFFFFF;
93
+ --fw-on-secondary-soft: color-mix(in srgb, var(--fw-on-secondary) 72%, transparent);
94
+ --fw-on-secondary-fill: color-mix(in srgb, var(--fw-on-secondary) 10%, transparent);
95
+ --fw-on-secondary-line: color-mix(in srgb, var(--fw-on-secondary) 16%, transparent);
96
+ --fw-overlay: rgba(0, 0, 0, 0.6);
97
+ --fw-overlay-soft: rgba(0, 0, 0, 0.4);
98
+ --fw-focus-ring: 0 0 0 4px color-mix(in srgb, var(--fw-primary) 25%, transparent);
99
+ --fw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
100
+ --fw-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
101
+ --fw-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45);
102
+ --fw-shadow-primary: 0 6px 16px color-mix(in srgb, var(--fw-primary) 22%, transparent);
103
+ --fw-shadow-success: 0 6px 16px color-mix(in srgb, var(--fw-success) 22%, transparent);
104
+ }
105
+ }
package/dist/iife.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './index';
2
+ export { default } from './index';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Fernwell — vanilla JS enhancers for the Fernwell design system.
3
+ *
4
+ * ESM / CJS: import { init, theme, toast } from 'fernwell'; init();
5
+ * <script>: <script src="https://unpkg.com/fernwell/dist/fernwell.iife.js"></script>
6
+ * → window.Fernwell, auto-initialised on DOMContentLoaded
7
+ * (add data-fw-no-init to the <script> tag to opt out).
8
+ */
9
+ import * as theme from './theme';
10
+ import * as combobox from './combobox';
11
+ import * as modal from './modal';
12
+ import * as nav from './nav';
13
+ import * as loading from './loading';
14
+ import * as toast from './toast';
15
+ export { theme, combobox, modal, nav, loading, toast };
16
+ export type { Theme, TokenOverrides, TokenThemeOverrides } from './theme';
17
+ export type { ComboboxOptions, ComboboxInstance } from './combobox';
18
+ export type { ToastVariant, ToastOptions } from './toast';
19
+ export declare const version = "__FW_VERSION__";
20
+ /**
21
+ * Wire every `data-fw-*` hook under `root`. Safe to call more than once —
22
+ * already-bound elements are skipped — so call it again after injecting
23
+ * markup (e.g. after an HTMX / Turbo swap).
24
+ */
25
+ export declare function init(root?: ParentNode): void;
26
+ declare const Fernwell: {
27
+ version: string;
28
+ init: typeof init;
29
+ theme: typeof theme;
30
+ combobox: typeof combobox;
31
+ modal: typeof modal;
32
+ nav: typeof nav;
33
+ loading: typeof loading;
34
+ toast: typeof toast;
35
+ };
36
+ export default Fernwell;
@@ -0,0 +1,5 @@
1
+ export declare function setButtonLoading(btn: HTMLButtonElement | null, loadingText?: string): void;
2
+ export declare function resetButtonLoading(btn: HTMLButtonElement | null): void;
3
+ /** Reset every loading button — e.g. after a bfcache restore. */
4
+ export declare function resetAll(root?: ParentNode): void;
5
+ export declare function init(root?: ParentNode): void;
@@ -0,0 +1,13 @@
1
+ export declare function open(target: string | HTMLElement, opener?: HTMLElement | null): void;
2
+ export declare function close(target: string | HTMLElement): void;
3
+ export declare function toggle(target: string | HTMLElement): void;
4
+ /**
5
+ * Click-outside-to-close, guarded against a classic false positive: a
6
+ * browser's `click` fires on the nearest common ancestor of mousedown and
7
+ * mouseup. A drag that starts inside the panel and ends on the backdrop has
8
+ * the overlay as that ancestor, so a naive `e.target === overlay` check would
9
+ * close the modal mid-selection. Close only when BOTH landed on the backdrop.
10
+ */
11
+ export declare function bindOutsideClickToClose(backdrop: HTMLElement, onClose: () => void): void;
12
+ /** Wire every trigger, overlay and close button under `root`. */
13
+ export declare function init(root?: ParentNode): void;
package/dist/nav.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare function open(toggle: HTMLElement): void;
2
+ export declare function close(toggle: HTMLElement): void;
3
+ export declare function init(root?: ParentNode): void;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Theme — toggles `data-theme="dark"` on <html>, remembers the choice, and
3
+ * falls back to the OS preference. Also carries the runtime token API
4
+ * (`setTokens` / `resetTokens` / `getToken`) for retheming Fernwell's colour
5
+ * tokens on the fly — per-tenant branding, a user-picked accent, a live
6
+ * preview — without touching a stylesheet.
7
+ *
8
+ * <button class="fw-btn fw-btn-ghost" data-fw-theme-toggle
9
+ * data-fw-theme-label-dark="☀️ Light" data-fw-theme-label-light="🌙 Dark">🌙 Dark</button>
10
+ *
11
+ * To avoid a flash of the wrong theme on load, inline this before your CSS:
12
+ * <script>document.documentElement.dataset.theme=localStorage.getItem('fw-theme')||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light')</script>
13
+ */
14
+ export type Theme = 'light' | 'dark';
15
+ /** The theme currently applied to <html>, or the system preference if none is set. */
16
+ export declare function get(): Theme;
17
+ /** Apply a theme, persist it, and update every toggle button on the page. */
18
+ export declare function set(theme: Theme, { persist }?: {
19
+ persist?: boolean;
20
+ }): void;
21
+ export declare function toggle(): Theme;
22
+ /** Apply the stored / system theme and wire every `[data-fw-theme-toggle]` under `root`. */
23
+ export declare function init(root?: ParentNode): void;
24
+ /** Token name → CSS value. Bare names (`primary`) and full names (`--fw-primary`) both work. */
25
+ export type TokenOverrides = Record<string, string>;
26
+ /** Split form: set different values per theme instead of both at once. */
27
+ export interface TokenThemeOverrides {
28
+ light?: TokenOverrides;
29
+ dark?: TokenOverrides;
30
+ }
31
+ /**
32
+ * Override Fernwell design tokens at runtime — every derived token (hovers,
33
+ * tints, focus ring, glows) follows automatically, in both themes:
34
+ *
35
+ * theme.setTokens({ primary: '#2266ff' });
36
+ *
37
+ * Pass `{ light, dark }` to set different values per theme, and `scope` to
38
+ * theme a subtree instead of the whole page:
39
+ *
40
+ * theme.setTokens({ light: { primary: '#2266ff' }, dark: { primary: '#5c9dff' } });
41
+ * theme.setTokens({ secondary: '#a33' }, { scope: '.tenant-acme' });
42
+ *
43
+ * Calls accumulate (merge into whatever overrides are already set for that
44
+ * scope) — call `resetTokens()` to clear them.
45
+ */
46
+ export declare function setTokens(tokens: TokenOverrides | TokenThemeOverrides, opts?: {
47
+ scope?: string;
48
+ }): void;
49
+ /** Clear runtime token overrides — for one `scope`, or every scope if omitted. */
50
+ export declare function resetTokens(scope?: string): void;
51
+ /** The live, resolved value of a token (e.g. `getToken('primary')` → `'#ffc145'`), including runtime overrides. */
52
+ export declare function getToken(name: string, el?: Element): string;