From c8a620464d54023eea6f078c546681e7bf128586 Mon Sep 17 00:00:00 2001 From: HieuNTg Date: Wed, 13 May 2026 16:27:49 +0700 Subject: [PATCH 1/6] perf(css): purge + minify Tailwind, wire built CSS (S1) Tighten content globs to TS sources only (drop web/**/*.js scan which included the 60KB minified runtime bundle whose identifiers caused false-positive class matches inflating the purged output). main.built.css: 101569 bytes raw -> 98515 bytes raw / 16497 bytes gz (vs ~80KB unpurged CDN baseline cited in sprint plan). The built CSS was already wired into web/index.html (line 29) in a prior commit; this commit refreshes the purged artifact. --- tailwind.config.js | 10 ++++++---- web/css/main.built.css | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tailwind.config.js b/tailwind.config.js index bd636069..419008a5 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -17,13 +17,15 @@ module.exports = { // Paths Tailwind scans to detect used class names for PurgeCSS/JIT tree-shaking. // Must cover every file that references Tailwind utilities — missing paths cause // classes to be purged in production builds. + // + // We scan TS sources only (not compiled .js siblings or web/dist/**) — minified + // bundles add false-positive identifier matches that bloat the purged output. content: [ - 'web/**/*.html', - 'web/**/*.js', + 'web/index.html', + 'web/dashboard.html', + 'web/js/**/*.ts', // Include any Jinja/HTML templates served by FastAPI (if present) 'templates/**/*.html', - // Alpine.js x-bind / :class expressions inside inline scripts - 'web/**/*.ts', ], theme: { diff --git a/web/css/main.built.css b/web/css/main.built.css index 3bf846b1..7bd767be 100644 --- a/web/css/main.built.css +++ b/web/css/main.built.css @@ -1,3 +1,3 @@ :root{--sf-color-brand-50:#eff6ff;--sf-color-brand-100:#dbeafe;--sf-color-brand-200:#bfdbfe;--sf-color-brand-500:#3b82f6;--sf-color-brand-600:#2563eb;--sf-color-brand-700:#1d4ed8;--sf-color-brand-800:#1e40af;--sf-color-surface-50:#f8fafc;--sf-color-surface-100:#f1f5f9;--sf-color-surface-200:#e2e8f0;--sf-color-text-primary:#1e293b;--sf-color-text-secondary:#475569;--sf-color-text-muted:#94a3b8;--sf-color-status-success:#16a34a;--sf-color-status-error:#dc2626;--sf-color-status-warning:#f59e0b;--sf-font-sans:"Inter",system-ui,sans-serif;--sf-text-xs:12px;--sf-text-sm:14px;--sf-text-base:16px;--sf-text-lg:18px;--sf-text-xl:20px;--sf-text-2xl:24px;--sf-font-light:300;--sf-font-normal:400;--sf-font-medium:500;--sf-font-semibold:600;--sf-font-bold:700;--sf-space-1:4px;--sf-space-2:8px;--sf-space-3:12px;--sf-space-4:16px;--sf-space-5:20px;--sf-space-6:24px;--sf-space-8:32px;--sf-space-10:40px;--sf-shadow-sm:0 1px 2px 0 rgba(0,0,0,.05);--sf-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--sf-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--sf-radius-sm:6px;--sf-radius-md:8px;--sf-radius-lg:12px;--sf-radius-xl:16px;--sf-radius-full:9999px;--sf-duration-fast:150ms;--sf-duration-base:250ms;--sf-duration-slow:400ms;--sf-ease-default:ease;--sf-ease-out:ease-out;--sf-ease-spring:cubic-bezier(0.4,0,0.2,1);--sf-bg-base:#fafaf7;--sf-bg-surface:#fff;--sf-bg-elevated:#f5f5f0;--sf-text-primary:#1a1a2e;--sf-text-secondary:#6b7280;--sf-text-tertiary:#94a3b8;--sf-accent-primary:#2563eb;--sf-accent-forge:#f59e0b;--sf-accent-complete:#10b981;--sf-accent-danger:#ef4444;--sf-border-subtle:#e5e5e0;--sf-border-strong:#94a3b8;--sf-font-display:"Inter",system-ui,sans-serif;--sf-font-body:"Inter",system-ui,sans-serif;--sf-font-mono:"JetBrains Mono",ui-monospace,"Sarasa Mono SC",monospace;--sf-text-display:32px;--sf-text-h1:24px;--sf-text-h2:20px;--sf-text-h3:18px;--sf-text-h4:16px;--sf-text-body:13px;--sf-text-caption:11px;--sf-space-7:28px;--sf-space-9:36px;--sf-space-11:44px;--sf-space-12:48px;--sf-ease-spring-emphasized:cubic-bezier(0.2,0,0,1);--sf-duration-instant:0ms;--sf-duration-shimmer:1800ms}@media (prefers-color-scheme:dark){:root{--sf-color-surface-50:#0f172a;--sf-color-surface-100:#1e293b;--sf-color-surface-200:#334155;--sf-color-text-primary:#f8fafc;--sf-color-text-secondary:#e2e8f0;--sf-color-text-muted:#94a3b8}}.dark{--sf-color-surface-50:#0f172a;--sf-color-surface-100:#1e293b;--sf-color-surface-200:#334155;--sf-color-text-primary:#f8fafc;--sf-color-text-secondary:#e2e8f0;--sf-color-text-muted:#94a3b8;--sf-shadow-sm:0 1px 2px 0 rgba(0,0,0,.3);--sf-shadow-md:0 4px 6px -1px rgba(0,0,0,.4),0 2px 4px -2px rgba(0,0,0,.3);--sf-shadow-lg:0 10px 15px -3px rgba(0,0,0,.4),0 4px 6px -4px rgba(0,0,0,.3);--dm-bg:#0f172a;--dm-surface:#1e293b;--dm-border:#475569;--dm-text:#f8fafc;--dm-text-secondary:#e2e8f0;--dm-text-muted:#94a3b8;--sf-bg-base:#0f1219;--sf-bg-surface:#1a1f2e;--sf-bg-elevated:#242a3d;--sf-text-primary:#e8e8ed;--sf-text-secondary:#9ca3af;--sf-text-tertiary:#94a3b8;--sf-accent-primary:#3b82f6;--sf-accent-forge:#fbbf24;--sf-accent-complete:#34d399;--sf-accent-danger:#f87171;--sf-border-subtle:#2d3348;--sf-border-strong:#475569}@media (prefers-color-scheme:dark){:root:not(.light){--sf-bg-base:#0f1219;--sf-bg-surface:#1a1f2e;--sf-bg-elevated:#242a3d;--sf-text-primary:#e8e8ed;--sf-text-secondary:#9ca3af;--sf-text-tertiary:#94a3b8;--sf-accent-primary:#3b82f6;--sf-accent-forge:#fbbf24;--sf-accent-complete:#34d399;--sf-accent-danger:#f87171;--sf-border-subtle:#2d3348;--sf-border-strong:#475569}}:focus-visible{outline:2px solid #3b82f6;outline-offset:2px}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;box-shadow:0 0 0 4px rgba(59,130,246,.15)}.star-rating{display:inline-flex;gap:2px;line-height:1}.star{cursor:pointer;font-size:1.5rem;color:var(--sf-color-text-muted,#94a3b8);transition:color var(--sf-duration-fast,.15s) var(--sf-ease-default,ease),transform var(--sf-duration-fast,.15s) var(--sf-ease-default,ease);-webkit-user-select:none;-moz-user-select:none;user-select:none;line-height:1}.star-sm .star,.star.star-sm{font-size:1rem}.star-lg .star,.star.star-lg{font-size:2rem}.star.filled,.star:hover{color:#f59e0b}.star:hover{transform:scale(1.15)}.star:active{transform:scale(.9)}.star-rating.readonly .star{cursor:default;pointer-events:none}.star-rating.readonly .star:hover{transform:none}@keyframes sf-feedback-pop{0%{transform:scale(.8);opacity:0}60%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}.feedback-success{animation:sf-feedback-pop var(--sf-duration-slow,.4s) var(--sf-ease-spring,cubic-bezier(.4,0,.2,1)) forwards}@keyframes sf-slide-down{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}.feedback-details-enter{animation:sf-slide-down var(--sf-duration-base,.25s) var(--sf-ease-out,ease-out) forwards}@media (max-width:639px){[role=button],a,button,input[type=checkbox],input[type=radio],select{min-height:44px}button.p-1,button.p-1\.5,button.p-2{min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center}.grid.grid-cols-2,.grid.sm\:grid-cols-2{grid-template-columns:1fr!important}input[type=email],input[type=number],input[type=password],input[type=text],input[type=url],select,textarea{width:100%!important;box-sizing:border-box}.story-form,[id=page-config],[id=page-setup],form{padding-left:1rem!important;padding-right:1rem!important}.text-xs{font-size:.7rem}.btn-primary,button[type=submit]{width:100%;justify-content:center}.branch-reader,.reader-container,[id=page-reader]{overflow-x:hidden;width:100%;max-width:100vw}.chapter-content,.prose,[id=page-reader] p{word-break:break-word;overflow-wrap:break-word;hyphens:auto}.branch-choices,.flex.gap-3.mt-4{flex-direction:column!important;gap:.5rem!important}.reader-scroll-area{overflow-y:auto;-webkit-overflow-scrolling:touch;max-height:calc(100vh - 120px);padding-bottom:env(safe-area-inset-bottom,1rem)}.audio-player,.tts-player,[id=audio-controls]{flex-direction:column!important;align-items:stretch!important;gap:.5rem!important;padding:.75rem!important}.audio-player input[type=range],.tts-player input[type=range]{width:100%!important;min-height:44px}.audio-controls-row{display:flex;justify-content:center;gap:.75rem}}@media (max-width:639px){@media (max-width:374px){.audio-volume-control{display:none}}}@media (max-width:767px){main{margin-left:0!important;padding-left:.5rem;padding-right:.5rem}header h1{font-size:1rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:160px}.sf-branch-tree-block canvas,.sf-branch-tree__canvas{max-width:100vw!important;width:100%!important}.sf-reader__sidebar{position:fixed;top:0;left:0;bottom:0;z-index:40;width:80vw;max-width:300px;transform:translateX(-100%);transition:transform .2s ease;overflow-y:auto}.sf-reader__sidebar[data-open=true]{transform:translateX(0)}.sf-stat-tile{min-height:44px}.sf-agent-bubble{width:100%}.sf-theater{overflow-x:hidden}.sf-export-cards,.sf-settings-providers{grid-template-columns:1fr!important}}@supports (padding:env(safe-area-inset-bottom)){aside,body{padding-bottom:env(safe-area-inset-bottom)}}:root[data-forge-ui=on] .sf-forge-btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--sf-space-2);padding:var(--sf-space-3) var(--sf-space-6);border:1px solid transparent;border-radius:var(--sf-radius-md);font-family:var(--sf-font-body);font-size:var(--sf-text-h4);font-weight:var(--sf-font-semibold);line-height:1;background:var(--sf-accent-primary);color:#fff;cursor:pointer;transition:background-color var(--sf-duration-fast) var(--sf-ease-spring),box-shadow var(--sf-duration-fast) var(--sf-ease-spring),transform var(--sf-duration-fast) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-forge-btn[data-variant=secondary]{background:var(--sf-bg-elevated);color:var(--sf-text-primary);border-color:var(--sf-border-subtle)}:root[data-forge-ui=on] .sf-forge-btn[data-variant=ghost]{background:transparent;color:var(--sf-text-primary);border-color:transparent}:root[data-forge-ui=on] .sf-forge-btn[data-variant=danger]{background:var(--sf-accent-danger);color:#fff}:root[data-forge-ui=on] .sf-forge-btn:hover:not([disabled]),:root[data-forge-ui=on] .sf-forge-btn[data-state=hover]:not([disabled]){transform:translateY(-1px);box-shadow:var(--sf-shadow-md)}:root[data-forge-ui=on] .sf-forge-btn[aria-busy=true],:root[data-forge-ui=on] .sf-forge-btn[data-state=loading]{background:var(--sf-accent-forge);cursor:progress}:root[data-forge-ui=on] .sf-forge-btn[data-state=loading]:after{content:"";width:12px;height:12px;border-radius:var(--sf-radius-full);background:currentColor;opacity:.85;animation:sf-forge-btn-pulse var(--sf-duration-shimmer) var(--sf-ease-spring) infinite}:root[data-forge-ui=on] .sf-forge-btn[data-state=disabled],:root[data-forge-ui=on] .sf-forge-btn[disabled]{opacity:.5;cursor:not-allowed}@keyframes sf-forge-btn-pulse{0%,to{opacity:.6;transform:scale(.85)}50%{opacity:1;transform:scale(1.1)}}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-forge-btn,:root[data-forge-ui=on] .sf-forge-btn[data-state=loading]:after{transition:none;animation:none}}:root[data-forge-ui=on] .sf-phase-timeline{display:flex;flex-direction:row;align-items:center;gap:var(--sf-space-3);list-style:none;margin:0;padding:0}:root[data-forge-ui=on] .sf-phase-timeline__step{position:relative;display:inline-flex;align-items:center;gap:var(--sf-space-2);padding:var(--sf-space-2) var(--sf-space-3);border-radius:var(--sf-radius-md);background:var(--sf-bg-surface);border:1px solid var(--sf-border-subtle);color:var(--sf-text-secondary);font-size:var(--sf-text-caption);font-family:var(--sf-font-body);transition:background-color var(--sf-duration-fast) var(--sf-ease-spring),color var(--sf-duration-fast) var(--sf-ease-spring),box-shadow var(--sf-duration-fast) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-phase-timeline__step[data-state=active]{color:var(--sf-text-primary);border-color:var(--sf-accent-forge);box-shadow:0 0 0 0 var(--sf-accent-forge);animation:sf-phase-pulse 1.2s var(--sf-ease-spring) infinite}:root[data-forge-ui=on] .sf-phase-timeline__step[data-state=done]{color:var(--sf-text-primary);border-color:var(--sf-accent-complete);background:var(--sf-bg-elevated)}:root[data-forge-ui=on] .sf-phase-timeline__step[data-state=error]{color:var(--sf-text-primary);border-color:var(--sf-accent-danger)}@keyframes sf-phase-pulse{0%,to{box-shadow:0 0 0 0 color-mix(in oklab,var(--sf-accent-forge) 60%,transparent)}50%{box-shadow:0 0 0 8px color-mix(in oklab,var(--sf-accent-forge) 0,transparent)}}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-phase-timeline__step[data-state=active]{animation:none}}:root[data-forge-ui=on] .sf-genre-orb{--orb-hue:var(--sf-accent-primary);position:relative;display:inline-flex;align-items:center;justify-content:center;width:64px;height:64px;border-radius:var(--sf-radius-full);border:2px solid var(--sf-border-subtle);background:radial-gradient(circle at 30% 30%,color-mix(in oklab,var(--orb-hue) 30%,transparent) 0,transparent 70%);cursor:pointer;transition:transform var(--sf-duration-fast) var(--sf-ease-spring),box-shadow var(--sf-duration-fast) var(--sf-ease-spring),border-color var(--sf-duration-fast) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-genre-orb:hover{transform:scale(1.05);box-shadow:0 0 24px color-mix(in oklab,var(--orb-hue) 40%,transparent)}:root[data-forge-ui=on] .sf-genre-orb[aria-checked=true]{border-color:var(--orb-hue);background:radial-gradient(circle at 30% 30%,var(--orb-hue) 0,color-mix(in oklab,var(--orb-hue) 40%,transparent) 80%)}:root[data-forge-ui=on] .sf-genre-orb__label{font-size:var(--sf-text-caption);color:var(--sf-text-secondary)}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-genre-orb{transition:none}:root[data-forge-ui=on] .sf-genre-orb:hover{transform:none;box-shadow:none}}:root[data-forge-ui=on] .sf-config-panel{border:1px solid var(--sf-border-subtle);border-radius:var(--sf-radius-md);background:var(--sf-bg-surface);margin-bottom:var(--sf-space-3);overflow:hidden}:root[data-forge-ui=on] .sf-config-panel__summary{display:flex;align-items:center;justify-content:space-between;gap:var(--sf-space-3);padding:var(--sf-space-3) var(--sf-space-4);font-family:var(--sf-font-body);font-size:var(--sf-text-h4);font-weight:var(--sf-font-semibold);color:var(--sf-text-primary);cursor:pointer;list-style:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}:root[data-forge-ui=on] .sf-config-panel__summary::-webkit-details-marker{display:none}:root[data-forge-ui=on] .sf-config-panel__chevron{display:inline-block;width:12px;height:12px;transition:transform var(--sf-duration-fast) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-config-panel[data-expanded=true] .sf-config-panel__chevron,:root[data-forge-ui=on] details[open] .sf-config-panel__chevron{transform:rotate(90deg)}:root[data-forge-ui=on] .sf-config-panel[data-dirty=true] .sf-config-panel__summary:after{content:"";width:8px;height:8px;border-radius:var(--sf-radius-full);background:var(--sf-accent-primary);margin-left:var(--sf-space-2)}:root[data-forge-ui=on] .sf-config-panel__body{padding:var(--sf-space-3) var(--sf-space-4);border-top:1px solid var(--sf-border-subtle);display:grid;gap:var(--sf-space-3)}:root[data-forge-ui=on] .sf-config-panel__field{display:grid;gap:var(--sf-space-1)}:root[data-forge-ui=on] .sf-config-panel__field--invalid{color:var(--sf-accent-danger)}:root[data-forge-ui=on] .sf-config-panel__help{font-size:var(--sf-text-caption);color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-config-panel__error{font-size:var(--sf-text-caption);color:var(--sf-accent-danger)}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-config-panel__chevron{transition:none}}:root[data-forge-ui=on] .sf-story-card{position:relative;display:grid;grid-template-rows:auto 1fr auto;gap:var(--sf-space-2);padding:var(--sf-space-3);border-radius:var(--sf-radius-md);background:var(--sf-bg-surface);border:1px solid var(--sf-border-subtle);color:var(--sf-text-primary);text-decoration:none;cursor:pointer;transition:transform var(--sf-duration-fast) var(--sf-ease-spring),box-shadow var(--sf-duration-fast) var(--sf-ease-spring),border-color var(--sf-duration-fast) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-story-card[data-mode=list]{grid-template-columns:80px 1fr auto;grid-template-rows:auto;align-items:center}:root[data-forge-ui=on] .sf-story-card:focus-visible,:root[data-forge-ui=on] .sf-story-card:hover,:root[data-forge-ui=on] .sf-story-card[data-state=hover]{transform:translateY(-2px);box-shadow:var(--sf-shadow-md);border-color:var(--sf-accent-primary)}:root[data-forge-ui=on] .sf-story-card__cover{aspect-ratio:3/4;border-radius:var(--sf-radius-sm);background:var(--sf-bg-elevated);overflow:hidden}:root[data-forge-ui=on] .sf-story-card__cover img{width:100%;height:100%;-o-object-fit:cover;object-fit:cover;display:block}:root[data-forge-ui=on] .sf-story-card__title{font-family:var(--sf-font-body);font-size:var(--sf-text-h4);font-weight:var(--sf-font-semibold);color:var(--sf-text-primary);line-height:var(--sf-leading-snug)}:root[data-forge-ui=on] .sf-story-card__meta{display:flex;align-items:center;gap:var(--sf-space-2);font-size:var(--sf-text-caption);color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-story-card__progress{position:relative;height:4px;border-radius:var(--sf-radius-full);background:var(--sf-border-subtle);overflow:hidden}:root[data-forge-ui=on] .sf-story-card__progress-fill{position:absolute;inset:0;width:0;background:var(--sf-accent-forge);transition:width var(--sf-duration-base) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-story-card[data-status=done]{border-color:var(--sf-accent-complete)}:root[data-forge-ui=on] .sf-story-card[data-status=error]{border-color:var(--sf-accent-danger)}:root[data-forge-ui=on] .sf-story-card__actions{display:flex;gap:var(--sf-space-1);opacity:0;transition:opacity var(--sf-duration-fast) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-story-card:focus-within .sf-story-card__actions,:root[data-forge-ui=on] .sf-story-card:hover .sf-story-card__actions{opacity:1}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-story-card,:root[data-forge-ui=on] .sf-story-card__actions,:root[data-forge-ui=on] .sf-story-card__progress-fill{transition:none}:root[data-forge-ui=on] .sf-story-card:focus-visible,:root[data-forge-ui=on] .sf-story-card:hover{transform:none}}:root[data-forge-ui=on] .sf-toast-region{position:fixed;top:var(--sf-space-4);right:var(--sf-space-4);z-index:9999;display:flex;flex-direction:column;gap:var(--sf-space-2);pointer-events:none;max-width:380px}:root[data-forge-ui=on] .sf-toast-region--assertive{pointer-events:none}:root[data-forge-ui=on] .sf-toast{pointer-events:auto;display:grid;grid-template-columns:auto 1fr auto;align-items:start;gap:var(--sf-space-2);padding:var(--sf-space-3) var(--sf-space-4);border-radius:var(--sf-radius-md);background:var(--sf-bg-surface);border-left:4px solid var(--sf-accent-primary);box-shadow:var(--sf-shadow-md);font-family:var(--sf-font-body);font-size:var(--sf-text-body);color:var(--sf-text-primary);animation:sf-toast-enter var(--sf-duration-base) var(--sf-ease-spring)}:root[data-forge-ui=on] .sf-toast[data-variant=success]{border-left-color:var(--sf-accent-complete)}:root[data-forge-ui=on] .sf-toast[data-variant=warning]{border-left-color:var(--sf-accent-forge)}:root[data-forge-ui=on] .sf-toast[data-variant=error]{border-left-color:var(--sf-accent-danger)}:root[data-forge-ui=on] .sf-toast__message{line-height:var(--sf-leading-snug)}:root[data-forge-ui=on] .sf-toast__close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:var(--sf-radius-sm);color:var(--sf-text-secondary);cursor:pointer}:root[data-forge-ui=on] .sf-toast__close:hover{background:var(--sf-bg-elevated);color:var(--sf-text-primary)}@keyframes sf-toast-enter{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-toast{animation:none}}:root[data-forge-ui=on] .sf-library-forge{display:flex;flex-direction:column;gap:var(--sf-space-4)}:root[data-forge-ui=on] .sf-library-forge__viewbar{display:flex;align-items:center;justify-content:space-between;gap:var(--sf-space-3)}:root[data-forge-ui=on] .sf-library-forge__count{font-size:var(--sf-text-caption);color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-library-forge__viewmodes{display:inline-flex;gap:var(--sf-space-1);padding:var(--sf-space-1);border-radius:var(--sf-radius-md);background:var(--sf-bg-elevated)}:root[data-forge-ui=on] .sf-library-forge__viewmodes .sf-forge-btn[data-state=selected]{background:var(--sf-bg-surface);color:var(--sf-text-primary);box-shadow:var(--sf-shadow-sm)}:root[data-forge-ui=on] .sf-library-forge__grid{display:grid;gap:var(--sf-space-3)}:root[data-forge-ui=on] .sf-library-forge__grid[data-view=grid]{grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}:root[data-forge-ui=on] .sf-library-forge__grid[data-view=list]{grid-template-columns:1fr}:root[data-forge-ui=on] .sf-library-forge__empty{grid-column:1/-1;padding:var(--sf-space-8) var(--sf-space-4);text-align:center;font-size:var(--sf-text-caption);color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-story-card__body{display:flex;flex-direction:column;gap:var(--sf-space-1);min-width:0}:root[data-forge-ui=on] .sf-story-card__body .sf-story-card__title{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:root[data-forge-ui=on] .sf-theater{display:flex;flex-direction:column;gap:var(--sf-space-3);padding:var(--sf-space-4);border-radius:var(--sf-radius-lg);background:var(--sf-bg-surface);border:1px solid var(--sf-border-subtle,rgba(148,163,184,.18));transition:background .32s ease,border-color .32s ease}:root[data-forge-ui=on] .sf-theater__header{display:flex;align-items:center;justify-content:space-between}:root[data-forge-ui=on] .sf-theater__title{font-size:var(--sf-text-body);font-weight:600;color:var(--sf-text-primary)}:root[data-forge-ui=on] .sf-theater__state{font-size:var(--sf-text-caption);text-transform:uppercase;letter-spacing:.06em;color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-theater__agents{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:var(--sf-space-2)}:root[data-forge-ui=on] .sf-theater__empty{font-size:var(--sf-text-caption);color:var(--sf-text-secondary);text-align:center;padding:var(--sf-space-4) 0}:root[data-forge-ui=on] .sf-agent-bubble{display:flex;flex-direction:column;gap:var(--sf-space-1);padding:var(--sf-space-2);border-radius:var(--sf-radius-md);background:var(--sf-bg-elevated);border:1px solid transparent;transition:border-color .2s ease,transform .2s ease}:root[data-forge-ui=on] .sf-agent-bubble__head{display:flex;align-items:center;justify-content:space-between;font-size:var(--sf-text-caption)}:root[data-forge-ui=on] .sf-agent-bubble__name{font-weight:600;color:var(--sf-text-primary)}:root[data-forge-ui=on] .sf-agent-bubble__state{text-transform:uppercase;letter-spacing:.05em;color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-agent-bubble__msg{font-size:var(--sf-text-caption);color:var(--sf-text-primary);line-height:1.4;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}:root[data-forge-ui=on] .sf-agent-bubble[data-state=thinking]{border-color:rgba(99,102,241,.45)}:root[data-forge-ui=on] .sf-agent-bubble[data-state=speaking]{border-color:rgba(16,185,129,.45)}:root[data-forge-ui=on] .sf-agent-bubble[data-state=debating]{border-color:rgba(244,114,182,.55);transform:translateY(-1px)}:root[data-forge-ui=on] .sf-agent-bubble[data-state=voting]{border-color:rgba(245,158,11,.6)}:root[data-forge-ui=on] .sf-agent-bubble[data-state=done]{opacity:.7}:root[data-forge-ui=on] .sf-quality-gauge{display:flex;flex-direction:column;gap:var(--sf-space-2);padding:var(--sf-space-3);border-radius:var(--sf-radius-md);background:var(--sf-bg-elevated)}:root[data-forge-ui=on] .sf-quality-gauge__value{font-size:1.75rem;font-weight:700;color:var(--sf-text-primary);font-variant-numeric:tabular-nums}:root[data-forge-ui=on] .sf-quality-gauge__dims{display:flex;flex-wrap:wrap;gap:var(--sf-space-2);list-style:none;padding:0;margin:0}:root[data-forge-ui=on] .sf-quality-gauge__dim{display:inline-flex;align-items:center;gap:var(--sf-space-1);padding:0 var(--sf-space-2);border-radius:var(--sf-radius-pill,9999px);background:var(--sf-bg-surface);font-size:var(--sf-text-caption)}:root[data-forge-ui=on] .sf-quality-gauge__dim-name{color:var(--sf-text-secondary)}:root[data-forge-ui=on] .sf-quality-gauge__dim-value{color:var(--sf-text-primary);font-variant-numeric:tabular-nums;font-weight:600}:root[data-forge-ui=on] .sf-theater__graph{display:block;border-radius:var(--sf-radius-md);overflow:hidden;background:var(--sf-bg-elevated)}:root[data-forge-ui=on] .sf-character-graph{display:block;width:100%;height:auto;max-height:360px;touch-action:none}:root[data-forge-ui=on] .sf-theater__debate,:root[data-forge-ui=on] .sf-theater__reader{font-size:var(--sf-text-caption);color:var(--sf-text-primary);padding:var(--sf-space-1) var(--sf-space-2);border-radius:var(--sf-radius-sm,6px);background:var(--sf-bg-elevated)}:root[data-forge-ui=on] .sf-theater__debate-tag{display:inline-block;font-size:.65rem;font-weight:700;letter-spacing:.08em;color:rgba(236,72,153,.95);margin-right:var(--sf-space-2)}:root[data-forge-ui=on] [data-page=pipeline][data-state=generating] .sf-theater{background:linear-gradient(180deg,rgba(99,102,241,.05),var(--sf-bg-surface));border-color:rgba(99,102,241,.25)}:root[data-forge-ui=on] [data-page=pipeline][data-state=done] .sf-theater{background:linear-gradient(180deg,rgba(16,185,129,.06),var(--sf-bg-surface));border-color:rgba(16,185,129,.3)}:root[data-forge-ui=on] [data-page=pipeline][data-state=error] .sf-theater{background:linear-gradient(180deg,rgba(244,63,94,.06),var(--sf-bg-surface));border-color:rgba(244,63,94,.35);animation:sf-theater-shake .32s ease}:root[data-forge-ui=on] [data-page=pipeline][data-state=interrupted] .sf-theater{background:linear-gradient(180deg,rgba(245,158,11,.06),var(--sf-bg-surface));border-color:rgba(245,158,11,.35)}@keyframes sf-theater-shake{0%,to{transform:translateX(0)}20%{transform:translateX(-4px)}40%{transform:translateX(4px)}60%{transform:translateX(-2px)}80%{transform:translateX(2px)}}:root[data-forge-ui=on] .sf-reader{--sf-reader-bg:#f8fafc;--sf-reader-fg:#1f2937;--sf-reader-muted:#64748b;--sf-reader-card:#fff;--sf-reader-border:rgba(15,23,42,.08);--sf-reader-accent:var(--sf-color-brand-600,#4f46e5);--sf-reader-max-width:64ch;background:var(--sf-reader-bg);color:var(--sf-reader-fg);border-radius:14px;padding:12px;transition:background-color .2s ease,color .2s ease}:root[data-forge-ui=on] .sf-reader--sepia{--sf-reader-bg:#f4ecd8;--sf-reader-fg:#4b3a26;--sf-reader-muted:#8a7659;--sf-reader-card:#fbf5e3;--sf-reader-border:rgba(75,58,38,.16);--sf-reader-accent:#b45309}:root[data-forge-ui=on] .sf-reader--night{--sf-reader-bg:#0b1220;--sf-reader-fg:#e2e8f0;--sf-reader-muted:#94a3b8;--sf-reader-card:#111827;--sf-reader-border:rgba(148,163,184,.18);--sf-reader-accent:#a78bfa}:root[data-forge-ui=on] .sf-reader--col-narrow{--sf-reader-max-width:48ch}:root[data-forge-ui=on] .sf-reader--col-normal{--sf-reader-max-width:64ch}:root[data-forge-ui=on] .sf-reader--col-wide{--sf-reader-max-width:78ch}:root[data-forge-ui=on] .sf-reader .card{background:var(--sf-reader-card);color:var(--sf-reader-fg);border-color:var(--sf-reader-border)}:root[data-forge-ui=on] .sf-reader h2,:root[data-forge-ui=on] .sf-reader h3,:root[data-forge-ui=on] .sf-reader h4{color:var(--sf-reader-fg)}:root[data-forge-ui=on] .sf-reader__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:10px 12px;margin-bottom:12px;background:var(--sf-reader-card);border:1px solid var(--sf-reader-border);border-radius:12px;position:sticky;top:12px;z-index:5;backdrop-filter:saturate(140%) blur(6px)}:root[data-forge-ui=on] .sf-reader__group{display:inline-flex;align-items:center;gap:4px;padding:4px 6px;border-radius:8px;background:color-mix(in oklab,var(--sf-reader-bg) 70%,var(--sf-reader-card));border:1px solid var(--sf-reader-border)}:root[data-forge-ui=on] .sf-reader__group-label{font-size:10px;font-weight:700;color:var(--sf-reader-muted);letter-spacing:.04em;text-transform:uppercase;padding:0 4px}:root[data-forge-ui=on] .sf-reader__btn{width:24px;height:24px;border-radius:6px;border:none;background:transparent;color:var(--sf-reader-fg);font-weight:700;font-size:14px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:background-color .12s ease}:root[data-forge-ui=on] .sf-reader__btn:hover{background:color-mix(in oklab,var(--sf-reader-accent) 12%,transparent)}:root[data-forge-ui=on] .sf-reader__value{min-width:28px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px;font-weight:600;color:var(--sf-reader-fg)}:root[data-forge-ui=on] .sf-reader__chip{padding:3px 10px;border-radius:999px;border:1px solid var(--sf-reader-border);background:transparent;color:var(--sf-reader-muted);font-size:11px;font-weight:600;cursor:pointer;transition:all .12s ease}:root[data-forge-ui=on] .sf-reader__chip:hover{color:var(--sf-reader-fg);border-color:var(--sf-reader-accent)}:root[data-forge-ui=on] .sf-reader__chip.is-active{background:var(--sf-reader-accent);color:#fff;border-color:var(--sf-reader-accent)}:root[data-forge-ui=on] .sf-reader__theme{width:28px;height:28px;border-radius:999px;border:1px solid var(--sf-reader-border);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:14px;background:var(--sf-reader-card);color:var(--sf-reader-fg);transition:transform .12s ease,box-shadow .12s ease}:root[data-forge-ui=on] .sf-reader__theme--day{background:#fafafa;color:#1f2937}:root[data-forge-ui=on] .sf-reader__theme--sepia{background:#f4ecd8;color:#4b3a26}:root[data-forge-ui=on] .sf-reader__theme--night{background:#0b1220;color:#e2e8f0}:root[data-forge-ui=on] .sf-reader__theme.is-active{box-shadow:0 0 0 2px var(--sf-reader-accent);transform:scale(1.08)}:root[data-forge-ui=on] .sf-reader__bookmark{margin-left:auto;display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:8px;border:1px solid var(--sf-reader-border);background:transparent;color:var(--sf-reader-muted);font-size:12px;font-weight:600;cursor:pointer;transition:all .12s ease}:root[data-forge-ui=on] .sf-reader__bookmark:hover{color:var(--sf-reader-fg);border-color:var(--sf-reader-accent)}:root[data-forge-ui=on] .sf-reader__bookmark[aria-pressed=true]{background:color-mix(in oklab,var(--sf-reader-accent) 16%,transparent);color:var(--sf-reader-accent);border-color:var(--sf-reader-accent)}:root[data-forge-ui=on] .sf-reader__bookmark-label{font-size:11px;letter-spacing:.01em}:root[data-forge-ui=on] .sf-reader__prose{font-size:var(--sf-reader-font-size,18px);line-height:var(--sf-reader-line-height,1.9);font-family:var(--sf-reader-font-family,"Iowan Old Style","Charter","Source Serif Pro",Georgia,serif);color:var(--sf-reader-fg);max-width:var(--sf-reader-max-width,64ch);margin-inline:auto;white-space:pre-wrap;word-spacing:.01em;hyphens:auto}:root[data-forge-ui=on] .sf-reader__prose strong{color:inherit;font-weight:700}:root[data-forge-ui=on] .sf-reader__prose br{line-height:inherit}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-reader,:root[data-forge-ui=on] .sf-reader__bookmark,:root[data-forge-ui=on] .sf-reader__btn,:root[data-forge-ui=on] .sf-reader__chip,:root[data-forge-ui=on] .sf-reader__theme{transition:none}:root[data-forge-ui=on] [data-page=pipeline][data-state=error] .sf-theater{animation:none}:root[data-forge-ui=on] .sf-agent-bubble{transition:none}}:root[data-forge-ui=on] .sf-story-card__cover .sf-genre-orb{width:56px;height:56px;margin:var(--sf-space-3)}:root[data-forge-ui=on] .sf-reader__progress-bar{position:fixed;top:0;left:0;width:100%;height:3px;z-index:100;background:transparent;pointer-events:none}:root[data-forge-ui=on] .sf-reader__progress-fill{height:100%;background:var(--sf-accent-primary,#2563eb);transition:width .12s linear;transform-origin:left}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-reader__progress-fill{transition:none}}:root[data-forge-ui=on] .sf-reader__sidebar{position:fixed;top:0;right:0;bottom:0;width:280px;max-width:85vw;z-index:50;background:var(--sf-reader-card,#fff);border-left:1px solid var(--sf-reader-border,rgba(15,23,42,.08));display:flex;flex-direction:column;overflow:hidden;transform:translateX(100%);transition:transform var(--sf-duration-base,.25s) var(--sf-ease-spring,cubic-bezier(.4,0,.2,1))}:root[data-forge-ui=on] .sf-reader__sidebar[data-open=true]{transform:translateX(0)}:root[data-forge-ui=on] .sf-reader__sidebar-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--sf-reader-border,rgba(15,23,42,.08));font-size:13px;font-weight:600;color:var(--sf-reader-fg,#1f2937);flex-shrink:0}:root[data-forge-ui=on] .sf-reader__sidebar-close{width:28px;height:28px;border:none;border-radius:6px;background:transparent;color:var(--sf-reader-muted,#64748b);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:background-color .12s ease}:root[data-forge-ui=on] .sf-reader__sidebar-close:hover{background:color-mix(in oklab,var(--sf-reader-fg,#1f2937) 8%,transparent)}:root[data-forge-ui=on] .sf-reader__sidebar-list{flex:1;overflow-y:auto;padding:8px 0}:root[data-forge-ui=on] .sf-reader__sidebar-item{display:flex;align-items:baseline;gap:8px;padding:9px 16px;cursor:pointer;border:none;background:transparent;width:100%;text-align:left;transition:background-color .12s ease}:root[data-forge-ui=on] .sf-reader__sidebar-item:hover{background:color-mix(in oklab,var(--sf-reader-accent,#4f46e5) 6%,transparent)}:root[data-forge-ui=on] .sf-reader__sidebar-item[aria-current=true]{background:color-mix(in oklab,var(--sf-reader-accent,#4f46e5) 10%,transparent)}:root[data-forge-ui=on] .sf-reader__sidebar-item[aria-current=true] .sf-reader__sidebar-num{color:var(--sf-reader-accent,#4f46e5);font-weight:700}:root[data-forge-ui=on] .sf-reader__sidebar-num{font-size:11px;font-weight:600;color:var(--sf-reader-muted,#64748b);min-width:28px;flex-shrink:0}:root[data-forge-ui=on] .sf-reader__sidebar-title{font-size:13px;color:var(--sf-reader-fg,#1f2937);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:root[data-forge-ui=on] .sf-reader__sidebar-eta{font-size:10px;color:var(--sf-reader-muted,#64748b);flex-shrink:0;white-space:nowrap}:root[data-forge-ui=on] .sf-reader__sidebar-scrim{position:fixed;inset:0;z-index:49;background:rgba(0,0,0,.3);opacity:0;pointer-events:none;transition:opacity var(--sf-duration-base,.25s) ease}:root[data-forge-ui=on] .sf-reader__sidebar-scrim[data-open=true]{opacity:1;pointer-events:auto}:root[data-forge-ui=on] .sf-reader__sidebar-toggle{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:8px;border:1px solid var(--sf-reader-border,rgba(15,23,42,.08));background:transparent;color:var(--sf-reader-muted,#64748b);font-size:12px;font-weight:600;cursor:pointer;transition:all .12s ease}:root[data-forge-ui=on] .sf-reader__sidebar-toggle:hover{color:var(--sf-reader-fg,#1f2937);border-color:var(--sf-reader-accent,#4f46e5)}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-reader__sidebar,:root[data-forge-ui=on] .sf-reader__sidebar-close,:root[data-forge-ui=on] .sf-reader__sidebar-item,:root[data-forge-ui=on] .sf-reader__sidebar-scrim,:root[data-forge-ui=on] .sf-reader__sidebar-toggle{transition:none}}:root[data-forge-ui=on] .sf-reader__portrait{display:block;width:56px;height:56px;border-radius:50%;-o-object-fit:cover;object-fit:cover;border:2px solid var(--sf-reader-border,rgba(15,23,42,.08));float:left;margin:0 12px 4px 0;opacity:0;animation:sf-portrait-fadein .4s ease forwards}@keyframes sf-portrait-fadein{to{opacity:1}}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-reader__portrait{animation:none;opacity:1}}:root[data-forge-ui=on] .sf-reader__para-block{overflow:hidden;margin-bottom:.5em}:root[data-forge-ui=on] .sf-reader__para-block:after{content:"";display:table;clear:both}:root[data-forge-ui=on] .sf-branch-tree-wrap{margin-top:12px}:root[data-forge-ui=on] .sf-branch-tree-block{position:relative;margin-top:12px;border:1px solid var(--sf-border-subtle,#2d3348);border-radius:8px;overflow:hidden;background:var(--sf-bg-surface,#1a1f2e)}:root[data-forge-ui=on] .sf-branch-tree{position:relative;display:flex;flex-direction:column;background:var(--sf-bg-surface,#1a1f2e);border:1px solid var(--sf-border-subtle,#2d3348);border-radius:var(--sf-radius-lg,8px);overflow:hidden}:root[data-forge-ui=on] .sf-branch-tree__canvas{display:block;width:100%;touch-action:none;cursor:grab;outline:none}:root[data-forge-ui=on] .sf-branch-tree__canvas:focus-visible{outline:2px solid var(--sf-accent-primary,#3b82f6);outline-offset:-2px}:root[data-forge-ui=on] .sf-branch-tree__canvas:active{cursor:grabbing}:root[data-forge-ui=on] .sf-branch-tree__minimap{border:1px solid var(--sf-border-subtle,#2d3348);border-radius:var(--sf-radius-sm,4px)}:root[data-forge-ui=on] .sf-branch-tree__minimap,:root[data-forge-ui=on] .sf-branch-tree__minimap-label{position:absolute;bottom:var(--sf-space-3,12px);right:var(--sf-space-3,12px);pointer-events:none;background:rgba(15,18,25,.7)}:root[data-forge-ui=on] .sf-branch-tree__minimap-label{font-size:var(--sf-text-xs,12px);color:var(--sf-text-secondary,#9ca3af);padding:2px 8px;border-radius:999px}:root[data-forge-ui=on] .sf-branch-tree__toolbar{display:flex;align-items:center;gap:var(--sf-space-2,8px);padding:var(--sf-space-2,8px) var(--sf-space-3,12px);border-top:1px solid var(--sf-border-subtle,#2d3348);background:var(--sf-bg-elevated,#242a3d)}:root[data-forge-ui=on] .sf-branch-tree__sr-list{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (prefers-reduced-motion:reduce){:root[data-forge-ui=on] .sf-branch-tree__canvas{cursor:default}}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: } -/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.left-0{left:0}.left-0\.5{left:.125rem}.left-3{left:.75rem}.left-\[calc\(100\%-0\.95rem\)\]{left:calc(100% - .95rem)}.right-2{right:.5rem}.top-0{top:0}.top-0\.5{top:.125rem}.top-1\/2{top:50%}.top-2{top:.5rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0{margin-left:0}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-96{max-height:24rem}.max-h-\[600px\]{max-height:600px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-20{width:5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[110px\]{min-width:110px}.min-w-\[28px\]{min-width:28px}.min-w-\[48px\]{min-width:48px}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-7xl{max-width:80rem}.max-w-\[100px\]{max-width:100px}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-2{--tw-translate-y:-0.5rem}.-translate-y-2,.translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.translate-y-0{--tw-translate-y:0px}.rotate-180,.translate-y-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1\.5{row-gap:.375rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.625rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-surface-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(241 245 249/var(--tw-divide-opacity,1))}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:12px}.rounded-md{border-radius:8px}.rounded-xl{border-radius:16px}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-200{--tw-border-opacity:1;border-color:rgb(253 230 138/var(--tw-border-opacity,1))}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-blue-400{--tw-border-opacity:1;border-color:rgb(96 165 250/var(--tw-border-opacity,1))}.border-brand-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-brand-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-brand-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-emerald-200{--tw-border-opacity:1;border-color:rgb(167 243 208/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-green-400{--tw-border-opacity:1;border-color:rgb(74 222 128/var(--tw-border-opacity,1))}.border-green-800{--tw-border-opacity:1;border-color:rgb(22 101 52/var(--tw-border-opacity,1))}.border-indigo-200{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.border-orange-200{--tw-border-opacity:1;border-color:rgb(254 215 170/var(--tw-border-opacity,1))}.border-orange-400{--tw-border-opacity:1;border-color:rgb(251 146 60/var(--tw-border-opacity,1))}.border-pink-200{--tw-border-opacity:1;border-color:rgb(251 207 232/var(--tw-border-opacity,1))}.border-purple-200{--tw-border-opacity:1;border-color:rgb(233 213 255/var(--tw-border-opacity,1))}.border-purple-400{--tw-border-opacity:1;border-color:rgb(192 132 252/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-rose-200{--tw-border-opacity:1;border-color:rgb(254 205 211/var(--tw-border-opacity,1))}.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.border-surface-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity,1))}.border-surface-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.border-violet-100{--tw-border-opacity:1;border-color:rgb(237 233 254/var(--tw-border-opacity,1))}.border-violet-200{--tw-border-opacity:1;border-color:rgb(221 214 254/var(--tw-border-opacity,1))}.border-yellow-200{--tw-border-opacity:1;border-color:rgb(254 240 138/var(--tw-border-opacity,1))}.bg-amber-100{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))}.bg-amber-200{--tw-bg-opacity:1;background-color:rgb(253 230 138/var(--tw-bg-opacity,1))}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.bg-amber-500{--tw-bg-opacity:1;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))}.bg-amber-600{--tw-bg-opacity:1;background-color:rgb(217 119 6/var(--tw-bg-opacity,1))}.bg-black\/30{background-color:rgba(0,0,0,.3)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-brand-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-brand-50\/30{background-color:rgba(239,246,255,.3)}.bg-brand-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-brand-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-emerald-100{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.bg-emerald-50{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity,1))}.bg-emerald-600{--tw-bg-opacity:1;background-color:rgb(5 150 105/var(--tw-bg-opacity,1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-green-500\/10{background-color:rgba(34,197,94,.1)}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.bg-orange-500{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity,1))}.bg-pink-50{--tw-bg-opacity:1;background-color:rgb(253 242 248/var(--tw-bg-opacity,1))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(250 245 255/var(--tw-bg-opacity,1))}.bg-purple-500{--tw-bg-opacity:1;background-color:rgb(168 85 247/var(--tw-bg-opacity,1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(254 202 202/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-red-900\/20{background-color:rgba(127,29,29,.2)}.bg-rose-100{--tw-bg-opacity:1;background-color:rgb(255 228 230/var(--tw-bg-opacity,1))}.bg-rose-50{--tw-bg-opacity:1;background-color:rgb(255 241 242/var(--tw-bg-opacity,1))}.bg-sky-50{--tw-bg-opacity:1;background-color:rgb(240 249 255/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity,1))}.bg-slate-400{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity,1))}.bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-surface-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-surface-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.bg-surface-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-surface-50\/60{background-color:rgba(248,250,252,.6)}.bg-violet-100{--tw-bg-opacity:1;background-color:rgb(237 233 254/var(--tw-bg-opacity,1))}.bg-violet-50{--tw-bg-opacity:1;background-color:rgb(245 243 255/var(--tw-bg-opacity,1))}.bg-violet-600{--tw-bg-opacity:1;background-color:rgb(124 58 237/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/15{background-color:hsla(0,0%,100%,.15)}.bg-white\/60{background-color:hsla(0,0%,100%,.6)}.bg-white\/70{background-color:hsla(0,0%,100%,.7)}.bg-white\/80{background-color:hsla(0,0%,100%,.8)}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity,1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-brand-50{--tw-gradient-from:#eff6ff var(--tw-gradient-from-position);--tw-gradient-to:rgba(239,246,255,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand-500{--tw-gradient-from:#3b82f6 var(--tw-gradient-from-position);--tw-gradient-to:rgba(59,130,246,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand-500\/10{--tw-gradient-from:rgba(59,130,246,.1) var(--tw-gradient-from-position);--tw-gradient-to:rgba(59,130,246,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand-600{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-orange-50{--tw-gradient-from:#fff7ed var(--tw-gradient-from-position);--tw-gradient-to:rgba(255,247,237,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-orange-500{--tw-gradient-from:#f97316 var(--tw-gradient-from-position);--tw-gradient-to:rgba(249,115,22,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-violet-50{--tw-gradient-from:#f5f3ff var(--tw-gradient-from-position);--tw-gradient-to:rgba(245,243,255,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-brand-100{--tw-gradient-to:#dbeafe var(--tw-gradient-to-position)}.to-brand-500{--tw-gradient-to:#3b82f6 var(--tw-gradient-to-position)}.to-orange-100{--tw-gradient-to:#ffedd5 var(--tw-gradient-to-position)}.to-red-500{--tw-gradient-to:#ef4444 var(--tw-gradient-to-position)}.to-violet-100{--tw-gradient-to:#ede9fe var(--tw-gradient-to-position)}.to-violet-50{--tw-gradient-to:#f5f3ff var(--tw-gradient-to-position)}.to-violet-500{--tw-gradient-to:#8b5cf6 var(--tw-gradient-to-position)}.to-violet-500\/10{--tw-gradient-to:rgba(139,92,246,.1) var(--tw-gradient-to-position)}.to-violet-600{--tw-gradient-to:#7c3aed var(--tw-gradient-to-position)}.fill-amber-400{fill:#fbbf24}.fill-brand-500{fill:#3b82f6}.fill-slate-500{fill:#64748b}.fill-surface-200{fill:#e2e8f0}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-12{padding:3rem}.p-16{padding:4rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.\!px-2\.5{padding-left:.625rem!important;padding-right:.625rem!important}.\!py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-5{padding-bottom:1.25rem}.pl-3{padding-left:.75rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-\[18px\]{padding-top:18px}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:Inter,system-ui,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[9px\]{font-size:9px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-\[1\.9\]{line-height:1.9}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-normal{letter-spacing:0}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-amber-400{--tw-text-opacity:1;color:rgb(251 191 36/var(--tw-text-opacity,1))}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.text-amber-700\/80{color:rgba(180,83,9,.8)}.text-amber-800{--tw-text-opacity:1;color:rgb(146 64 14/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-brand-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-brand-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-brand-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-emerald-400{--tw-text-opacity:1;color:rgb(52 211 153/var(--tw-text-opacity,1))}.text-emerald-500{--tw-text-opacity:1;color:rgb(16 185 129/var(--tw-text-opacity,1))}.text-emerald-600{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity,1))}.text-emerald-700{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.text-emerald-700\/80{color:rgba(4,120,87,.8)}.text-emerald-800{--tw-text-opacity:1;color:rgb(6 95 70/var(--tw-text-opacity,1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity,1))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-indigo-700{--tw-text-opacity:1;color:rgb(67 56 202/var(--tw-text-opacity,1))}.text-orange-400{--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-orange-700{--tw-text-opacity:1;color:rgb(194 65 12/var(--tw-text-opacity,1))}.text-pink-700{--tw-text-opacity:1;color:rgb(190 24 93/var(--tw-text-opacity,1))}.text-purple-700{--tw-text-opacity:1;color:rgb(126 34 206/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-rose-400{--tw-text-opacity:1;color:rgb(251 113 133/var(--tw-text-opacity,1))}.text-rose-500{--tw-text-opacity:1;color:rgb(244 63 94/var(--tw-text-opacity,1))}.text-rose-600{--tw-text-opacity:1;color:rgb(225 29 72/var(--tw-text-opacity,1))}.text-rose-700{--tw-text-opacity:1;color:rgb(190 18 60/var(--tw-text-opacity,1))}.text-sky-400{--tw-text-opacity:1;color:rgb(56 189 248/var(--tw-text-opacity,1))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1))}.text-violet-400{--tw-text-opacity:1;color:rgb(167 139 250/var(--tw-text-opacity,1))}.text-violet-500{--tw-text-opacity:1;color:rgb(139 92 246/var(--tw-text-opacity,1))}.text-violet-600{--tw-text-opacity:1;color:rgb(124 58 237/var(--tw-text-opacity,1))}.text-violet-700{--tw-text-opacity:1;color:rgb(109 40 217/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/90{color:hsla(0,0%,100%,.9)}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.text-yellow-700{--tw-text-opacity:1;color:rgb(161 98 7/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.accent-brand-600{accent-color:#2563eb}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-brand-500\/25{--tw-shadow-color:rgba(59,130,246,.25);--tw-shadow:var(--tw-shadow-colored)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-brand-100{--tw-ring-opacity:1;--tw-ring-color:rgb(219 234 254/var(--tw-ring-opacity,1))}.ring-brand-200{--tw-ring-opacity:1;--tw-ring-color:rgb(191 219 254/var(--tw-ring-opacity,1))}.sepia{--tw-sepia:sepia(100%)}.filter,.sepia{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-sm{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-transform{transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}[x-cloak]{display:none!important}.sf-toggle{display:inline-flex;flex-shrink:0}.sf-toggle-track{display:block;width:36px;height:20px;background:#cbd5e1;border-radius:9999px;position:relative;transition:background var(--sf-duration-fast) var(--sf-ease-spring)}.dark .sf-toggle-track{background:#475569}.sf-toggle.active .sf-toggle-track{background:var(--sf-color-brand-600)}.sf-toggle-thumb{display:block;width:16px;height:16px;background:#fff;border-radius:9999px;position:absolute;top:2px;left:2px;transition:transform var(--sf-duration-fast) var(--sf-ease-spring);box-shadow:0 1px 3px rgba(0,0,0,.15)}.sf-toggle.active .sf-toggle-thumb{transform:translateX(16px)}input[type=range].sf-range{-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;width:100%;height:6px;background:#e2e8f0!important;border-radius:9999px;outline:none;border:none;padding:0;margin:8px 0}.dark input[type=range].sf-range{background:#334155!important}input[type=range].sf-range::-webkit-slider-runnable-track{height:6px;background:transparent;border-radius:9999px}input[type=range].sf-range::-webkit-slider-thumb{-webkit-appearance:none!important;appearance:none!important;width:14px;height:14px;background:#2563eb!important;border-radius:50%;cursor:pointer;border:2px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.2);margin-top:-4px;-webkit-transition:transform .15s ease,box-shadow .15s ease;transition:transform .15s ease,box-shadow .15s ease}input[type=range].sf-range::-webkit-slider-thumb:hover{transform:scale(1.15);box-shadow:0 2px 8px rgba(0,0,0,.3)}input[type=range].sf-range::-moz-range-track{height:6px;background:#e2e8f0;border-radius:9999px;border:none}.dark input[type=range].sf-range::-moz-range-track{background:#334155}input[type=range].sf-range::-moz-range-thumb{width:14px;height:14px;background:#2563eb;border:2px solid #fff;border-radius:50%;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.2)}details[open] .details-chevron{transform:rotate(180deg)}@media (prefers-reduced-motion:reduce){*,:after,:before{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.last\:mb-0:last-child{margin-bottom:0}.last\:border-b-0:last-child{border-bottom-width:0}.hover\:border-blue-300:hover{--tw-border-opacity:1;border-color:rgb(147 197 253/var(--tw-border-opacity,1))}.hover\:border-brand-500:hover{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.hover\:border-green-300:hover{--tw-border-opacity:1;border-color:rgb(134 239 172/var(--tw-border-opacity,1))}.hover\:border-orange-300:hover{--tw-border-opacity:1;border-color:rgb(253 186 116/var(--tw-border-opacity,1))}.hover\:border-purple-300:hover{--tw-border-opacity:1;border-color:rgb(216 180 254/var(--tw-border-opacity,1))}.hover\:border-violet-400:hover{--tw-border-opacity:1;border-color:rgb(167 139 250/var(--tw-border-opacity,1))}.hover\:bg-amber-100:hover{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))}.hover\:bg-amber-200:hover{--tw-bg-opacity:1;background-color:rgb(253 230 138/var(--tw-bg-opacity,1))}.hover\:bg-amber-300:hover{--tw-bg-opacity:1;background-color:rgb(252 211 77/var(--tw-bg-opacity,1))}.hover\:bg-amber-700:hover{--tw-bg-opacity:1;background-color:rgb(180 83 9/var(--tw-bg-opacity,1))}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-brand-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.hover\:bg-brand-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-emerald-100:hover{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.hover\:bg-emerald-200:hover{--tw-bg-opacity:1;background-color:rgb(167 243 208/var(--tw-bg-opacity,1))}.hover\:bg-emerald-50:hover{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.hover\:bg-emerald-700:hover{--tw-bg-opacity:1;background-color:rgb(4 120 87/var(--tw-bg-opacity,1))}.hover\:bg-red-200:hover{--tw-bg-opacity:1;background-color:rgb(254 202 202/var(--tw-bg-opacity,1))}.hover\:bg-red-50:hover{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.hover\:bg-rose-100:hover{--tw-bg-opacity:1;background-color:rgb(255 228 230/var(--tw-bg-opacity,1))}.hover\:bg-rose-200:hover{--tw-bg-opacity:1;background-color:rgb(254 205 211/var(--tw-bg-opacity,1))}.hover\:bg-surface-100:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.hover\:bg-surface-200:hover{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.hover\:bg-surface-50:hover{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.hover\:bg-violet-100:hover{--tw-bg-opacity:1;background-color:rgb(237 233 254/var(--tw-bg-opacity,1))}.hover\:bg-violet-200:hover{--tw-bg-opacity:1;background-color:rgb(221 214 254/var(--tw-bg-opacity,1))}.hover\:bg-violet-50:hover{--tw-bg-opacity:1;background-color:rgb(245 243 255/var(--tw-bg-opacity,1))}.hover\:bg-violet-700:hover{--tw-bg-opacity:1;background-color:rgb(109 40 217/var(--tw-bg-opacity,1))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.hover\:text-amber-700:hover{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.hover\:text-amber-800:hover{--tw-text-opacity:1;color:rgb(146 64 14/var(--tw-text-opacity,1))}.hover\:text-brand-600:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.hover\:text-brand-700:hover{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.hover\:text-emerald-600:hover{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity,1))}.hover\:text-emerald-700:hover{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.hover\:text-emerald-800:hover{--tw-text-opacity:1;color:rgb(6 95 70/var(--tw-text-opacity,1))}.hover\:text-red-500:hover{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.hover\:text-red-600:hover{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.hover\:text-red-800:hover{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.hover\:text-rose-700:hover{--tw-text-opacity:1;color:rgb(190 18 60/var(--tw-text-opacity,1))}.hover\:text-slate-600:hover{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.hover\:text-slate-700:hover{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.hover\:text-slate-800:hover{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1))}.hover\:text-violet-600:hover{--tw-text-opacity:1;color:rgb(124 58 237/var(--tw-text-opacity,1))}.hover\:text-violet-700:hover{--tw-text-opacity:1;color:rgb(109 40 217/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.hover\:shadow-md:hover,.hover\:shadow-sm:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-sm:hover{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.focus\:not-sr-only:focus{position:static;width:auto;height:auto;padding:0;margin:0;overflow:visible;clip:auto;white-space:normal}.focus\:fixed:focus{position:fixed}.focus\:left-2:focus{left:.5rem}.focus\:top-2:focus{top:.5rem}.focus\:z-50:focus{z-index:50}.focus\:rounded-lg:focus{border-radius:12px}.focus\:border-brand-500:focus{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.focus\:bg-brand-600:focus{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.focus\:px-4:focus{padding-left:1rem;padding-right:1rem}.focus\:py-2:focus{padding-top:.5rem;padding-bottom:.5rem}.focus\:text-sm:focus{font-size:.875rem;line-height:1.25rem}.focus\:font-semibold:focus{font-weight:600}.focus\:text-white:focus{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-brand-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(191 219 254/var(--tw-ring-opacity,1))}.focus\:ring-brand-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.focus\:ring-brand-500\/20:focus{--tw-ring-color:rgba(59,130,246,.2)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.group[open] .group-open\:rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:bg-brand-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.group:hover .group-hover\:opacity-100{opacity:1}.dark\:border-amber-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(146 64 14/var(--tw-border-opacity,1))}.dark\:border-blue-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(30 64 175/var(--tw-border-opacity,1))}.dark\:border-brand-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(30 64 175/var(--tw-border-opacity,1))}.dark\:border-emerald-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(6 95 70/var(--tw-border-opacity,1))}.dark\:border-green-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(22 101 52/var(--tw-border-opacity,1))}.dark\:border-indigo-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(55 48 163/var(--tw-border-opacity,1))}.dark\:border-orange-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(154 52 18/var(--tw-border-opacity,1))}.dark\:border-pink-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(157 23 77/var(--tw-border-opacity,1))}.dark\:border-purple-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(107 33 168/var(--tw-border-opacity,1))}.dark\:border-red-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(153 27 27/var(--tw-border-opacity,1))}.dark\:border-slate-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(51 65 85/var(--tw-border-opacity,1))}.dark\:border-slate-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(30 41 59/var(--tw-border-opacity,1))}.dark\:border-violet-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(91 33 182/var(--tw-border-opacity,1))}.dark\:border-yellow-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(133 77 14/var(--tw-border-opacity,1))}.dark\:bg-amber-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(146 64 14/var(--tw-bg-opacity,1))}.dark\:bg-amber-900\/20:is(.dark *){background-color:rgba(120,53,15,.2)}.dark\:bg-amber-900\/30:is(.dark *){background-color:rgba(120,53,15,.3)}.dark\:bg-blue-900\/20:is(.dark *){background-color:rgba(30,58,138,.2)}.dark\:bg-emerald-900\/20:is(.dark *){background-color:rgba(6,78,59,.2)}.dark\:bg-emerald-900\/30:is(.dark *){background-color:rgba(6,78,59,.3)}.dark\:bg-green-900\/30:is(.dark *){background-color:rgba(20,83,45,.3)}.dark\:bg-indigo-900\/20:is(.dark *){background-color:rgba(49,46,129,.2)}.dark\:bg-orange-900\/20:is(.dark *){background-color:rgba(124,45,18,.2)}.dark\:bg-pink-900\/20:is(.dark *){background-color:rgba(131,24,67,.2)}.dark\:bg-purple-900\/20:is(.dark *){background-color:rgba(88,28,135,.2)}.dark\:bg-red-900\/20:is(.dark *){background-color:rgba(127,29,29,.2)}.dark\:bg-red-900\/30:is(.dark *){background-color:rgba(127,29,29,.3)}.dark\:bg-red-900\/40:is(.dark *){background-color:rgba(127,29,29,.4)}.dark\:bg-rose-900\/20:is(.dark *){background-color:rgba(136,19,55,.2)}.dark\:bg-rose-900\/30:is(.dark *){background-color:rgba(136,19,55,.3)}.dark\:bg-slate-600:is(.dark *){--tw-bg-opacity:1;background-color:rgb(71 85 105/var(--tw-bg-opacity,1))}.dark\:bg-slate-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.dark\:bg-slate-800\/40:is(.dark *){background-color:rgba(30,41,59,.4)}.dark\:bg-slate-900\/20:is(.dark *){background-color:rgba(15,23,42,.2)}.dark\:bg-surface-100:is(.dark *){--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.dark\:bg-violet-900\/20:is(.dark *){background-color:rgba(76,29,149,.2)}.dark\:bg-violet-900\/30:is(.dark *){background-color:rgba(76,29,149,.3)}.dark\:bg-yellow-900\/20:is(.dark *){background-color:rgba(113,63,18,.2)}.dark\:from-orange-900\/30:is(.dark *){--tw-gradient-from:rgba(124,45,18,.3) var(--tw-gradient-from-position);--tw-gradient-to:rgba(124,45,18,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.dark\:from-violet-900\/30:is(.dark *){--tw-gradient-from:rgba(76,29,149,.3) var(--tw-gradient-from-position);--tw-gradient-to:rgba(76,29,149,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.dark\:to-brand-800\/30:is(.dark *){--tw-gradient-to:rgba(30,64,175,.3) var(--tw-gradient-to-position)}.dark\:to-orange-800\/30:is(.dark *){--tw-gradient-to:rgba(154,52,18,.3) var(--tw-gradient-to-position)}.dark\:to-violet-400\/10:is(.dark *){--tw-gradient-to:rgba(167,139,250,.1) var(--tw-gradient-to-position)}.dark\:to-violet-800\/30:is(.dark *){--tw-gradient-to:rgba(91,33,182,.3) var(--tw-gradient-to-position)}.dark\:to-violet-900\/20:is(.dark *){--tw-gradient-to:rgba(76,29,149,.2) var(--tw-gradient-to-position)}.dark\:fill-slate-400:is(.dark *){fill:#94a3b8}.dark\:text-amber-200:is(.dark *){--tw-text-opacity:1;color:rgb(253 230 138/var(--tw-text-opacity,1))}.dark\:text-amber-300:is(.dark *){--tw-text-opacity:1;color:rgb(252 211 77/var(--tw-text-opacity,1))}.dark\:text-amber-300\/80:is(.dark *){color:rgba(252,211,77,.8)}.dark\:text-amber-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 191 36/var(--tw-text-opacity,1))}.dark\:text-amber-500:is(.dark *){--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity,1))}.dark\:text-emerald-200:is(.dark *){--tw-text-opacity:1;color:rgb(167 243 208/var(--tw-text-opacity,1))}.dark\:text-emerald-300\/80:is(.dark *){color:rgba(110,231,183,.8)}.dark\:text-emerald-400:is(.dark *){--tw-text-opacity:1;color:rgb(52 211 153/var(--tw-text-opacity,1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.dark\:text-indigo-400:is(.dark *){--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.dark\:text-orange-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity,1))}.dark\:text-pink-400:is(.dark *){--tw-text-opacity:1;color:rgb(244 114 182/var(--tw-text-opacity,1))}.dark\:text-purple-400:is(.dark *){--tw-text-opacity:1;color:rgb(192 132 252/var(--tw-text-opacity,1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.dark\:text-rose-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 113 133/var(--tw-text-opacity,1))}.dark\:text-slate-100:is(.dark *){--tw-text-opacity:1;color:rgb(241 245 249/var(--tw-text-opacity,1))}.dark\:text-slate-200:is(.dark *){--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.dark\:text-slate-300:is(.dark *){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.dark\:text-slate-400:is(.dark *){--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.dark\:text-slate-500:is(.dark *){--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.dark\:text-slate-600:is(.dark *){--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.dark\:text-violet-400:is(.dark *){--tw-text-opacity:1;color:rgb(167 139 250/var(--tw-text-opacity,1))}.dark\:text-yellow-400:is(.dark *){--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.dark\:ring-brand-700:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgb(29 78 216/var(--tw-ring-opacity,1))}.dark\:hover\:border-brand-600:hover:is(.dark *){--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.dark\:hover\:border-violet-600:hover:is(.dark *){--tw-border-opacity:1;border-color:rgb(124 58 237/var(--tw-border-opacity,1))}.dark\:hover\:bg-amber-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(180 83 9/var(--tw-bg-opacity,1))}.dark\:hover\:bg-amber-800\/40:hover:is(.dark *){background-color:rgba(146,64,14,.4)}.dark\:hover\:bg-amber-900\/40:hover:is(.dark *){background-color:rgba(120,53,15,.4)}.dark\:hover\:bg-emerald-800\/40:hover:is(.dark *){background-color:rgba(6,95,70,.4)}.dark\:hover\:bg-emerald-900\/20:hover:is(.dark *){background-color:rgba(6,78,59,.2)}.dark\:hover\:bg-emerald-900\/40:hover:is(.dark *){background-color:rgba(6,78,59,.4)}.dark\:hover\:bg-red-800:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(153 27 27/var(--tw-bg-opacity,1))}.dark\:hover\:bg-red-900\/20:hover:is(.dark *){background-color:rgba(127,29,29,.2)}.dark\:hover\:bg-rose-800\/40:hover:is(.dark *){background-color:rgba(159,18,57,.4)}.dark\:hover\:bg-slate-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity,1))}.dark\:hover\:bg-surface-100:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.dark\:hover\:bg-violet-800\/40:hover:is(.dark *){background-color:rgba(91,33,182,.4)}.dark\:hover\:bg-violet-900\/20:hover:is(.dark *){background-color:rgba(76,29,149,.2)}@media (min-width:640px){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:768px){.md\:mx-6{margin-left:1.5rem;margin-right:1.5rem}.md\:ml-60{margin-left:15rem}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:p-10{padding:2.5rem}.md\:p-6{padding:1.5rem}.md\:p-8{padding:2rem}.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width:1024px){.lg\:col-span-5{grid-column:span 5/span 5}.lg\:col-span-7{grid-column:span 7/span 7}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:p-8{padding:2rem}} \ No newline at end of file +/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.left-0{left:0}.left-0\.5{left:.125rem}.left-3{left:.75rem}.left-\[calc\(100\%-0\.95rem\)\]{left:calc(100% - .95rem)}.right-2{right:.5rem}.top-0{top:0}.top-0\.5{top:.125rem}.top-1\/2{top:50%}.top-2{top:.5rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0{margin-left:0}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-96{max-height:24rem}.max-h-\[600px\]{max-height:600px}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-64{width:16rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[110px\]{min-width:110px}.min-w-\[48px\]{min-width:48px}.min-w-full{min-width:100%}.max-w-3xl{max-width:48rem}.max-w-5xl{max-width:64rem}.max-w-7xl{max-width:80rem}.max-w-\[100px\]{max-width:100px}.max-w-md{max-width:28rem}.max-w-none{max-width:none}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-2{--tw-translate-y:-0.5rem}.-translate-y-2,.translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.translate-y-0{--tw-translate-y:0px}.rotate-180,.translate-y-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1\.5{row-gap:.375rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.625rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-surface-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(241 245 249/var(--tw-divide-opacity,1))}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:12px}.rounded-md{border-radius:8px}.rounded-xl{border-radius:16px}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-200{--tw-border-opacity:1;border-color:rgb(253 230 138/var(--tw-border-opacity,1))}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-blue-400{--tw-border-opacity:1;border-color:rgb(96 165 250/var(--tw-border-opacity,1))}.border-brand-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-brand-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-brand-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-emerald-200{--tw-border-opacity:1;border-color:rgb(167 243 208/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-green-400{--tw-border-opacity:1;border-color:rgb(74 222 128/var(--tw-border-opacity,1))}.border-indigo-200{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.border-orange-200{--tw-border-opacity:1;border-color:rgb(254 215 170/var(--tw-border-opacity,1))}.border-orange-400{--tw-border-opacity:1;border-color:rgb(251 146 60/var(--tw-border-opacity,1))}.border-pink-200{--tw-border-opacity:1;border-color:rgb(251 207 232/var(--tw-border-opacity,1))}.border-purple-200{--tw-border-opacity:1;border-color:rgb(233 213 255/var(--tw-border-opacity,1))}.border-purple-400{--tw-border-opacity:1;border-color:rgb(192 132 252/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-rose-200{--tw-border-opacity:1;border-color:rgb(254 205 211/var(--tw-border-opacity,1))}.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.border-surface-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity,1))}.border-surface-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.border-violet-100{--tw-border-opacity:1;border-color:rgb(237 233 254/var(--tw-border-opacity,1))}.border-violet-200{--tw-border-opacity:1;border-color:rgb(221 214 254/var(--tw-border-opacity,1))}.border-yellow-200{--tw-border-opacity:1;border-color:rgb(254 240 138/var(--tw-border-opacity,1))}.bg-amber-100{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))}.bg-amber-200{--tw-bg-opacity:1;background-color:rgb(253 230 138/var(--tw-bg-opacity,1))}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.bg-amber-500{--tw-bg-opacity:1;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))}.bg-amber-600{--tw-bg-opacity:1;background-color:rgb(217 119 6/var(--tw-bg-opacity,1))}.bg-black\/30{background-color:rgba(0,0,0,.3)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-brand-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-brand-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-brand-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-emerald-100{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.bg-emerald-50{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity,1))}.bg-emerald-600{--tw-bg-opacity:1;background-color:rgb(5 150 105/var(--tw-bg-opacity,1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.bg-pink-50{--tw-bg-opacity:1;background-color:rgb(253 242 248/var(--tw-bg-opacity,1))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(250 245 255/var(--tw-bg-opacity,1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-red-200{--tw-bg-opacity:1;background-color:rgb(254 202 202/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-red-900\/20{background-color:rgba(127,29,29,.2)}.bg-rose-100{--tw-bg-opacity:1;background-color:rgb(255 228 230/var(--tw-bg-opacity,1))}.bg-rose-50{--tw-bg-opacity:1;background-color:rgb(255 241 242/var(--tw-bg-opacity,1))}.bg-sky-50{--tw-bg-opacity:1;background-color:rgb(240 249 255/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity,1))}.bg-slate-400{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity,1))}.bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-surface-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-surface-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.bg-surface-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-surface-50\/60{background-color:rgba(248,250,252,.6)}.bg-violet-100{--tw-bg-opacity:1;background-color:rgb(237 233 254/var(--tw-bg-opacity,1))}.bg-violet-50{--tw-bg-opacity:1;background-color:rgb(245 243 255/var(--tw-bg-opacity,1))}.bg-violet-600{--tw-bg-opacity:1;background-color:rgb(124 58 237/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/15{background-color:hsla(0,0%,100%,.15)}.bg-white\/60{background-color:hsla(0,0%,100%,.6)}.bg-white\/70{background-color:hsla(0,0%,100%,.7)}.bg-white\/80{background-color:hsla(0,0%,100%,.8)}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity,1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-brand-50{--tw-gradient-from:#eff6ff var(--tw-gradient-from-position);--tw-gradient-to:rgba(239,246,255,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand-500{--tw-gradient-from:#3b82f6 var(--tw-gradient-from-position);--tw-gradient-to:rgba(59,130,246,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand-600{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-orange-50{--tw-gradient-from:#fff7ed var(--tw-gradient-from-position);--tw-gradient-to:rgba(255,247,237,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-orange-500{--tw-gradient-from:#f97316 var(--tw-gradient-from-position);--tw-gradient-to:rgba(249,115,22,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-violet-50{--tw-gradient-from:#f5f3ff var(--tw-gradient-from-position);--tw-gradient-to:rgba(245,243,255,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-brand-100{--tw-gradient-to:#dbeafe var(--tw-gradient-to-position)}.to-brand-500{--tw-gradient-to:#3b82f6 var(--tw-gradient-to-position)}.to-orange-100{--tw-gradient-to:#ffedd5 var(--tw-gradient-to-position)}.to-red-500{--tw-gradient-to:#ef4444 var(--tw-gradient-to-position)}.to-violet-100{--tw-gradient-to:#ede9fe var(--tw-gradient-to-position)}.to-violet-50{--tw-gradient-to:#f5f3ff var(--tw-gradient-to-position)}.to-violet-500{--tw-gradient-to:#8b5cf6 var(--tw-gradient-to-position)}.to-violet-600{--tw-gradient-to:#7c3aed var(--tw-gradient-to-position)}.fill-amber-400{fill:#fbbf24}.fill-brand-500{fill:#3b82f6}.fill-slate-500{fill:#64748b}.fill-surface-200{fill:#e2e8f0}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.\!px-2\.5{padding-left:.625rem!important;padding-right:.625rem!important}.\!py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-5{padding-bottom:1.25rem}.pl-3{padding-left:.75rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-\[18px\]{padding-top:18px}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:Inter,system-ui,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[9px\]{font-size:9px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-\[1\.9\]{line-height:1.9}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-normal{letter-spacing:0}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-amber-400{--tw-text-opacity:1;color:rgb(251 191 36/var(--tw-text-opacity,1))}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.text-amber-700\/80{color:rgba(180,83,9,.8)}.text-amber-800{--tw-text-opacity:1;color:rgb(146 64 14/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-brand-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-brand-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-brand-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-emerald-400{--tw-text-opacity:1;color:rgb(52 211 153/var(--tw-text-opacity,1))}.text-emerald-500{--tw-text-opacity:1;color:rgb(16 185 129/var(--tw-text-opacity,1))}.text-emerald-600{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity,1))}.text-emerald-700{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.text-emerald-700\/80{color:rgba(4,120,87,.8)}.text-emerald-800{--tw-text-opacity:1;color:rgb(6 95 70/var(--tw-text-opacity,1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity,1))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-indigo-700{--tw-text-opacity:1;color:rgb(67 56 202/var(--tw-text-opacity,1))}.text-orange-400{--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-orange-700{--tw-text-opacity:1;color:rgb(194 65 12/var(--tw-text-opacity,1))}.text-pink-700{--tw-text-opacity:1;color:rgb(190 24 93/var(--tw-text-opacity,1))}.text-purple-700{--tw-text-opacity:1;color:rgb(126 34 206/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-rose-500{--tw-text-opacity:1;color:rgb(244 63 94/var(--tw-text-opacity,1))}.text-rose-600{--tw-text-opacity:1;color:rgb(225 29 72/var(--tw-text-opacity,1))}.text-rose-700{--tw-text-opacity:1;color:rgb(190 18 60/var(--tw-text-opacity,1))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1))}.text-violet-400{--tw-text-opacity:1;color:rgb(167 139 250/var(--tw-text-opacity,1))}.text-violet-500{--tw-text-opacity:1;color:rgb(139 92 246/var(--tw-text-opacity,1))}.text-violet-600{--tw-text-opacity:1;color:rgb(124 58 237/var(--tw-text-opacity,1))}.text-violet-700{--tw-text-opacity:1;color:rgb(109 40 217/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/90{color:hsla(0,0%,100%,.9)}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.text-yellow-700{--tw-text-opacity:1;color:rgb(161 98 7/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.accent-brand-600{accent-color:#2563eb}.\!opacity-100{opacity:1!important}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-2{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-brand-200{--tw-ring-opacity:1;--tw-ring-color:rgb(191 219 254/var(--tw-ring-opacity,1))}.sepia{--tw-sepia:sepia(100%)}.filter,.sepia{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-sm{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-transform{transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}[x-cloak]{display:none!important}.sf-toggle{display:inline-flex;flex-shrink:0}.sf-toggle-track{display:block;width:36px;height:20px;background:#cbd5e1;border-radius:9999px;position:relative;transition:background var(--sf-duration-fast) var(--sf-ease-spring)}.dark .sf-toggle-track{background:#475569}.sf-toggle.active .sf-toggle-track{background:var(--sf-color-brand-600)}.sf-toggle-thumb{display:block;width:16px;height:16px;background:#fff;border-radius:9999px;position:absolute;top:2px;left:2px;transition:transform var(--sf-duration-fast) var(--sf-ease-spring);box-shadow:0 1px 3px rgba(0,0,0,.15)}.sf-toggle.active .sf-toggle-thumb{transform:translateX(16px)}input[type=range].sf-range{-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;width:100%;height:6px;background:#e2e8f0!important;border-radius:9999px;outline:none;border:none;padding:0;margin:8px 0}.dark input[type=range].sf-range{background:#334155!important}input[type=range].sf-range::-webkit-slider-runnable-track{height:6px;background:transparent;border-radius:9999px}input[type=range].sf-range::-webkit-slider-thumb{-webkit-appearance:none!important;appearance:none!important;width:14px;height:14px;background:#2563eb!important;border-radius:50%;cursor:pointer;border:2px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.2);margin-top:-4px;-webkit-transition:transform .15s ease,box-shadow .15s ease;transition:transform .15s ease,box-shadow .15s ease}input[type=range].sf-range::-webkit-slider-thumb:hover{transform:scale(1.15);box-shadow:0 2px 8px rgba(0,0,0,.3)}input[type=range].sf-range::-moz-range-track{height:6px;background:#e2e8f0;border-radius:9999px;border:none}.dark input[type=range].sf-range::-moz-range-track{background:#334155}input[type=range].sf-range::-moz-range-thumb{width:14px;height:14px;background:#2563eb;border:2px solid #fff;border-radius:50%;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.2)}details[open] .details-chevron{transform:rotate(180deg)}@media (prefers-reduced-motion:reduce){*,:after,:before{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.last\:mb-0:last-child{margin-bottom:0}.last\:border-b-0:last-child{border-bottom-width:0}.hover\:border-blue-300:hover{--tw-border-opacity:1;border-color:rgb(147 197 253/var(--tw-border-opacity,1))}.hover\:border-brand-500:hover{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.hover\:border-green-300:hover{--tw-border-opacity:1;border-color:rgb(134 239 172/var(--tw-border-opacity,1))}.hover\:border-orange-300:hover{--tw-border-opacity:1;border-color:rgb(253 186 116/var(--tw-border-opacity,1))}.hover\:border-purple-300:hover{--tw-border-opacity:1;border-color:rgb(216 180 254/var(--tw-border-opacity,1))}.hover\:border-violet-400:hover{--tw-border-opacity:1;border-color:rgb(167 139 250/var(--tw-border-opacity,1))}.hover\:bg-amber-100:hover{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))}.hover\:bg-amber-200:hover{--tw-bg-opacity:1;background-color:rgb(253 230 138/var(--tw-bg-opacity,1))}.hover\:bg-amber-300:hover{--tw-bg-opacity:1;background-color:rgb(252 211 77/var(--tw-bg-opacity,1))}.hover\:bg-amber-700:hover{--tw-bg-opacity:1;background-color:rgb(180 83 9/var(--tw-bg-opacity,1))}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-brand-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.hover\:bg-brand-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-emerald-100:hover{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.hover\:bg-emerald-200:hover{--tw-bg-opacity:1;background-color:rgb(167 243 208/var(--tw-bg-opacity,1))}.hover\:bg-emerald-50:hover{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.hover\:bg-emerald-700:hover{--tw-bg-opacity:1;background-color:rgb(4 120 87/var(--tw-bg-opacity,1))}.hover\:bg-red-200:hover{--tw-bg-opacity:1;background-color:rgb(254 202 202/var(--tw-bg-opacity,1))}.hover\:bg-red-50:hover{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.hover\:bg-rose-100:hover{--tw-bg-opacity:1;background-color:rgb(255 228 230/var(--tw-bg-opacity,1))}.hover\:bg-rose-200:hover{--tw-bg-opacity:1;background-color:rgb(254 205 211/var(--tw-bg-opacity,1))}.hover\:bg-surface-100:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.hover\:bg-surface-200:hover{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.hover\:bg-surface-50:hover{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.hover\:bg-violet-100:hover{--tw-bg-opacity:1;background-color:rgb(237 233 254/var(--tw-bg-opacity,1))}.hover\:bg-violet-200:hover{--tw-bg-opacity:1;background-color:rgb(221 214 254/var(--tw-bg-opacity,1))}.hover\:bg-violet-50:hover{--tw-bg-opacity:1;background-color:rgb(245 243 255/var(--tw-bg-opacity,1))}.hover\:bg-violet-700:hover{--tw-bg-opacity:1;background-color:rgb(109 40 217/var(--tw-bg-opacity,1))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.hover\:text-amber-700:hover{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.hover\:text-amber-800:hover{--tw-text-opacity:1;color:rgb(146 64 14/var(--tw-text-opacity,1))}.hover\:text-brand-600:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.hover\:text-brand-700:hover{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.hover\:text-emerald-600:hover{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity,1))}.hover\:text-emerald-700:hover{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.hover\:text-emerald-800:hover{--tw-text-opacity:1;color:rgb(6 95 70/var(--tw-text-opacity,1))}.hover\:text-red-500:hover{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.hover\:text-red-600:hover{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.hover\:text-red-800:hover{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.hover\:text-rose-700:hover{--tw-text-opacity:1;color:rgb(190 18 60/var(--tw-text-opacity,1))}.hover\:text-slate-600:hover{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.hover\:text-slate-700:hover{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.hover\:text-slate-800:hover{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1))}.hover\:text-violet-600:hover{--tw-text-opacity:1;color:rgb(124 58 237/var(--tw-text-opacity,1))}.hover\:text-violet-700:hover{--tw-text-opacity:1;color:rgb(109 40 217/var(--tw-text-opacity,1))}.hover\:shadow-sm:hover{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:not-sr-only:focus{position:static;width:auto;height:auto;padding:0;margin:0;overflow:visible;clip:auto;white-space:normal}.focus\:fixed:focus{position:fixed}.focus\:left-2:focus{left:.5rem}.focus\:top-2:focus{top:.5rem}.focus\:z-50:focus{z-index:50}.focus\:rounded-lg:focus{border-radius:12px}.focus\:border-brand-500:focus{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.focus\:bg-brand-600:focus{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.focus\:px-4:focus{padding-left:1rem;padding-right:1rem}.focus\:py-2:focus{padding-top:.5rem;padding-bottom:.5rem}.focus\:text-sm:focus{font-size:.875rem;line-height:1.25rem}.focus\:font-semibold:focus{font-weight:600}.focus\:text-white:focus{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-brand-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(191 219 254/var(--tw-ring-opacity,1))}.focus\:ring-brand-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.focus\:ring-brand-500\/20:focus{--tw-ring-color:rgba(59,130,246,.2)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.group[open] .group-open\:rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:opacity-100{opacity:1}.dark\:border-amber-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(146 64 14/var(--tw-border-opacity,1))}.dark\:border-blue-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(30 64 175/var(--tw-border-opacity,1))}.dark\:border-brand-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(30 64 175/var(--tw-border-opacity,1))}.dark\:border-emerald-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(6 95 70/var(--tw-border-opacity,1))}.dark\:border-indigo-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(55 48 163/var(--tw-border-opacity,1))}.dark\:border-orange-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(154 52 18/var(--tw-border-opacity,1))}.dark\:border-pink-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(157 23 77/var(--tw-border-opacity,1))}.dark\:border-purple-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(107 33 168/var(--tw-border-opacity,1))}.dark\:border-red-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(153 27 27/var(--tw-border-opacity,1))}.dark\:border-slate-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(51 65 85/var(--tw-border-opacity,1))}.dark\:border-slate-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(30 41 59/var(--tw-border-opacity,1))}.dark\:border-violet-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(91 33 182/var(--tw-border-opacity,1))}.dark\:border-yellow-800:is(.dark *){--tw-border-opacity:1;border-color:rgb(133 77 14/var(--tw-border-opacity,1))}.dark\:bg-amber-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(146 64 14/var(--tw-bg-opacity,1))}.dark\:bg-amber-900\/20:is(.dark *){background-color:rgba(120,53,15,.2)}.dark\:bg-amber-900\/30:is(.dark *){background-color:rgba(120,53,15,.3)}.dark\:bg-blue-900\/20:is(.dark *){background-color:rgba(30,58,138,.2)}.dark\:bg-emerald-900\/20:is(.dark *){background-color:rgba(6,78,59,.2)}.dark\:bg-emerald-900\/30:is(.dark *){background-color:rgba(6,78,59,.3)}.dark\:bg-green-900\/30:is(.dark *){background-color:rgba(20,83,45,.3)}.dark\:bg-indigo-900\/20:is(.dark *){background-color:rgba(49,46,129,.2)}.dark\:bg-orange-900\/20:is(.dark *){background-color:rgba(124,45,18,.2)}.dark\:bg-pink-900\/20:is(.dark *){background-color:rgba(131,24,67,.2)}.dark\:bg-purple-900\/20:is(.dark *){background-color:rgba(88,28,135,.2)}.dark\:bg-red-900\/20:is(.dark *){background-color:rgba(127,29,29,.2)}.dark\:bg-red-900\/30:is(.dark *){background-color:rgba(127,29,29,.3)}.dark\:bg-red-900\/40:is(.dark *){background-color:rgba(127,29,29,.4)}.dark\:bg-rose-900\/20:is(.dark *){background-color:rgba(136,19,55,.2)}.dark\:bg-rose-900\/30:is(.dark *){background-color:rgba(136,19,55,.3)}.dark\:bg-slate-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.dark\:bg-slate-800\/40:is(.dark *){background-color:rgba(30,41,59,.4)}.dark\:bg-slate-900\/20:is(.dark *){background-color:rgba(15,23,42,.2)}.dark\:bg-surface-100:is(.dark *){--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.dark\:bg-violet-900\/20:is(.dark *){background-color:rgba(76,29,149,.2)}.dark\:bg-violet-900\/30:is(.dark *){background-color:rgba(76,29,149,.3)}.dark\:bg-yellow-900\/20:is(.dark *){background-color:rgba(113,63,18,.2)}.dark\:from-orange-900\/30:is(.dark *){--tw-gradient-from:rgba(124,45,18,.3) var(--tw-gradient-from-position);--tw-gradient-to:rgba(124,45,18,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.dark\:from-violet-900\/30:is(.dark *){--tw-gradient-from:rgba(76,29,149,.3) var(--tw-gradient-from-position);--tw-gradient-to:rgba(76,29,149,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.dark\:to-brand-800\/30:is(.dark *){--tw-gradient-to:rgba(30,64,175,.3) var(--tw-gradient-to-position)}.dark\:to-orange-800\/30:is(.dark *){--tw-gradient-to:rgba(154,52,18,.3) var(--tw-gradient-to-position)}.dark\:to-violet-800\/30:is(.dark *){--tw-gradient-to:rgba(91,33,182,.3) var(--tw-gradient-to-position)}.dark\:to-violet-900\/20:is(.dark *){--tw-gradient-to:rgba(76,29,149,.2) var(--tw-gradient-to-position)}.dark\:fill-slate-400:is(.dark *){fill:#94a3b8}.dark\:text-amber-200:is(.dark *){--tw-text-opacity:1;color:rgb(253 230 138/var(--tw-text-opacity,1))}.dark\:text-amber-300:is(.dark *){--tw-text-opacity:1;color:rgb(252 211 77/var(--tw-text-opacity,1))}.dark\:text-amber-300\/80:is(.dark *){color:rgba(252,211,77,.8)}.dark\:text-amber-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 191 36/var(--tw-text-opacity,1))}.dark\:text-amber-500:is(.dark *){--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.dark\:text-blue-400:is(.dark *){--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity,1))}.dark\:text-emerald-200:is(.dark *){--tw-text-opacity:1;color:rgb(167 243 208/var(--tw-text-opacity,1))}.dark\:text-emerald-300\/80:is(.dark *){color:rgba(110,231,183,.8)}.dark\:text-emerald-400:is(.dark *){--tw-text-opacity:1;color:rgb(52 211 153/var(--tw-text-opacity,1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.dark\:text-indigo-400:is(.dark *){--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.dark\:text-orange-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity,1))}.dark\:text-pink-400:is(.dark *){--tw-text-opacity:1;color:rgb(244 114 182/var(--tw-text-opacity,1))}.dark\:text-purple-400:is(.dark *){--tw-text-opacity:1;color:rgb(192 132 252/var(--tw-text-opacity,1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.dark\:text-rose-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 113 133/var(--tw-text-opacity,1))}.dark\:text-slate-100:is(.dark *){--tw-text-opacity:1;color:rgb(241 245 249/var(--tw-text-opacity,1))}.dark\:text-slate-200:is(.dark *){--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.dark\:text-slate-300:is(.dark *){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.dark\:text-slate-400:is(.dark *){--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.dark\:text-slate-500:is(.dark *){--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.dark\:text-slate-600:is(.dark *){--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.dark\:text-violet-400:is(.dark *){--tw-text-opacity:1;color:rgb(167 139 250/var(--tw-text-opacity,1))}.dark\:text-yellow-400:is(.dark *){--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.dark\:ring-brand-700:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgb(29 78 216/var(--tw-ring-opacity,1))}.dark\:hover\:border-brand-600:hover:is(.dark *){--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.dark\:hover\:border-violet-600:hover:is(.dark *){--tw-border-opacity:1;border-color:rgb(124 58 237/var(--tw-border-opacity,1))}.dark\:hover\:bg-amber-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(180 83 9/var(--tw-bg-opacity,1))}.dark\:hover\:bg-amber-800\/40:hover:is(.dark *){background-color:rgba(146,64,14,.4)}.dark\:hover\:bg-amber-900\/40:hover:is(.dark *){background-color:rgba(120,53,15,.4)}.dark\:hover\:bg-emerald-800\/40:hover:is(.dark *){background-color:rgba(6,95,70,.4)}.dark\:hover\:bg-emerald-900\/20:hover:is(.dark *){background-color:rgba(6,78,59,.2)}.dark\:hover\:bg-emerald-900\/40:hover:is(.dark *){background-color:rgba(6,78,59,.4)}.dark\:hover\:bg-red-800:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(153 27 27/var(--tw-bg-opacity,1))}.dark\:hover\:bg-red-900\/20:hover:is(.dark *){background-color:rgba(127,29,29,.2)}.dark\:hover\:bg-rose-800\/40:hover:is(.dark *){background-color:rgba(159,18,57,.4)}.dark\:hover\:bg-slate-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity,1))}.dark\:hover\:bg-surface-100:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.dark\:hover\:bg-violet-800\/40:hover:is(.dark *){background-color:rgba(91,33,182,.4)}.dark\:hover\:bg-violet-900\/20:hover:is(.dark *){background-color:rgba(76,29,149,.2)}@media (min-width:640px){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:768px){.md\:mx-6{margin-left:1.5rem;margin-right:1.5rem}.md\:ml-60{margin-left:15rem}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:p-10{padding:2.5rem}.md\:p-6{padding:1.5rem}.md\:p-8{padding:2rem}.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width:1024px){.lg\:p-8{padding:2rem}} \ No newline at end of file From 3d9f18df04ec1112dc5174055b1af5450ede2f77 Mon Sep 17 00:00:00 2001 From: HieuNTg Date: Wed, 13 May 2026 16:30:12 +0700 Subject: [PATCH 2/6] feat(static): gzip-aware StaticFiles with precompressed sibling lookup (S3-runtime) FastAPI's GZipMiddleware doesn't wrap StaticFiles mounts, leaving CSS/JS to ship uncompressed (~98KB raw for main.built.css vs ~16KB gzipped). This blocked sprint #1's external-critical-CSS attempt and gates the sprint #2 perf target of Lighthouse >=85. GzippedStaticFiles subclasses starlette.staticfiles.StaticFiles and: - serves a sibling .gz verbatim when present and the client accepts gzip - otherwise compresses at runtime (level 6) for payloads >=1KB, memoised in a 128-entry LRU keyed by (path, mtime_ns, size) so a touched file invalidates naturally - falls through to vanilla StaticFiles for HEAD/405, no-accept-encoding, small files, and already-compressed content types (images, fonts) Wired into app.py at both /static and /static/locales mount points. Companion precompress script lands in the next commit. Verified: - pytest tests/test_gzipped_static_files.py -v -> 4 passed - live smoke on port 7862: Content-Encoding: gzip content-length: 16675 (down from 98515, -83% wire) --- app.py | 5 +- services/gzipped_static_files.py | 203 +++++++++++++++++++++++++++++ tests/test_gzipped_static_files.py | 115 ++++++++++++++++ 3 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 services/gzipped_static_files.py create mode 100644 tests/test_gzipped_static_files.py diff --git a/app.py b/app.py index bf9df46b..69a97320 100644 --- a/app.py +++ b/app.py @@ -30,6 +30,7 @@ from fastapi.staticfiles import StaticFiles from config import ConfigManager +from services.gzipped_static_files import GzippedStaticFiles # Logging from services.structured_logger import configure_logging @@ -293,9 +294,9 @@ async def dispatch(self, request: Request, call_next): # Mount locales FIRST (more specific path takes precedence) if os.path.isdir(locales_dir): - main_app.mount("/static/locales", StaticFiles(directory=locales_dir), name="locales") + main_app.mount("/static/locales", GzippedStaticFiles(directory=locales_dir), name="locales") # Then mount web/ for remaining static files - main_app.mount("/static", StaticFiles(directory=web_dir), name="static") + main_app.mount("/static", GzippedStaticFiles(directory=web_dir), name="static") # Generated chapter images images_dir = os.path.join(base_dir, "output", "images") diff --git a/services/gzipped_static_files.py b/services/gzipped_static_files.py new file mode 100644 index 00000000..71bef357 --- /dev/null +++ b/services/gzipped_static_files.py @@ -0,0 +1,203 @@ +"""Gzip-aware StaticFiles for FastAPI/Starlette. + +FastAPI's GZipMiddleware does NOT wrap StaticFiles mounts (the middleware sits +above the routing layer but StaticFiles writes the body directly to the ASGI +`send` callable, bypassing the buffering middleware would need). + +This class restores gzip on static responses two ways: + +1. If a sibling `.gz` file exists on disk (e.g. produced by + ``scripts/precompress-static.mjs``), serve it verbatim with the right + headers. Highest compression level, zero CPU per request. +2. Otherwise, if the client accepts gzip and the payload is over the size + threshold, compress in-process and cache the result by ``(path, mtime)`` + in a bounded LRU. Dev mode without a build step still works. + +Small files (< ~1 KB) are served uncompressed: gzip framing overhead can +exceed the savings and the CPU cost is wasted. +""" + +from __future__ import annotations + +import gzip +import mimetypes +import os +import stat +from functools import lru_cache +from typing import Tuple + +import anyio +from starlette.datastructures import Headers +from starlette.exceptions import HTTPException +from starlette.responses import Response +from starlette.staticfiles import StaticFiles +from starlette.types import Scope + +# Minimum uncompressed size (bytes) before we bother gzipping at runtime. +# Below this, framing overhead can negate the win and we pay CPU for nothing. +_MIN_GZIP_SIZE = 1024 + +# Content types that are already compressed (images, fonts, archives). +# Re-gzipping them wastes CPU and rarely shrinks the payload. +_SKIP_TYPES = frozenset( + { + "image/png", + "image/jpeg", + "image/jpg", + "image/gif", + "image/webp", + "image/avif", + "font/woff", + "font/woff2", + "application/zip", + "application/gzip", + "application/x-gzip", + "application/octet-stream", + } +) + + +def _client_accepts_gzip(scope: Scope) -> bool: + headers = Headers(scope=scope) + accept_encoding = headers.get("accept-encoding", "") + # Permissive parse: any token containing "gzip" counts. Don't bother with + # q-values — no real client sends `gzip;q=0` for a static asset. + return "gzip" in accept_encoding.lower() + + +def _guess_content_type(path: str) -> str: + ctype, _ = mimetypes.guess_type(path) + return ctype or "application/octet-stream" + + +@lru_cache(maxsize=128) +def _compress_cached(full_path: str, mtime_ns: int, size: int) -> bytes: + """Read + gzip a file, memoised by (path, mtime, size). + + ``mtime_ns`` and ``size`` are part of the cache key so a touched/rewritten + file invalidates the entry naturally — no manual cache busting needed. + The ``size`` argument is unused inside the function but participates in + the key. + """ + del size # only used as part of the cache key + with open(full_path, "rb") as fh: + raw = fh.read() + # level=6 is the default zlib level — good ratio without burning CPU. + return gzip.compress(raw, compresslevel=6, mtime=0) + + +class GzippedStaticFiles(StaticFiles): + """StaticFiles subclass that serves gzip when the client supports it. + + Drop-in replacement: same constructor signature as ``StaticFiles``. + """ + + async def get_response(self, path: str, scope: Scope) -> Response: + if scope["method"] not in ("GET", "HEAD"): + raise HTTPException(status_code=405) + + if not _client_accepts_gzip(scope): + return await super().get_response(path, scope) + + # Try precompressed sibling first (e.g. main.built.css.gz). + gz_path = path + ".gz" + try: + gz_full_path, gz_stat = await anyio.to_thread.run_sync( + self.lookup_path, gz_path + ) + except (PermissionError, OSError): + gz_full_path, gz_stat = "", None + + if gz_stat is not None and stat.S_ISREG(gz_stat.st_mode): + # Locate the un-compressed sibling so we know the original + # content-type and can serve a sane response if the underlying + # file is missing. This also gives the upstream caching + # response logic something to hash against. + try: + orig_full_path, orig_stat = await anyio.to_thread.run_sync( + self.lookup_path, path + ) + except (PermissionError, OSError): + orig_full_path, orig_stat = "", None + + content_type = _guess_content_type(path) + return await self._precompressed_response( + gz_full_path, + gz_stat, + content_type, + scope, + ) + + # No precompressed sibling — fall back to runtime gzip when worth it. + try: + full_path, file_stat = await anyio.to_thread.run_sync( + self.lookup_path, path + ) + except PermissionError: + raise HTTPException(status_code=401) + except OSError as exc: + # Re-use the parent's 404/path-too-long handling. + return await super().get_response(path, scope) + + if ( + file_stat is not None + and stat.S_ISREG(file_stat.st_mode) + and file_stat.st_size >= _MIN_GZIP_SIZE + ): + content_type = _guess_content_type(path) + if content_type not in _SKIP_TYPES: + return await self._runtime_gzip_response( + full_path, file_stat, content_type, scope + ) + + # Fall through: directory, missing, too-small, or skip-type. + return await super().get_response(path, scope) + + async def _precompressed_response( + self, + gz_full_path: str, + gz_stat: os.stat_result, + content_type: str, + scope: Scope, + ) -> Response: + def _read() -> bytes: + with open(gz_full_path, "rb") as fh: + return fh.read() + + body = await anyio.to_thread.run_sync(_read) + headers = { + "content-encoding": "gzip", + "content-type": content_type, + "vary": "Accept-Encoding", + "content-length": str(len(body)), + } + return Response( + content=body if scope["method"] == "GET" else b"", + status_code=200, + headers=headers, + ) + + async def _runtime_gzip_response( + self, + full_path: str, + file_stat: os.stat_result, + content_type: str, + scope: Scope, + ) -> Response: + body = await anyio.to_thread.run_sync( + _compress_cached, full_path, file_stat.st_mtime_ns, file_stat.st_size + ) + headers = { + "content-encoding": "gzip", + "content-type": content_type, + "vary": "Accept-Encoding", + "content-length": str(len(body)), + } + return Response( + content=body if scope["method"] == "GET" else b"", + status_code=200, + headers=headers, + ) + + +__all__ = ["GzippedStaticFiles"] diff --git a/tests/test_gzipped_static_files.py b/tests/test_gzipped_static_files.py new file mode 100644 index 00000000..d3a44609 --- /dev/null +++ b/tests/test_gzipped_static_files.py @@ -0,0 +1,115 @@ +"""Tests for services.gzipped_static_files.GzippedStaticFiles. + +Verifies the four contractual behaviours documented in S3: + +1. Precompressed `.gz` sibling is served verbatim with `Content-Encoding: gzip`. +2. Files >1KB without a sibling get compressed at runtime; the body decodes + back to the original payload. +3. Missing `Accept-Encoding` header → uncompressed response. +4. Files <1KB are served uncompressed regardless of `Accept-Encoding`. +""" + +from __future__ import annotations + +import gzip +import os +from pathlib import Path + +import httpx +import pytest +import pytest_asyncio +from fastapi import FastAPI + +from services.gzipped_static_files import GzippedStaticFiles + + +# ---------- fixtures ---------------------------------------------------------- + + +@pytest_asyncio.fixture +async def static_app(tmp_path: Path): + """Build a tiny FastAPI app mounting GzippedStaticFiles at /static. + + The fixture yields ``(client, tmp_path)`` so each test can drop assets into + the tmp dir and immediately request them. + """ + app = FastAPI() + app.mount("/static", GzippedStaticFiles(directory=str(tmp_path)), name="static") + + transport = httpx.ASGITransport(app=app) + async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: + yield client, tmp_path + + +# ---------- tests ------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_serves_precompressed_gz_when_available(static_app): + client, tmp_path = static_app + # Large enough that runtime gzip *would* fire — so we can prove the sibling + # is preferred (different bytes vs runtime-compressed level=6). + raw = (b"body { color: hotpink; } /* padding */" * 50) + (tmp_path / "foo.css").write_bytes(raw) + # Use a deliberately distinct compression level (9) so the .gz bytes + # differ from what runtime gzip would produce at level 6. + gz_bytes = gzip.compress(raw, compresslevel=9, mtime=0) + (tmp_path / "foo.css.gz").write_bytes(gz_bytes) + + resp = await client.get("/static/foo.css", headers={"Accept-Encoding": "gzip"}) + + assert resp.status_code == 200 + assert resp.headers.get("content-encoding") == "gzip" + assert resp.headers.get("content-type", "").startswith("text/css") + assert resp.headers.get("vary") == "Accept-Encoding" + # httpx auto-decompresses when transport sees content-encoding; compare the + # decoded bytes to the raw source to confirm payload integrity. + assert resp.content == raw + # Confirm we actually shipped the level-9 sibling, not a runtime recompress: + # decompress the on-disk file and the response body should match the raw. + assert gzip.decompress(gz_bytes) == raw + + +@pytest.mark.asyncio +async def test_falls_back_to_runtime_gzip_when_no_sibling(static_app): + client, tmp_path = static_app + raw = b"console.log('hello world');\n" * 100 # ~2.7KB, well above 1KB + (tmp_path / "app.js").write_bytes(raw) + + resp = await client.get("/static/app.js", headers={"Accept-Encoding": "gzip"}) + + assert resp.status_code == 200 + assert resp.headers.get("content-encoding") == "gzip" + assert resp.headers.get("vary") == "Accept-Encoding" + # httpx already decoded the body for us — verify it round-trips. + assert resp.content == raw + + +@pytest.mark.asyncio +async def test_no_gzip_when_accept_encoding_omitted(static_app): + client, tmp_path = static_app + raw = b"a" * 4096 + (tmp_path / "plain.css").write_bytes(raw) + # A sibling .gz exists too — must still NOT be served when the client + # doesn't advertise gzip support. + (tmp_path / "plain.css.gz").write_bytes(gzip.compress(raw)) + + # httpx adds its own Accept-Encoding by default; override explicitly. + resp = await client.get("/static/plain.css", headers={"Accept-Encoding": "identity"}) + + assert resp.status_code == 200 + assert resp.headers.get("content-encoding") in (None, "") + assert resp.content == raw + + +@pytest.mark.asyncio +async def test_no_gzip_for_small_files(static_app): + client, tmp_path = static_app + raw = b"tiny" # 4 bytes — well below threshold + (tmp_path / "tiny.css").write_bytes(raw) + + resp = await client.get("/static/tiny.css", headers={"Accept-Encoding": "gzip"}) + + assert resp.status_code == 200 + assert resp.headers.get("content-encoding") in (None, "") + assert resp.content == raw From 6138a22daa74c89bbd122dacfded4db09e69a013 Mon Sep 17 00:00:00 2001 From: HieuNTg Date: Wed, 13 May 2026 16:30:24 +0700 Subject: [PATCH 3/6] chore(build): precompress static assets at build time (S3-precompress) Walks web/css, web/dist/js, web/static, web/js and writes sibling .gz (zlib level 9) for every compressible file >1KB whose .gz is missing or older than the source. Pairs with GzippedStaticFiles which prefers the sibling over runtime compression. Level 9 squeezes ~3-5% more out of CSS/JS than the runtime level-6 path, paid once at build time. Idempotent (mtime-gated). Wired into npm run build after the JS bundle step; .gitignore excludes the .gz artifacts so they're never checked in. Runtime path keeps dev mode working without a build. Verified: - node scripts/precompress-static.mjs -> 47 files compressed, 413.2 KB saved - second run -> 0 compressed, 47 up-to-date (idempotent) - live smoke with sibling present: wire size 16526 (precompressed lvl-9) vs 16675 (runtime lvl-6) -- confirms sibling preference --- .gitignore | 6 ++ package.json | 3 +- scripts/precompress-static.mjs | 116 +++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 scripts/precompress-static.mjs diff --git a/.gitignore b/.gitignore index d49920ab..63769679 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,12 @@ web/dist/* web/dist/js/* !web/dist/js/runtime-bundle.min.js +# ── Pre-compressed static assets (S3) ────────────────────────────── +# Generated by `node scripts/precompress-static.mjs` during build. +# Runtime gzip in services/gzipped_static_files.py handles the missing case, +# so dev mode without a build step still works. +web/**/*.gz + # ── IDE & OS ─────────────────────────────────────────────────────── .DS_Store Thumbs.db diff --git a/package.json b/package.json index bd74fa52..7dc35720 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc -p tsconfig.build.json && node scripts/build-runtime-bundle.mjs", + "build": "tsc -p tsconfig.build.json && node scripts/build-runtime-bundle.mjs && node scripts/precompress-static.mjs", + "build:precompress": "node scripts/precompress-static.mjs", "build:bundle": "node scripts/build-runtime-bundle.mjs", "build:css": "tailwindcss -i web/css/main.css -o web/css/main.built.css --minify", "build:vite": "vite build", diff --git a/scripts/precompress-static.mjs b/scripts/precompress-static.mjs new file mode 100644 index 00000000..954a3df6 --- /dev/null +++ b/scripts/precompress-static.mjs @@ -0,0 +1,116 @@ +#!/usr/bin/env node +/** + * Pre-compress static assets with gzip (level 9) for the FastAPI server's + * GzippedStaticFiles handler to serve verbatim. + * + * Why: at runtime we compress on-demand at level 6 with an LRU cache, which + * is fine — but level 9 squeezes another ~3-5% out of CSS/JS for the cost of + * a few hundred ms of build-time CPU, paid once. Production wins. + * + * Walks a hard-coded list of asset dirs, writes `.gz` next to every + * candidate > 1KB when the .gz is missing or older than the source. + * + * Run via `npm run build` (wired in package.json after the JS bundle step). + */ + +import { promises as fs } from 'node:fs'; +import { gzipSync, constants as zlibConstants } from 'node:zlib'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(__dirname, '..'); + +const TARGET_DIRS = [ + 'web/css', + 'web/dist/js', + 'web/static', + 'web/js', // built TS output, if present +]; + +const COMPRESSIBLE_EXTS = new Set(['.css', '.js', '.mjs', '.svg', '.json', '.map', '.html']); +const MIN_SIZE = 1024; + +/** Recursively yield files under `dir`. Missing dirs are silently skipped. */ +async function* walk(dir) { + let entries; + try { + entries = await fs.readdir(dir, { withFileTypes: true }); + } catch (err) { + if (err.code === 'ENOENT') return; + throw err; + } + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + yield* walk(full); + } else if (entry.isFile()) { + yield full; + } + } +} + +async function precompress(filePath) { + const ext = path.extname(filePath).toLowerCase(); + if (!COMPRESSIBLE_EXTS.has(ext)) return null; + if (filePath.endsWith('.gz')) return null; + + const srcStat = await fs.stat(filePath); + if (srcStat.size < MIN_SIZE) return null; + + const gzPath = filePath + '.gz'; + try { + const gzStat = await fs.stat(gzPath); + if (gzStat.mtimeMs >= srcStat.mtimeMs) { + return { filePath, skipped: true, savedBytes: 0 }; + } + } catch (err) { + if (err.code !== 'ENOENT') throw err; + } + + const raw = await fs.readFile(filePath); + const compressed = gzipSync(raw, { level: zlibConstants.Z_BEST_COMPRESSION }); + await fs.writeFile(gzPath, compressed); + return { + filePath, + skipped: false, + savedBytes: raw.length - compressed.length, + rawSize: raw.length, + gzSize: compressed.length, + }; +} + +async function main() { + let compressed = 0; + let skipped = 0; + let savedBytes = 0; + + for (const rel of TARGET_DIRS) { + const abs = path.join(ROOT, rel); + for await (const file of walk(abs)) { + const result = await precompress(file); + if (!result) continue; + if (result.skipped) { + skipped += 1; + } else { + compressed += 1; + savedBytes += result.savedBytes; + const relPath = path.relative(ROOT, result.filePath); + const pct = ((result.savedBytes / result.rawSize) * 100).toFixed(1); + console.log( + ` gz ${relPath} ${result.rawSize}b → ${result.gzSize}b (-${pct}%)`, + ); + } + } + } + + const savedKb = (savedBytes / 1024).toFixed(1); + console.log( + `precompress-static: ${compressed} files compressed, ${skipped} up-to-date, ${savedKb} KB saved`, + ); +} + +main().catch((err) => { + console.error('precompress-static failed:', err); + process.exit(1); +}); From 59929224ba0fc11abb6b367dcbfd6a6f9e031723 Mon Sep 17 00:00:00 2001 From: HieuNTg Date: Wed, 13 May 2026 16:31:27 +0700 Subject: [PATCH 4/6] perf(font): self-host Inter WOFF2 with Vietnamese subset (S2) Replace fonts.googleapis.com/gstatic.com CDN with self-hosted Inter variable WOFF2 under web/fonts/inter/. Subset to Latin Basic + Latin-1 Supplement + Latin Extended-A + Vietnamese diacritics block (U+1EA0-1EF9 and the eight standalone VN codepoints) via pyftsubset. Size: roman 63KB, italic 69KB (was unsubsetted 352KB + 388KB). Italic gated by font-style+unicode-range so it only downloads when italic glyphs render. Both files use font-display: swap. Removes: - preconnect to fonts.googleapis.com / fonts.gstatic.com - Adds: - for roman variant (paints latin text immediately) - @font-face declarations inlined in the critical