From fb1ecccd340e9034a41164f151c10a1b2fcc72ad Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Feb 2026 12:53:27 +0000 Subject: [PATCH 1/7] Add AI Readiness Accelerator offer package - Client-facing one-pager with positioning, pricing, and CTA - SOW template with full scope, deliverables, and terms - Internal delivery SOP with phase-by-phase procedures - Pre-call questionnaire template - AI Readiness Scorecard template (6 pillars) - Use-case ROI calculator template - AI Acceptable Use Policy template for governance kit https://claude.ai/code/session_019DXrMJ4k9ujmA3BDgUNzHn --- .../AI-Readiness-Accelerator-OnePager.md | 92 +++ BizDeedz/Offers/Internal-Delivery-SOP.md | 681 ++++++++++++++++++ BizDeedz/Offers/SOW-Template.md | 291 ++++++++ .../templates/AI-Acceptable-Use-Policy.md | 334 +++++++++ .../AI-Readiness-Scorecard-Template.md | 388 ++++++++++ .../templates/Pre-Call-Questionnaire.md | 120 +++ .../templates/Use-Case-ROI-Calculator.md | 243 +++++++ 7 files changed, 2149 insertions(+) create mode 100644 BizDeedz/Offers/AI-Readiness-Accelerator-OnePager.md create mode 100644 BizDeedz/Offers/Internal-Delivery-SOP.md create mode 100644 BizDeedz/Offers/SOW-Template.md create mode 100644 BizDeedz/Offers/templates/AI-Acceptable-Use-Policy.md create mode 100644 BizDeedz/Offers/templates/AI-Readiness-Scorecard-Template.md create mode 100644 BizDeedz/Offers/templates/Pre-Call-Questionnaire.md create mode 100644 BizDeedz/Offers/templates/Use-Case-ROI-Calculator.md diff --git a/BizDeedz/Offers/AI-Readiness-Accelerator-OnePager.md b/BizDeedz/Offers/AI-Readiness-Accelerator-OnePager.md new file mode 100644 index 0000000..6eaf0b2 --- /dev/null +++ b/BizDeedz/Offers/AI-Readiness-Accelerator-OnePager.md @@ -0,0 +1,92 @@ +# AI Readiness Accelerator + +**Get your firm AI-ready in 14 days. No risk. No guesswork.** + +--- + +## The Problem + +Law firms are being sold AI tools they can't actually use. + +Your intake data is inconsistent. Your templates live in 6 different places. Your staff workflows exist only in people's heads. And nobody has thought through what happens when AI gives bad advice to a client. + +Deploying AI on a broken foundation creates malpractice exposure, not efficiency. + +--- + +## What You Get + +In 10-14 days, you receive a complete decision package: + +| Deliverable | What It Is | +|-------------|------------| +| **AI Readiness Scorecard** | Objective baseline across 6 dimensions: process maturity, data quality, knowledge systems, tooling, governance, and change capacity | +| **Prioritized Roadmap** | 30/60/90-day action plan sequenced by impact and effort | +| **Use-Case Portfolio** | 3-5 AI opportunities ranked by feasibility, ROI, and risk | +| **Governance Starter Kit** | Acceptable use policy, access controls, escalation rules, and audit requirements | + +--- + +## How It Works + +| Phase | Days | What Happens | +|-------|------|--------------| +| **Intake** | 0-2 | Secure data room setup, artifact collection, checklist completion | +| **Assessment** | 3-6 | Process walkthroughs, data profiling, systems inventory, staff interviews | +| **Analysis** | 7-9 | Use-case scoring, ROI modeling, risk mapping | +| **Delivery** | 10-12 | Scorecard presentation, roadmap walkthrough, governance review | +| **Decision** | 13-14 | Executive readout, next-step alignment | + +--- + +## Best Fit + +**Ideal client:** +- Bankruptcy, family law, estate planning, or high-volume civil practice +- 5-50 attorneys with paralegal/support staff +- Using practice management software (Clio, MyCase, PracticePanther, etc.) +- Current pain: intake bottlenecks, drafting delays, missed deadlines, or data chaos + +**Not a fit:** +- Solo practitioners without support staff +- Firms with no existing practice management system +- Firms under active litigation holds affecting data access + +--- + +## Pricing + +| Package | Investment | Includes | +|---------|------------|----------| +| **AI Readiness Scorecard** | $4,500 | Full assessment + deliverables (Phases A-E) | +| **Implementation Sprint** | $7,500/sprint | 2-week buildout sprints with defined scope | +| **Optimization Retainer** | $2,500/month | Ongoing monitoring, KPI tracking, governance upkeep | + +*Fixed-fee. No hourly surprises. Payment: 50% to start, 50% on delivery.* + +--- + +## Why BizDeedz + +We're not selling you AI tools. We're building the operational foundation that makes AI actually work. + +- **Operational-first**: We fix the plumbing before turning on the water +- **Governance-built-in**: Compliance and ethics baked in from day one +- **Measurable outcomes**: Cycle time, rework rates, and conversion tracked +- **Law-firm specific**: Built for bankruptcy, family, estate, and civil workflows + +--- + +## Next Step + +**Book a 30-minute diagnostic call.** + +We'll review your current tools, pain points, and goals. If there's a fit, you'll receive a scoped proposal within 48 hours. + +No obligation. No sales pressure. Just clarity. + +**[Schedule Call]** | hello@bizdeedz.com | (xxx) xxx-xxxx + +--- + +*BizDeedz, Inc. | Operational Automation for Legal* diff --git a/BizDeedz/Offers/Internal-Delivery-SOP.md b/BizDeedz/Offers/Internal-Delivery-SOP.md new file mode 100644 index 0000000..4e00f3d --- /dev/null +++ b/BizDeedz/Offers/Internal-Delivery-SOP.md @@ -0,0 +1,681 @@ +# AI Readiness Accelerator: Internal Delivery SOP + +**Version:** 1.0 +**Last Updated:** February 2026 +**Owner:** Delivery Lead + +--- + +## Table of Contents + +1. [Engagement Checklist](#1-engagement-checklist) +2. [Phase A: Demand Capture](#2-phase-a-demand-capture) +3. [Phase B: Intake & Data Room](#3-phase-b-intake--data-room) +4. [Phase C: Readiness Assessment](#4-phase-c-readiness-assessment) +5. [Phase D: Use-Case Portfolio](#5-phase-d-use-case-portfolio) +6. [Phase E: Roadmap & Governance](#6-phase-e-roadmap--governance) +7. [Templates & Checklists](#7-templates--checklists) +8. [Automation Runbook](#8-automation-runbook) + +--- + +## 1. Engagement Checklist + +### Pre-Kickoff Checklist + +- [ ] Discovery call completed +- [ ] Client qualifies (see fit criteria below) +- [ ] SOW sent and signed +- [ ] Initial payment received (50%) +- [ ] Kickoff meeting scheduled +- [ ] Client contact info captured in CRM +- [ ] Pre-call questionnaire sent + +### Qualification Criteria (Must Have 4/5) + +| Criterion | Indicator | +|-----------|-----------| +| Practice area fit | Bankruptcy, family, estate, civil litigation | +| Firm size | 5-50 attorneys | +| Has practice management | Clio, MyCase, PracticePanther, etc. | +| Has support staff | At least 1 paralegal or intake coordinator | +| Clear pain point | Intake, drafting, deadlines, or data chaos | + +### Disqualification Triggers + +- Solo practitioner with no staff +- No practice management system +- Active litigation hold affecting data access +- Budget below $4,000 +- No decision-maker access within 14 days + +--- + +## 2. Phase A: Demand Capture + +### Objective +Convert attention into qualified, booked diagnostic call. + +### Process Steps + +| Step | Action | Owner | Automation | +|------|--------|-------|------------| +| A1 | Lead captured (form, LinkedIn, referral) | Marketing | Auto-log to CRM | +| A2 | Lead scored and routed | - | Auto-score based on form fields | +| A3 | Booking link sent | - | Auto-email with Calendly link | +| A4 | Confirmation + reminders | - | Auto-sequence (24hr, 1hr before) | +| A5 | Pre-call questionnaire sent | - | Auto-send on booking confirmation | +| A6 | Discovery call conducted | Delivery Lead | Manual | +| A7 | Scope locked, SOW sent | Delivery Lead | Manual (template-based) | +| A8 | Payment processed | - | Stripe/ACH | +| A9 | Kickoff scheduled | - | Auto-calendar on payment | + +### Pre-Call Questionnaire Fields + +``` +1. Firm name +2. Primary practice area(s) +3. Number of attorneys +4. Number of support staff (paralegals, intake, admin) +5. Practice management software +6. Document management system +7. Biggest operational pain point (select top 2): + - Intake bottlenecks + - Drafting takes too long + - Missed deadlines + - Data chaos / can't find things + - Client communication gaps + - Rework / quality issues + - Other: ___ +8. Have you tried AI tools before? (Y/N) +9. If yes, what happened? +10. Who will be the decision-maker for this engagement? +11. What does success look like in 90 days? +``` + +--- + +## 3. Phase B: Intake & Data Room + +### Objective +Collect all artifacts within 48 hours of kickoff. + +### Data Room Structure + +``` +[CLIENT NAME] - AI Readiness/ +├── 00-Admin/ +│ ├── SOW-Signed.pdf +│ ├── Contacts.md +│ └── Timeline.md +├── 01-Org-and-Roles/ +│ ├── org-chart.pdf +│ └── role-list.csv +├── 02-Tool-Stack/ +│ ├── tools-inventory.csv +│ └── screenshots/ +├── 03-Sample-Matters/ +│ └── [10-20 redacted matter files] +├── 04-SOPs-Templates/ +│ ├── intake-scripts/ +│ ├── checklists/ +│ ├── pleadings-templates/ +│ └── email-templates/ +├── 05-KPI-Exports/ +│ ├── leads.csv +│ ├── consults.csv +│ ├── retainers.csv +│ └── cycle-times.csv +└── 06-Deliverables/ + └── [Output files go here] +``` + +### Artifact Checklist (Send to Client) + +```markdown +## Required Artifacts for AI Readiness Assessment + +Please upload the following to your secure data room by [DATE]: + +### Organization (Folder: 01-Org-and-Roles) +- [ ] Org chart or team structure diagram +- [ ] List of roles that touch intake, drafting, filing, and client comms + +### Technology (Folder: 02-Tool-Stack) +- [ ] List of software tools used (practice mgmt, email, DMS, billing, e-sign) +- [ ] Screenshots of main dashboards (optional but helpful) + +### Sample Work (Folder: 03-Sample-Matters) +- [ ] 10-20 sample matters (redact client PII as needed) +- [ ] Mix of: new intake, in-progress, and closed matters + +### Processes (Folder: 04-SOPs-Templates) +- [ ] Intake scripts or call guides +- [ ] Checklists used for case setup or filing +- [ ] Pleading or document templates +- [ ] Email templates for client communication + +### Metrics (Folder: 05-KPI-Exports) +- [ ] Lead/intake volume (last 6-12 months) +- [ ] Consultation-to-retainer conversion data +- [ ] Filing cycle times (if tracked) +- [ ] Any rework or rejection tracking + +--- + +Questions? Reply to this email or message [CONTACT]. + +Upload link: [DATA ROOM URL] +``` + +### Auto-Chase Sequence + +| Day | Action | +|-----|--------| +| Day 0 | Initial artifact request | +| Day 1 | Status check ("anything blocking you?") | +| Day 2 | Escalation ("we need X to stay on schedule") | +| Day 3 | Call if incomplete | + +--- + +## 4. Phase C: Readiness Assessment + +### Objective +Score the firm across 6 pillars that predict AI success. + +### Assessment Interview Guide + +**Interview 1: Intake Coordinator (45-60 min)** + +``` +1. Walk me through what happens when a new lead calls or fills out a form. +2. How do you determine if someone is a good fit? +3. What information do you collect at first contact? +4. Where does that information get recorded? +5. How do you hand off to the attorney or paralegal? +6. What are the most common reasons a lead doesn't become a client? +7. What do you wish was easier or faster? +``` + +**Interview 2: Paralegal (60 min)** + +``` +1. Walk me through a typical new matter setup. +2. Where do you get the client information from? +3. What documents do you typically draft first? +4. Where do templates live? How current are they? +5. How do you track deadlines and filings? +6. What causes the most rework or delays? +7. How do you communicate status to clients? +8. What tools do you use daily? What's frustrating about them? +``` + +**Interview 3: Attorney (45-60 min)** + +``` +1. What's your biggest bottleneck right now? +2. How do you review paralegal work before filing? +3. What types of errors do you catch most often? +4. How confident are you in your current data/reporting? +5. What's your appetite for AI? Concerns? +6. Who would champion a new system? Who would resist? +7. What does success look like in 6 months? +``` + +### Assessment Scoring Rubric + +**Score each pillar 0-5:** + +| Score | Definition | +|-------|------------| +| 0 | Non-existent | +| 1 | Ad-hoc, inconsistent | +| 2 | Defined but not followed | +| 3 | Followed with exceptions | +| 4 | Consistent, measured | +| 5 | Optimized, continuously improving | + +#### Pillar 1: Process Maturity + +| Indicator | 0-1 | 2-3 | 4-5 | +|-----------|-----|-----|-----| +| Intake flow | No standard process | Written SOP exists | SOP followed, measured | +| Case setup | Different every time | Template exists | Automated checklist | +| Drafting | Start from scratch | Templates used | Version-controlled library | +| Filing | Manual, error-prone | Checklist exists | Tracked with SLAs | + +#### Pillar 2: Data Quality + +| Indicator | 0-1 | 2-3 | 4-5 | +|-----------|-----|-----|-----| +| Field consistency | Free-text chaos | Some dropdowns | Enforced taxonomy | +| Duplicate rate | >10% | 5-10% | <5% | +| Null/missing | >20% critical fields | 10-20% | <10% | +| Naming conventions | None | Informal | Enforced | + +#### Pillar 3: Knowledge System + +| Indicator | 0-1 | 2-3 | 4-5 | +|-----------|-----|-----|-----| +| Template location | Scattered, unknown | Central folder | Versioned library | +| SOPs | In people's heads | Written, outdated | Current, accessible | +| FAQ/playbooks | None | Informal | Documented, searchable | + +#### Pillar 4: Tooling & Integrations + +| Indicator | 0-1 | 2-3 | 4-5 | +|-----------|-----|-----|-----| +| Practice mgmt | Spreadsheets/paper | Basic PM tool | Mature PM with integrations | +| Document mgmt | Local drives | Shared drive | DMS with version control | +| Integrations | Copy-paste between | Some manual sync | API connections | + +#### Pillar 5: Risk & Governance + +| Indicator | 0-1 | 2-3 | 4-5 | +|-----------|-----|-----|-----| +| Data access | No controls | Role-based folders | Permissioned DMS | +| AI policy | None | Informal guidance | Written policy | +| Audit trail | None | Some logging | Complete audit trail | +| Retention | Ad-hoc | Written policy | Automated enforcement | + +#### Pillar 6: Change Capacity + +| Indicator | 0-1 | 2-3 | 4-5 | +|-----------|-----|-----|-----| +| Training history | No formal training | Occasional | Regular, documented | +| Adoption track record | Changes fail | Mixed results | Changes stick | +| Role clarity | Unclear ownership | Defined roles | Accountable owners | +| Executive support | Skeptical | Interested | Active sponsor | + +### Data Profiling Checklist + +Run on each CSV export: + +``` +- [ ] Row count +- [ ] Column inventory +- [ ] Null rate per column +- [ ] Duplicate detection (by key field) +- [ ] Date format consistency +- [ ] Outlier detection (numeric fields) +- [ ] Taxonomy analysis (categorical fields) +``` + +### Assessment Output + +Internal workbook with: +- Pillar scores (0-5) +- Evidence notes for each score +- Direct quotes from interviews +- Data quality findings +- Key risks identified + +--- + +## 5. Phase D: Use-Case Portfolio + +### Objective +Select 3-5 AI opportunities that are feasible AND worth it. + +### Use-Case Scoring Matrix + +Score each candidate 1-5: + +| Criterion | Weight | Definition | +|-----------|--------|------------| +| Volume | 25% | How often does this happen? | +| Repetitiveness | 20% | Same process each time? | +| Data availability | 20% | Is input data clean and accessible? | +| Impact | 20% | Time saved, errors reduced, revenue captured | +| Risk | 15% | What's the blast radius if AI fails? | + +**Scoring:** +- Volume: 1=monthly, 3=weekly, 5=daily+ +- Repetitive: 1=unique each time, 5=identical process +- Data: 1=unstructured chaos, 5=clean structured fields +- Impact: 1=minor convenience, 5=major capacity unlock +- Risk: 1=high (client-facing legal), 5=low (internal admin) + +### Standard Use-Case Library + +| Use Case | Typical Volume | Complexity | Risk | +|----------|----------------|------------|------| +| Intake triage + routing | High | Low | Medium | +| Document classification + filing | High | Low | Low | +| Deadline extraction + task creation | High | Medium | Medium | +| Template-based drafting assist | Medium | Medium | High | +| Client status updates | High | Low | Low | +| Missing document requests | Medium | Low | Low | +| Conflict check assistance | Medium | Medium | High | + +### Use-Case One-Pager Template + +```markdown +## [USE CASE NAME] + +### Problem +[What pain does this solve? Current state.] + +### Workflow +1. Trigger: [What kicks this off?] +2. Input: [What data/documents are needed?] +3. Process: [What does the automation do?] +4. Output: [What gets created/updated?] +5. Human checkpoint: [Where does a person review?] + +### Controls +- [ ] Confidence threshold for escalation +- [ ] Human review before client-facing output +- [ ] Audit logging +- [ ] Exception handling + +### Success Metrics +- Cycle time: [Before] → [After] +- Error rate: [Before] → [After] +- Volume capacity: [Before] → [After] + +### Effort Estimate +- Implementation: [S/M/L] +- Change management: [S/M/L] +- Risk: [Low/Medium/High] + +### ROI Projection +| Metric | Assumption | Value | +|--------|------------|-------| +| Hours saved/week | X tasks × Y min each | Z hours | +| Hourly value | Staff cost or billable | $XX | +| Annual value | (Hours × Rate × 50 weeks) | $XX,XXX | +| Implementation cost | Sprint(s) required | $XX,XXX | +| Payback period | Months | X months | +``` + +--- + +## 6. Phase E: Roadmap & Governance + +### Objective +Deliver board-ready plan with clear next steps. + +### Deliverables Checklist + +- [ ] AI Readiness Scorecard (PDF) +- [ ] Risk Register (spreadsheet) +- [ ] Prioritized Roadmap (PDF + task board) +- [ ] Data Cleanup Plan (document) +- [ ] Use-Case Portfolio (PDF + one-pagers) +- [ ] Governance Starter Kit (document bundle) + +### Scorecard Template Structure + +``` +Page 1: Executive Summary +- Overall readiness score (average of pillars) +- Top 3 strengths +- Top 3 gaps +- Recommended first move + +Page 2: Pillar Scores +- Spider chart visualization +- Score breakdown by pillar +- Benchmark comparison (if available) + +Pages 3-8: Pillar Details +- Score + rationale +- Key findings +- Recommendations + +Page 9: Use-Case Portfolio Summary +- Ranked list with effort/impact/risk +- Recommended sequence + +Page 10: Roadmap Overview +- 30/60/90 day milestones +- Dependencies +- Resource requirements + +Page 11: Governance Summary +- Key policies needed +- Risk controls +- Next steps + +Page 12: Appendix +- Data quality findings +- Interview summary +- Assumptions +``` + +### Risk Register Template + +| Risk ID | Category | Description | Likelihood | Impact | Controls | Owner | Status | +|---------|----------|-------------|------------|--------|----------|-------|--------| +| R001 | Data | Inconsistent matter taxonomy | High | Medium | Standardize fields | Ops | Open | +| R002 | Compliance | No AI usage policy | High | High | Draft policy | Partner | Open | +| R003 | Adoption | Staff resistance | Medium | High | Training plan | Mgr | Open | + +### Governance Starter Kit Contents + +**Document 1: AI Acceptable Use Policy (2-3 pages)** + +```markdown +## Purpose +This policy governs the use of AI tools at [FIRM NAME]. + +## Scope +Applies to all attorneys, paralegals, and staff. + +## Approved Uses +- Document classification and filing +- Deadline extraction and task creation +- Drafting assistance using approved templates +- Internal research and summarization +- Client communication drafts (with human review) + +## Prohibited Uses +- Legal advice to clients without attorney review +- Submission of AI output without human verification +- Use of client data in public AI tools (ChatGPT, etc.) +- Creating final work product without attorney sign-off + +## Human Review Requirements +- All client-facing output requires attorney review +- All legal analysis requires attorney verification +- All filings require human quality check + +## Data Protection +- Client data may only be used with approved, secure AI tools +- No client PII in prompts to public models +- All AI interactions must be logged + +## Compliance +Violations subject to disciplinary action. +``` + +**Document 2: Access & Permissions Model** + +```markdown +## Role-Based Access + +| Role | Practice Mgmt | DMS | AI Tools | Client Data | +|------|---------------|-----|----------|-------------| +| Partner | Full | Full | Full | Full | +| Associate | Full | Full | Full | Assigned | +| Paralegal | Edit | Edit | Supervised | Assigned | +| Intake | Create | Read | None | Limited | +| Admin | Read | Read | None | None | +``` + +**Document 3: Human-in-the-Loop Rules** + +```markdown +## Escalation Triggers + +AI output requires human review when: +- Confidence score < 85% +- New matter type not in training set +- Client-facing communication +- Filing or court submission +- Any fee-related calculation +- Conflict check results + +## Exception Handling + +When AI fails or flags uncertainty: +1. Route to designated human reviewer +2. Log exception with context +3. Complete task manually +4. Flag for model improvement review +``` + +--- + +## 7. Templates & Checklists + +### Discovery Call Script + +``` +"Thanks for taking the time today. I'd like to understand your +current situation, your goals around AI, and whether we're a +good fit to help. + +1. Tell me about your firm—practice areas, size, structure. + +2. What's driving your interest in AI right now? + +3. What's your biggest operational pain point today? + +4. What tools are you currently using for practice management, + documents, and client communication? + +5. Have you tried any AI tools? What happened? + +6. If we could wave a magic wand, what would be different in + 90 days? + +7. Who else would be involved in a decision like this? + +8. What questions do you have for me? + +--- + +[If qualified] + +Here's what I'm thinking: Our AI Readiness Accelerator is a +10-14 day engagement where we assess your operations, identify +the 3-5 AI opportunities that are actually worth pursuing, and +give you a roadmap with the governance controls to do it safely. + +It's $4,500 fixed-fee. If you're interested, I can send over a +scope of work today and we could kick off as early as [DATE]. + +What questions do you have?" +``` + +### Executive Readout Agenda (90 min) + +``` +1. Welcome + context (5 min) +2. Scorecard walkthrough (20 min) +3. Risk register highlights (10 min) +4. Use-case portfolio deep dive (20 min) +5. Roadmap presentation (15 min) +6. Governance overview (10 min) +7. Discussion + Q&A (10 min) +8. Next steps + close (5 min) +``` + +### Post-Engagement Handoff Checklist + +- [ ] All deliverables uploaded to client data room +- [ ] Client execution board created (Notion/Planner) +- [ ] Final invoice sent +- [ ] Feedback request sent (NPS + testimonial ask) +- [ ] CRM updated with outcome +- [ ] Implementation proposal sent (if requested) +- [ ] 30-day follow-up scheduled + +--- + +## 8. Automation Runbook + +### What to Automate + +| Process | Tool | Trigger | Action | +|---------|------|---------|--------| +| Lead capture → CRM | Make/Zapier | Form submit | Create CRM record + tag | +| Lead scoring | Make | CRM record created | Calculate score, route | +| Booking confirmation | Calendly | Event booked | Send confirmation + pre-call form | +| Reminder sequence | Make | Event -24h, -1h | Send reminder emails | +| Data room creation | Make | SOW signed | Create folder structure in Drive | +| Artifact checklist | Make | Data room created | Send checklist email + create tasks | +| Chase sequence | Make | Day 1, 2, 3 | Send follow-up if incomplete | +| Report generation | Google Docs | Assessment complete | Populate template from data | +| Invoice creation | Stripe/QBO | Milestone reached | Generate and send invoice | +| Follow-up scheduling | Make | Engagement complete | Create 30-day task | + +### Make.com Scenario Outlines + +**Scenario 1: Lead → CRM → Booking** + +``` +Trigger: Typeform/Webflow form submission +→ Parse form fields +→ Create Notion/Airtable record +→ Calculate lead score (weighted fields) +→ If score >= threshold: + → Send Calendly link email + → Tag as "Qualified" +→ Else: + → Send "not a fit" email + → Tag as "Disqualified" +``` + +**Scenario 2: Booking → Pre-Call Prep** + +``` +Trigger: Calendly event created +→ Create CRM deal/opportunity +→ Send pre-call questionnaire (Typeform) +→ Schedule reminder emails (-24h, -1h) +→ Create prep task for delivery lead +``` + +**Scenario 3: Payment → Kickoff** + +``` +Trigger: Stripe payment received +→ Update CRM status +→ Create Google Drive folder structure +→ Add client to shared Drive +→ Send welcome email with data room link +→ Send artifact checklist +→ Create intake task with Day 2 deadline +``` + +**Scenario 4: Artifact Chase** + +``` +Trigger: Daily at 9am +→ Check data room for required files +→ For each client with incomplete room: + → If Day 1: Send "anything blocking you?" + → If Day 2: Send "we need X to stay on schedule" + → If Day 3: Create escalation task + Slack alert +``` + +--- + +## Appendix: File Naming Conventions + +``` +[CLIENT]-[DOC TYPE]-[VERSION]-[DATE].ext + +Examples: +- AcmeLaw-Scorecard-v1-2026-02-15.pdf +- AcmeLaw-UseCase-IntakeRouting-v1.md +- AcmeLaw-Roadmap-v2-2026-02-20.pdf +``` + +--- + +*End of Internal Delivery SOP* diff --git a/BizDeedz/Offers/SOW-Template.md b/BizDeedz/Offers/SOW-Template.md new file mode 100644 index 0000000..5e7fd58 --- /dev/null +++ b/BizDeedz/Offers/SOW-Template.md @@ -0,0 +1,291 @@ +# Statement of Work +## AI Readiness Accelerator + +**Client:** [FIRM NAME] +**Prepared by:** BizDeedz, Inc. +**Date:** [DATE] +**SOW Version:** 1.0 + +--- + +## 1. Engagement Overview + +### 1.1 Purpose +BizDeedz will conduct an AI Readiness Assessment for [FIRM NAME] to evaluate operational readiness for AI deployment, identify high-value automation opportunities, and deliver a prioritized implementation roadmap with governance controls. + +### 1.2 Engagement Type +- [ ] AI Readiness Scorecard (Assessment Only) +- [ ] AI Readiness Scorecard + Implementation Sprint 1 +- [ ] Full Engagement (Scorecard + Implementation + Retainer) + +### 1.3 Timeline +| Milestone | Target Date | +|-----------|-------------| +| Kickoff | [DATE] | +| Data Room Complete | [DATE + 2 days] | +| Assessment Complete | [DATE + 6 days] | +| Deliverables Presentation | [DATE + 12 days] | +| Executive Readout | [DATE + 14 days] | + +--- + +## 2. Scope of Work + +### 2.1 Phase A: Pre-Engagement (Pre-Kickoff) + +**BizDeedz Responsibilities:** +- Conduct discovery call to confirm scope and fit +- Deliver pre-call snapshot questionnaire +- Validate engagement prerequisites + +**Client Responsibilities:** +- Complete pre-call questionnaire +- Confirm decision-maker availability for readout +- Execute this SOW and submit initial payment + +**Deliverable:** Signed SOW, scheduled kickoff + +--- + +### 2.2 Phase B: Intake & Data Room Setup (Days 0-2) + +**BizDeedz Responsibilities:** +- Create secure client data room (Google Workspace) +- Provide standardized artifact checklist +- Send automated reminders for missing items +- Confirm data room completion + +**Client Responsibilities:** +- Provide access to designated contact +- Submit required artifacts within 48 hours: + - [ ] Org chart / role list + - [ ] Tool stack inventory + - [ ] 10-20 sample matters (redacted as needed) + - [ ] SOPs and templates currently in use + - [ ] KPI exports (leads, consults, retainers, cycle times) + +**Deliverable:** Completed data room with all artifacts logged + +--- + +### 2.3 Phase C: Readiness Assessment (Days 3-6) + +**BizDeedz Responsibilities:** +- Conduct process walkthroughs with designated staff +- Perform data quality profiling on submitted exports +- Complete systems inventory and integration mapping +- Score firm across 6 assessment pillars (0-5 scale): + 1. Process Maturity + 2. Data Quality + 3. Knowledge Systems + 4. Tooling & Integrations + 5. Risk & Governance + 6. Change Capacity + +**Client Responsibilities:** +- Make available for interview (60-90 min each): + - [ ] 1 intake coordinator or receptionist + - [ ] 1-2 paralegals + - [ ] 1 attorney (preferably managing partner or practice lead) +- Provide screen-share access to demonstrate current workflows + +**Deliverable:** Completed assessment workbook (internal) + +--- + +### 2.4 Phase D: Use-Case Portfolio & ROI Model (Days 7-9) + +**BizDeedz Responsibilities:** +- Identify candidate AI use cases from assessment findings +- Score use cases by feasibility, impact, and risk +- Build ROI model with assumptions documented +- Draft use-case one-pagers for top 3-5 opportunities + +**Use-Case Selection Criteria:** +- High volume + repetitive + rules-based +- Clear success metrics (cycle time, rework, conversion) +- Low ambiguity or defined escalation rules +- Acceptable risk footprint with controls + +**Client Responsibilities:** +- Validate volume and frequency assumptions +- Confirm strategic priorities for use-case ranking + +**Deliverable:** Ranked use-case portfolio with ROI projections + +--- + +### 2.5 Phase E: Roadmap & Governance Kit (Days 10-12) + +**BizDeedz Responsibilities:** +- Compile AI Readiness Scorecard (final report) +- Create Risk Register with controls and owners +- Build Prioritized Roadmap (30/60/90 days) +- Draft Data Cleanup Plan (taxonomy, naming, minimum viable data) +- Assemble Governance Starter Kit: + - AI Acceptable Use Policy + - Access/Permissions Model + - Retention & Logging Requirements + - Human-in-the-Loop Rules + +**Client Responsibilities:** +- Review draft materials prior to final presentation +- Confirm attendees for executive readout + +**Deliverable:** Complete deliverables package (PDF + source files) + +--- + +### 2.6 Phase F: Executive Readout (Days 13-14) + +**BizDeedz Responsibilities:** +- Conduct 90-minute executive presentation +- Walk through scorecard, roadmap, and governance kit +- Facilitate discussion on next steps +- Provide implementation proposal if requested + +**Client Responsibilities:** +- Ensure decision-maker attendance +- Come prepared with questions and priorities + +**Deliverable:** Recorded session (optional), decision on next phase + +--- + +## 3. Out of Scope + +The following are explicitly excluded from this engagement: + +- Legal advice or ethics opinions +- Implementation of AI tools or automations +- Data migration or system configuration +- Staff training or change management programs +- Ongoing support beyond the engagement period +- Custom software development +- Compliance certifications or audits + +*Implementation services available as separate sprints.* + +--- + +## 4. Client Responsibilities Summary + +| Responsibility | Due | +|----------------|-----| +| Execute SOW and submit payment | Before kickoff | +| Complete pre-call questionnaire | Before kickoff | +| Submit all data room artifacts | Day 2 | +| Make staff available for interviews | Days 3-5 | +| Review draft deliverables | Day 11 | +| Attend executive readout | Day 13-14 | + +**Designated Client Contact:** [NAME, EMAIL, PHONE] + +--- + +## 5. Assumptions & Dependencies + +1. Client will provide timely access to requested data and personnel +2. Artifacts will be delivered in usable formats (PDF, CSV, DOCX) +3. Sample matters will be appropriately redacted for confidentiality +4. No material changes to firm operations during assessment period +5. Decision-maker(s) will be available for final readout + +**Schedule Impact:** Delays in artifact submission or interview availability will extend timeline day-for-day. + +--- + +## 6. Confidentiality & Data Handling + +- All client data will be stored in a dedicated, access-controlled Google Workspace +- BizDeedz will not share client data with third parties +- Sample matters and client information will be deleted within 30 days of engagement completion unless retention is requested +- BizDeedz may retain anonymized, aggregated findings for benchmarking purposes + +--- + +## 7. Pricing & Payment Terms + +### 7.1 Investment + +| Item | Fee | +|------|-----| +| AI Readiness Scorecard (Phases B-E) | $4,500 | +| **Total** | **$4,500** | + +### 7.2 Payment Schedule + +| Milestone | Amount | Due | +|-----------|--------|-----| +| Engagement Start | $2,250 (50%) | Upon SOW execution | +| Deliverables Complete | $2,250 (50%) | Upon executive readout | + +### 7.3 Payment Method +- ACH transfer (preferred) +- Credit card (+3% processing fee) + +### 7.4 Expenses +No travel or expenses anticipated. If travel is requested, expenses will be billed at cost with prior approval. + +--- + +## 8. Change Management + +Any changes to scope, timeline, or deliverables require written agreement from both parties. Changes may result in adjusted fees and timelines. + +--- + +## 9. Limitation of Liability + +BizDeedz's liability under this SOW shall not exceed the total fees paid. BizDeedz is not liable for client's implementation decisions, AI tool performance, or outcomes resulting from client actions taken after the engagement. + +--- + +## 10. Acceptance + +By signing below, both parties agree to the terms of this Statement of Work. + +**BizDeedz, Inc.** + +Signature: ________________________ +Name: ________________________ +Title: ________________________ +Date: ________________________ + +**[CLIENT FIRM NAME]** + +Signature: ________________________ +Name: ________________________ +Title: ________________________ +Date: ________________________ + +--- + +## Appendix A: Implementation Sprint Scope (If Selected) + +*To be scoped separately based on assessment findings.* + +| Sprint | Duration | Typical Scope | +|--------|----------|---------------| +| Sprint 1 | 2 weeks | Data taxonomy, intake routing, document automation foundation | +| Sprint 2 | 2 weeks | Drafting assist on templates, QC checkpoints | +| Sprint 3 | 2 weeks | Dashboards, adoption system, training | + +**Sprint Pricing:** $7,500 per 2-week sprint (fixed scope) + +--- + +## Appendix B: Optimization Retainer (If Selected) + +**Monthly Investment:** $2,500/month (minimum 3-month commitment) + +**Includes:** +- Monthly KPI performance review +- Automation health monitoring +- Backlog grooming and sprint recommendations +- Quarterly governance refresh +- Slack/email support (SLA: 24-hour response) + +--- + +*End of Statement of Work* diff --git a/BizDeedz/Offers/templates/AI-Acceptable-Use-Policy.md b/BizDeedz/Offers/templates/AI-Acceptable-Use-Policy.md new file mode 100644 index 0000000..41af44a --- /dev/null +++ b/BizDeedz/Offers/templates/AI-Acceptable-Use-Policy.md @@ -0,0 +1,334 @@ +# AI Acceptable Use Policy + +**[FIRM NAME]** + +**Effective Date:** [DATE] +**Version:** 1.0 +**Approved By:** [NAME, TITLE] + +--- + +## 1. Purpose + +This policy establishes guidelines for the acceptable use of artificial intelligence (AI) tools and services at [FIRM NAME]. It ensures AI is used in ways that enhance our practice while protecting client confidentiality, maintaining professional responsibility, and managing risk. + +--- + +## 2. Scope + +This policy applies to: +- All attorneys, paralegals, and staff +- All AI tools, including but not limited to: + - Generative AI (ChatGPT, Claude, Copilot, etc.) + - Practice-specific AI features in our software + - Automation tools with AI components + - Research and analytics tools using AI +- All work performed on behalf of the firm, including remote work + +--- + +## 3. Definitions + +**AI Tool:** Any software or service that uses machine learning, natural language processing, or similar technologies to generate, analyze, or process information. + +**Public AI Tool:** AI services accessible to the general public where input may be used to train models or stored by third parties (e.g., free-tier ChatGPT, Bard). + +**Enterprise AI Tool:** AI services with business agreements that include data protection, no training on inputs, and contractual safeguards. + +**Approved AI Tool:** An AI tool vetted and authorized by the firm for specific use cases. + +--- + +## 4. Guiding Principles + +1. **Human Judgment First:** AI assists human decision-making; it does not replace professional judgment. + +2. **Client Protection:** Client confidentiality and privilege must never be compromised. + +3. **Accuracy Over Speed:** AI output must be verified before use; speed gains cannot come at the cost of correctness. + +4. **Transparency:** When relevant, clients should be informed about AI use in their matters. + +5. **Continuous Learning:** We will regularly review and update AI practices as technology and ethics evolve. + +--- + +## 5. Approved Uses + +The following uses of AI are **approved** when using vetted, enterprise AI tools: + +### 5.1 Internal Productivity + +- Summarizing internal documents and research +- Drafting internal communications +- Generating first drafts of administrative content +- Brainstorming and outlining + +### 5.2 Legal Work (with Human Review) + +| Activity | AI Role | Human Requirement | +|----------|---------|-------------------| +| Document classification | Suggest category | Paralegal confirms | +| Template-based drafting | Generate first draft | Attorney reviews and edits | +| Deadline extraction | Identify dates from documents | Paralegal verifies | +| Research summarization | Summarize sources | Attorney validates | +| Client communication drafts | Generate draft text | Attorney approves before send | + +### 5.3 Intake and Client Service + +- Summarizing intake form responses +- Generating follow-up email drafts (human review required) +- Suggesting matter routing based on criteria +- Extracting key information from documents + +--- + +## 6. Prohibited Uses + +The following uses are **strictly prohibited**: + +### 6.1 Public AI Tools with Client Data + +**Never** input the following into public AI tools: +- Client names or identifying information +- Case details or facts +- Privileged communications +- Confidential documents or their contents +- Opposing party information +- Financial or billing data + +### 6.2 Unsupervised Legal Work + +- Generating legal advice sent directly to clients without attorney review +- Filing documents created by AI without human verification +- Making strategic decisions based solely on AI recommendations +- Using AI output as final work product + +### 6.3 Misrepresentation + +- Representing AI-generated content as original human work when disclosure is required +- Using AI to create false or misleading information +- Fabricating citations or authorities (AI "hallucinations") + +### 6.4 Circumventing Controls + +- Disabling logging or audit features +- Using personal accounts for firm work +- Sharing credentials for AI tools +- Using unapproved AI tools for client matters + +--- + +## 7. Client Data Protection + +### 7.1 Before Using AI with Client Information + +1. **Confirm the tool is approved** for use with client data +2. **Verify data handling terms** (no training, encryption, deletion) +3. **Consider necessity:** Is AI needed, or is manual processing appropriate? +4. **Minimize data:** Use only the information required + +### 7.2 Data Handling Requirements + +| Data Type | Public AI | Enterprise AI (Approved) | +|-----------|-----------|--------------------------| +| Client PII | Never | With controls | +| Case facts | Never | With controls | +| Privileged content | Never | Carefully, with controls | +| Public information | Permitted | Permitted | +| Internal admin | Permitted | Permitted | + +### 7.3 Engagement Letters + +Consider including AI disclosure language in engagement letters: + +> "Our firm may use artificial intelligence tools to assist with administrative tasks, document processing, and legal research. All AI-assisted work is reviewed by qualified attorneys. Client information is only used with AI tools that meet our data protection standards and is never used to train AI models." + +--- + +## 8. Human Review Requirements + +### 8.1 Mandatory Human Review + +The following **always** require human review before use or transmission: + +- Any communication sent to clients +- Any document filed with a court or agency +- Any legal advice or recommendations +- Any document sent to opposing counsel +- Any content containing legal citations +- Any work product leaving the firm + +### 8.2 Review Standards + +When reviewing AI output, the reviewer must: + +1. **Verify accuracy:** Confirm facts, citations, and calculations +2. **Check for hallucinations:** Validate that cited cases/statutes exist +3. **Assess appropriateness:** Ensure tone and content fit the purpose +4. **Apply judgment:** Consider what AI cannot—strategy, nuance, ethics +5. **Take ownership:** The reviewer is responsible for the final product + +--- + +## 9. Approved AI Tools + +### 9.1 Currently Approved + +| Tool | Approved Uses | Restrictions | +|------|---------------|--------------| +| [TOOL 1] | [Uses] | [Restrictions] | +| [TOOL 2] | [Uses] | [Restrictions] | +| [PM Software AI Features] | [Uses] | [Restrictions] | + +### 9.2 Requesting New Tools + +To request approval for a new AI tool: + +1. Submit request to [ROLE/EMAIL] +2. Provide: vendor name, use case, data handling terms, cost +3. IT/Compliance will evaluate security and privacy +4. Managing partner approval required for client data use +5. If approved, tool is added to this policy + +--- + +## 10. Logging and Audit + +### 10.1 What Is Logged + +- Use of AI tools (who, when, which tool) +- Queries involving client matters +- Output saved to client files + +### 10.2 Audit Rights + +The firm reserves the right to: +- Review AI usage logs +- Audit compliance with this policy +- Investigate suspected violations + +### 10.3 Retention + +AI interaction logs are retained for [X YEARS] consistent with our data retention policy. + +--- + +## 11. Training and Competence + +### 11.1 Required Training + +All staff must complete AI usage training: +- Initial training upon policy adoption +- Refresher training annually +- Update training when policy changes + +### 11.2 Training Content + +- This policy and its requirements +- Approved vs. prohibited uses +- Recognizing AI limitations and errors +- Data protection practices +- Reporting concerns + +--- + +## 12. Reporting Concerns + +### 12.1 What to Report + +- Suspected policy violations +- AI tool security concerns +- Potential client data exposure +- Observed AI errors or risks + +### 12.2 How to Report + +Report concerns to [ROLE/EMAIL]. Reports may be made anonymously. + +### 12.3 No Retaliation + +The firm prohibits retaliation against anyone who reports AI concerns in good faith. + +--- + +## 13. Violations + +### 13.1 Consequences + +Violations of this policy may result in: +- Additional training +- Revocation of AI access +- Disciplinary action up to termination +- Professional responsibility referral (if applicable) + +### 13.2 Determining Severity + +| Factor | Lower Severity | Higher Severity | +|--------|----------------|-----------------| +| Intent | Unintentional error | Deliberate bypass | +| Impact | No client data exposed | Client data compromised | +| Pattern | First occurrence | Repeated violations | +| Disclosure | Self-reported | Discovered by others | + +--- + +## 14. Policy Maintenance + +### 14.1 Review Cycle + +This policy will be reviewed: +- Quarterly for the first year +- Annually thereafter +- Upon significant AI developments or incidents + +### 14.2 Updates + +Policy updates require: +- Review by [ROLE] +- Approval by [ROLE] +- Communication to all staff +- Training on material changes + +--- + +## 15. Acknowledgment + +I have read and understand the AI Acceptable Use Policy. I agree to comply with its requirements. + +**Name:** _________________________ + +**Title:** _________________________ + +**Signature:** _________________________ + +**Date:** _________________________ + +--- + +## Appendix A: Quick Reference Card + +### Always OK +- Summarizing your own notes +- Drafting internal emails +- Brainstorming ideas +- Learning about legal concepts (general) + +### OK with Approved Tools + Human Review +- Drafting from templates +- Summarizing documents +- Client communication drafts +- Research assistance + +### Never OK +- Client data in public AI +- Sending AI output without review +- Fabricated citations +- Bypassing controls + +### When in Doubt +Ask [ROLE] before proceeding. + +--- + +*Policy prepared with assistance from BizDeedz, Inc.* diff --git a/BizDeedz/Offers/templates/AI-Readiness-Scorecard-Template.md b/BizDeedz/Offers/templates/AI-Readiness-Scorecard-Template.md new file mode 100644 index 0000000..28906b4 --- /dev/null +++ b/BizDeedz/Offers/templates/AI-Readiness-Scorecard-Template.md @@ -0,0 +1,388 @@ +# AI Readiness Scorecard + +**Client:** [FIRM NAME] +**Assessment Date:** [DATE] +**Prepared by:** BizDeedz, Inc. + +--- + +## Executive Summary + +### Overall Readiness Score: [X.X] / 5.0 + +**Readiness Level:** [Not Ready | Foundational | Developing | Ready | Optimized] + +| Level | Score Range | Meaning | +|-------|-------------|---------| +| Not Ready | 0.0 - 1.0 | Significant gaps; foundational work required before AI | +| Foundational | 1.1 - 2.0 | Basic elements in place; substantial prep needed | +| Developing | 2.1 - 3.0 | Processes defined; targeted improvements enable AI | +| Ready | 3.1 - 4.0 | Strong foundation; ready for controlled AI deployment | +| Optimized | 4.1 - 5.0 | Mature operations; positioned for advanced AI | + +### Top 3 Strengths + +1. **[STRENGTH 1]:** [One sentence description] +2. **[STRENGTH 2]:** [One sentence description] +3. **[STRENGTH 3]:** [One sentence description] + +### Top 3 Gaps + +1. **[GAP 1]:** [One sentence description + impact] +2. **[GAP 2]:** [One sentence description + impact] +3. **[GAP 3]:** [One sentence description + impact] + +### Recommended First Move + +[2-3 sentences on the single most impactful action to take in the next 30 days] + +--- + +## Pillar Scores + +| Pillar | Score | Status | +|--------|-------|--------| +| 1. Process Maturity | [X] / 5 | [Status] | +| 2. Data Quality | [X] / 5 | [Status] | +| 3. Knowledge System | [X] / 5 | [Status] | +| 4. Tooling & Integrations | [X] / 5 | [Status] | +| 5. Risk & Governance | [X] / 5 | [Status] | +| 6. Change Capacity | [X] / 5 | [Status] | + +*Status: Critical | Needs Work | Adequate | Strong | Excellent* + +### Visual Summary + +``` +Process Maturity [████░░░░░░] 4/5 +Data Quality [██░░░░░░░░] 2/5 +Knowledge System [███░░░░░░░] 3/5 +Tooling [████░░░░░░] 4/5 +Risk & Governance [█░░░░░░░░░] 1/5 +Change Capacity [███░░░░░░░] 3/5 +``` + +--- + +## Pillar 1: Process Maturity + +**Score: [X] / 5** + +### Current State + +[2-3 paragraphs describing the observed process maturity across intake, case setup, drafting, filing, and post-filing workflows. Include specific observations from interviews and artifact review.] + +### Key Findings + +| Area | Finding | Impact | +|------|---------|--------| +| Intake | [Observation] | [Impact on AI readiness] | +| Case Setup | [Observation] | [Impact on AI readiness] | +| Drafting | [Observation] | [Impact on AI readiness] | +| Filing | [Observation] | [Impact on AI readiness] | + +### Recommendations + +1. [Specific recommendation with action] +2. [Specific recommendation with action] +3. [Specific recommendation with action] + +--- + +## Pillar 2: Data Quality + +**Score: [X] / 5** + +### Current State + +[2-3 paragraphs on data quality findings: field consistency, duplicates, nulls, naming conventions, taxonomy.] + +### Data Profiling Results + +| Metric | Value | Benchmark | Status | +|--------|-------|-----------|--------| +| Duplicate Rate | [X]% | <5% | [Pass/Fail] | +| Null Rate (Critical Fields) | [X]% | <10% | [Pass/Fail] | +| Taxonomy Consistency | [X]% | >90% | [Pass/Fail] | +| Naming Convention Compliance | [X]% | >80% | [Pass/Fail] | + +### Critical Field Analysis + +| Field | Completeness | Consistency | Issue | +|-------|--------------|-------------|-------| +| Client Name | [X]% | [X]% | [Issue if any] | +| Matter Type | [X]% | [X]% | [Issue if any] | +| Open Date | [X]% | [X]% | [Issue if any] | +| Assigned Attorney | [X]% | [X]% | [Issue if any] | +| Status | [X]% | [X]% | [Issue if any] | + +### Recommendations + +1. [Specific recommendation with action] +2. [Specific recommendation with action] +3. [Specific recommendation with action] + +--- + +## Pillar 3: Knowledge System + +**Score: [X] / 5** + +### Current State + +[2-3 paragraphs on where institutional knowledge lives: templates, SOPs, playbooks, FAQs, training materials.] + +### Knowledge Inventory + +| Asset Type | Exists | Location | Currency | Accessibility | +|------------|--------|----------|----------|---------------| +| Document Templates | [Y/N] | [Where] | [Current/Outdated] | [Easy/Hard] | +| Intake Scripts | [Y/N] | [Where] | [Current/Outdated] | [Easy/Hard] | +| Process SOPs | [Y/N] | [Where] | [Current/Outdated] | [Easy/Hard] | +| Filing Checklists | [Y/N] | [Where] | [Current/Outdated] | [Easy/Hard] | +| Training Materials | [Y/N] | [Where] | [Current/Outdated] | [Easy/Hard] | + +### Recommendations + +1. [Specific recommendation with action] +2. [Specific recommendation with action] + +--- + +## Pillar 4: Tooling & Integrations + +**Score: [X] / 5** + +### Current State + +[2-3 paragraphs on current technology stack and integration status.] + +### Systems Inventory + +| System | Tool | Integration Status | Data Flow | +|--------|------|-------------------|-----------| +| Practice Management | [Tool] | [Native/API/Manual/None] | [Describe] | +| Document Management | [Tool] | [Native/API/Manual/None] | [Describe] | +| Email | [Tool] | [Native/API/Manual/None] | [Describe] | +| Billing | [Tool] | [Native/API/Manual/None] | [Describe] | +| E-Sign | [Tool] | [Native/API/Manual/None] | [Describe] | +| Intake Forms | [Tool] | [Native/API/Manual/None] | [Describe] | + +### Integration Gaps + +| Gap | Current Workaround | Impact | +|-----|-------------------|--------| +| [Gap 1] | [Manual process] | [Time/errors] | +| [Gap 2] | [Manual process] | [Time/errors] | + +### Recommendations + +1. [Specific recommendation with action] +2. [Specific recommendation with action] + +--- + +## Pillar 5: Risk & Governance + +**Score: [X] / 5** + +### Current State + +[2-3 paragraphs on current governance posture: policies, access controls, audit trails, compliance awareness.] + +### Governance Assessment + +| Control | Status | Gap | +|---------|--------|-----| +| Data access controls | [None/Basic/Role-based/Full] | [Gap if any] | +| AI usage policy | [None/Informal/Written/Enforced] | [Gap if any] | +| Audit trail | [None/Partial/Complete] | [Gap if any] | +| Retention policy | [None/Written/Automated] | [Gap if any] | +| Confidentiality training | [None/Onboarding/Ongoing] | [Gap if any] | + +### Risk Considerations for AI + +| Risk | Likelihood | Impact | Current Control | +|------|------------|--------|-----------------| +| AI output used without review | [H/M/L] | [H/M/L] | [Control or None] | +| Client data in public AI | [H/M/L] | [H/M/L] | [Control or None] | +| Incorrect legal advice | [H/M/L] | [H/M/L] | [Control or None] | + +### Recommendations + +1. [Specific recommendation with action] +2. [Specific recommendation with action] +3. [Specific recommendation with action] + +--- + +## Pillar 6: Change Capacity + +**Score: [X] / 5** + +### Current State + +[2-3 paragraphs on firm's ability to adopt new tools and processes: history, training, role clarity, executive support.] + +### Change Readiness Indicators + +| Indicator | Assessment | +|-----------|------------| +| Recent change history | [Success/Mixed/Failed/None] | +| Training infrastructure | [None/Ad-hoc/Formal] | +| Role clarity | [Unclear/Defined/Accountable] | +| Executive sponsorship | [Skeptical/Interested/Active] | +| Staff appetite | [Resistant/Cautious/Eager] | + +### Key Stakeholders + +| Role | Name | Stance | Influence | +|------|------|--------|-----------| +| Decision Maker | [Name] | [Champion/Neutral/Skeptic] | High | +| Operations Lead | [Name] | [Champion/Neutral/Skeptic] | Medium | +| Key User | [Name] | [Champion/Neutral/Skeptic] | Medium | + +### Recommendations + +1. [Specific recommendation with action] +2. [Specific recommendation with action] + +--- + +## Use-Case Portfolio + +### Recommended AI Opportunities + +| Rank | Use Case | Feasibility | Impact | Risk | Timeline | +|------|----------|-------------|--------|------|----------| +| 1 | [Use case] | [H/M/L] | [H/M/L] | [H/M/L] | [30/60/90 days] | +| 2 | [Use case] | [H/M/L] | [H/M/L] | [H/M/L] | [30/60/90 days] | +| 3 | [Use case] | [H/M/L] | [H/M/L] | [H/M/L] | [30/60/90 days] | +| 4 | [Use case] | [H/M/L] | [H/M/L] | [H/M/L] | [30/60/90 days] | +| 5 | [Use case] | [H/M/L] | [H/M/L] | [H/M/L] | [30/60/90 days] | + +### Combined ROI Projection + +| Metric | Year 1 Estimate | +|--------|-----------------| +| Hours saved (annual) | [X] hours | +| Value at staff rate | $[X] | +| Value at billable rate | $[X] | +| Implementation investment | $[X] | +| Net value | $[X] | +| Payback period | [X] months | + +*See Use-Case One-Pagers for detailed breakdown.* + +--- + +## 30/60/90 Day Roadmap + +### Days 1-30: Foundation + +**Objective:** [One-sentence goal] + +| Task | Owner | Deliverable | +|------|-------|-------------| +| [Task 1] | [Role] | [Output] | +| [Task 2] | [Role] | [Output] | +| [Task 3] | [Role] | [Output] | + +**Success Criteria:** [How you know it's done] + +### Days 31-60: Build + +**Objective:** [One-sentence goal] + +| Task | Owner | Deliverable | +|------|-------|-------------| +| [Task 1] | [Role] | [Output] | +| [Task 2] | [Role] | [Output] | +| [Task 3] | [Role] | [Output] | + +**Success Criteria:** [How you know it's done] + +### Days 61-90: Activate + +**Objective:** [One-sentence goal] + +| Task | Owner | Deliverable | +|------|-------|-------------| +| [Task 1] | [Role] | [Output] | +| [Task 2] | [Role] | [Output] | +| [Task 3] | [Role] | [Output] | + +**Success Criteria:** [How you know it's done] + +--- + +## Governance Starter Kit Summary + +### Included Documents + +1. **AI Acceptable Use Policy** - Defines approved and prohibited AI uses +2. **Access & Permissions Model** - Role-based access controls +3. **Human-in-the-Loop Rules** - Escalation triggers and exception handling +4. **Retention & Logging Requirements** - Audit trail specifications + +### Implementation Priority + +| Document | Priority | Effort | Timeline | +|----------|----------|--------|----------| +| AI Acceptable Use Policy | Critical | Low | Week 1 | +| Access & Permissions | High | Medium | Week 2-3 | +| Human-in-the-Loop Rules | High | Low | Week 2 | +| Retention & Logging | Medium | Medium | Week 3-4 | + +--- + +## Next Steps + +### Option A: Self-Implementation + +Use this scorecard and the accompanying governance kit to drive your own AI readiness improvements. Recommended if you have internal operations capacity. + +### Option B: Implementation Sprint + +BizDeedz can execute the 30-day roadmap items in a 2-week sprint. Fixed scope, fixed fee. + +**Sprint 1 typically includes:** +- Data taxonomy standardization +- Intake routing automation +- Document automation foundation +- KPI dashboard setup + +**Investment:** $7,500 + +### Option C: Full Engagement + +Scorecard + Implementation Sprints + Ongoing Optimization Retainer + +**Monthly retainer includes:** +- KPI monitoring +- Automation health checks +- Backlog grooming +- Quarterly governance refresh + +**Investment:** $2,500/month (3-month minimum) + +--- + +## Appendix + +### A. Interview Summary +[Key quotes and observations from interviews] + +### B. Data Quality Details +[Full profiling output] + +### C. Systems Architecture Diagram +[Current state diagram] + +### D. Assumptions & Limitations +[What this assessment does and does not cover] + +--- + +*Assessment conducted by BizDeedz, Inc.* +*For questions: [CONTACT EMAIL]* diff --git a/BizDeedz/Offers/templates/Pre-Call-Questionnaire.md b/BizDeedz/Offers/templates/Pre-Call-Questionnaire.md new file mode 100644 index 0000000..6273ae4 --- /dev/null +++ b/BizDeedz/Offers/templates/Pre-Call-Questionnaire.md @@ -0,0 +1,120 @@ +# Pre-Call Snapshot Questionnaire + +*Please complete before our discovery call. Takes 5-10 minutes.* + +--- + +## Your Firm + +**Firm Name:** _______________ + +**Primary Practice Area(s):** (select all that apply) +- [ ] Bankruptcy +- [ ] Family Law +- [ ] Estate Planning / Probate +- [ ] Personal Injury +- [ ] Civil Litigation +- [ ] Criminal Defense +- [ ] Immigration +- [ ] Real Estate +- [ ] Other: _______________ + +**Number of Attorneys:** ___ + +**Number of Support Staff:** +- Paralegals: ___ +- Intake/Reception: ___ +- Administrative: ___ + +--- + +## Your Technology + +**Practice Management Software:** +- [ ] Clio +- [ ] MyCase +- [ ] PracticePanther +- [ ] Smokeball +- [ ] Filevine +- [ ] CosmoLex +- [ ] None +- [ ] Other: _______________ + +**Document Management:** +- [ ] NetDocuments +- [ ] iManage +- [ ] Google Drive +- [ ] Dropbox +- [ ] OneDrive/SharePoint +- [ ] Local server +- [ ] None +- [ ] Other: _______________ + +**Other Key Tools:** (e.g., e-sign, billing, intake forms) +_______________________________________________ + +--- + +## Your Pain Points + +**Top 2 Operational Challenges:** (select exactly 2) +- [ ] Intake takes too long or drops leads +- [ ] Drafting is slow and inconsistent +- [ ] Missed deadlines or filing errors +- [ ] Can't find documents or data +- [ ] Client communication gaps +- [ ] Too much rework and corrections +- [ ] Reporting/visibility is poor +- [ ] Other: _______________ + +**How would you describe your current operations?** +- [ ] Chaotic—different every time +- [ ] Informal—we have ways of doing things but nothing written +- [ ] Defined—we have SOPs but don't always follow them +- [ ] Consistent—we follow our processes most of the time +- [ ] Optimized—we measure and continuously improve + +--- + +## Your AI Experience + +**Have you tried AI tools before?** +- [ ] No +- [ ] Yes, briefly +- [ ] Yes, ongoing use + +**If yes, what tools?** _______________ + +**What happened?** (select all that apply) +- [ ] Worked well, want to expand +- [ ] Useful but limited +- [ ] Didn't stick—adoption failed +- [ ] Concerns about accuracy +- [ ] Concerns about confidentiality +- [ ] Not applicable + +--- + +## Your Goals + +**What does success look like in 90 days?** +_______________________________________________ +_______________________________________________ + +**Who is the decision-maker for this engagement?** + +Name: _______________ +Title: _______________ +Email: _______________ + +--- + +## Anything Else? + +**What should we know before our call?** +_______________________________________________ +_______________________________________________ + +--- + +*Thank you! We'll review this before our call to make the most of our time together.* diff --git a/BizDeedz/Offers/templates/Use-Case-ROI-Calculator.md b/BizDeedz/Offers/templates/Use-Case-ROI-Calculator.md new file mode 100644 index 0000000..d5d9b39 --- /dev/null +++ b/BizDeedz/Offers/templates/Use-Case-ROI-Calculator.md @@ -0,0 +1,243 @@ +# Use-Case ROI Calculator + +**Client:** [FIRM NAME] +**Use Case:** [USE CASE NAME] +**Date:** [DATE] + +--- + +## Use Case Summary + +**Problem Statement:** +[What pain does this solve? 2-3 sentences on current state.] + +**Proposed Solution:** +[What will automation do? 2-3 sentences on future state.] + +--- + +## Volume Analysis + +| Metric | Value | Source | +|--------|-------|--------| +| Occurrences per week | [X] | [How calculated] | +| Occurrences per month | [X] | [Weekly × 4.3] | +| Occurrences per year | [X] | [Monthly × 12] | + +--- + +## Time Savings + +### Current State + +| Step | Time per Occurrence | Performed By | +|------|---------------------|--------------| +| [Step 1] | [X] min | [Role] | +| [Step 2] | [X] min | [Role] | +| [Step 3] | [X] min | [Role] | +| [Step 4] | [X] min | [Role] | +| **Total** | **[X] min** | | + +### Future State (With Automation) + +| Step | Time per Occurrence | Performed By | +|------|---------------------|--------------| +| [Step 1] | [X] min | [Auto/Role] | +| [Step 2] | [X] min | [Auto/Role] | +| [Step 3] | [X] min | [Auto/Role] | +| [Step 4] | [X] min | [Auto/Role] | +| **Total** | **[X] min** | | + +### Time Saved + +| Metric | Calculation | Value | +|--------|-------------|-------| +| Time saved per occurrence | [Current - Future] | [X] min | +| Weekly time saved | [Per occurrence × Weekly volume] | [X] min | +| Monthly time saved | [Weekly × 4.3] | [X] hours | +| Annual time saved | [Monthly × 12] | [X] hours | + +--- + +## Error Reduction + +### Current Error Profile + +| Error Type | Frequency | Rework Time | Impact | +|------------|-----------|-------------|--------| +| [Error 1] | [X]/month | [X] min each | [Describe] | +| [Error 2] | [X]/month | [X] min each | [Describe] | +| [Error 3] | [X]/month | [X] min each | [Describe] | + +### Projected Error Reduction + +| Error Type | Current | Projected | Reduction | +|------------|---------|-----------|-----------| +| [Error 1] | [X]/month | [X]/month | [X]% | +| [Error 2] | [X]/month | [X]/month | [X]% | +| [Error 3] | [X]/month | [X]/month | [X]% | + +### Rework Time Saved + +| Metric | Calculation | Value | +|--------|-------------|-------| +| Current monthly rework | [Errors × Rework time] | [X] hours | +| Projected monthly rework | [Reduced errors × Rework time] | [X] hours | +| Monthly rework saved | [Current - Projected] | [X] hours | +| Annual rework saved | [Monthly × 12] | [X] hours | + +--- + +## Financial Impact + +### Labor Cost Assumptions + +| Role | Hourly Cost | Billable Rate | +|------|-------------|---------------| +| Partner | $[X] | $[X] | +| Associate | $[X] | $[X] | +| Paralegal | $[X] | $[X] | +| Admin/Intake | $[X] | N/A | + +*Hourly cost = fully loaded (salary + benefits + overhead)* + +### Direct Labor Savings + +| Metric | Hours | × Rate | Value | +|--------|-------|--------|-------| +| Annual time saved | [X] | $[X] | $[X] | +| Annual rework saved | [X] | $[X] | $[X] | +| **Total labor savings** | **[X]** | | **$[X]** | + +### Capacity Unlocked + +| Metric | Calculation | Value | +|--------|-------------|-------| +| Hours freed annually | [Total hours saved] | [X] hours | +| If redirected to billable work | [Hours × Billable rate × Utilization %] | $[X] | +| If used to handle more volume | [Hours ÷ Time per matter × Avg matter value] | $[X] | + +### Revenue Protection / Acceleration + +| Impact | Assumption | Annual Value | +|--------|------------|--------------| +| Faster intake → Higher conversion | [X]% improvement × [X] leads × $[X] avg | $[X] | +| Fewer missed deadlines → Fewer write-offs | [X]% reduction × $[X] at-risk | $[X] | +| Faster cycle time → Faster collection | [X] days faster × $[X] avg AR | $[X] | + +--- + +## Implementation Cost + +### One-Time Costs + +| Item | Cost | +|------|------| +| BizDeedz implementation sprint | $[X] | +| Client staff time (implementation) | [X] hours × $[X] = $[X] | +| Tool/license costs (if any) | $[X] | +| **Total one-time** | **$[X]** | + +### Ongoing Costs + +| Item | Monthly | Annual | +|------|---------|--------| +| Tool/license fees | $[X] | $[X] | +| Maintenance/monitoring | $[X] | $[X] | +| **Total ongoing** | **$[X]** | **$[X]** | + +--- + +## ROI Summary + +### Conservative Estimate (Labor Savings Only) + +| Metric | Value | +|--------|-------| +| Annual benefit | $[X] | +| Year 1 cost (one-time + ongoing) | $[X] | +| Year 1 net value | $[X] | +| Payback period | [X] months | +| 3-year ROI | [X]% | + +### Moderate Estimate (Labor + Capacity) + +| Metric | Value | +|--------|-------| +| Annual benefit | $[X] | +| Year 1 cost | $[X] | +| Year 1 net value | $[X] | +| Payback period | [X] months | +| 3-year ROI | [X]% | + +### Optimistic Estimate (Labor + Capacity + Revenue) + +| Metric | Value | +|--------|-------| +| Annual benefit | $[X] | +| Year 1 cost | $[X] | +| Year 1 net value | $[X] | +| Payback period | [X] months | +| 3-year ROI | [X]% | + +--- + +## Sensitivity Analysis + +### If volume is 25% lower than estimated: + +| Metric | Original | Adjusted | +|--------|----------|----------| +| Annual time saved | [X] hours | [X] hours | +| Annual value | $[X] | $[X] | +| Payback period | [X] months | [X] months | + +### If implementation takes 50% longer: + +| Metric | Original | Adjusted | +|--------|----------|----------| +| Implementation cost | $[X] | $[X] | +| Year 1 net value | $[X] | $[X] | +| Payback period | [X] months | [X] months | + +--- + +## Risk Factors + +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|------------| +| Lower volume than estimated | [H/M/L] | [H/M/L] | Validate with 3-month data | +| Staff adoption issues | [H/M/L] | [H/M/L] | Training + change mgmt | +| Technical integration issues | [H/M/L] | [H/M/L] | Prototype first | +| Process exceptions require workarounds | [H/M/L] | [H/M/L] | Document exceptions upfront | + +--- + +## Recommendation + +**Proceed?** [Yes / Yes with conditions / No] + +**Confidence Level:** [High / Medium / Low] + +**Rationale:** +[2-3 sentences summarizing why this use case is or isn't worth pursuing] + +**Conditions (if any):** +- [Condition 1] +- [Condition 2] + +--- + +## Assumptions Log + +| Assumption | Value | Source | Sensitivity | +|------------|-------|--------|-------------| +| Weekly volume | [X] | [Source] | [High/Med/Low] | +| Time per occurrence | [X] min | [Source] | [High/Med/Low] | +| Error rate | [X]% | [Source] | [High/Med/Low] | +| Staff hourly cost | $[X] | [Source] | [Low] | +| Billable rate | $[X] | [Source] | [Low] | + +--- + +*Calculator prepared by BizDeedz, Inc.* From 100f38fcdba64b8afa7d2681e52cf66732152788 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Feb 2026 13:24:26 +0000 Subject: [PATCH 2/7] Add AI Readiness Accelerator React app scaffolding - Project config: Vite, TypeScript, Tailwind, Recharts - Types: firm, assessment, results, ROI - Constants: 6 pillars with questions, scoring thresholds, roadmap templates - Services: Gemini API (structured JSON), scoring calculations - UI primitives: Button, Card, Input, Select, Slider, Badge, ProgressBar Work in progress - components being built by parallel agents. https://claude.ai/code/session_019DXrMJ4k9ujmA3BDgUNzHn --- ai-readiness-accelerator/.env.example | 1 + ai-readiness-accelerator/.gitignore | 35 ++ ai-readiness-accelerator/index.html | 17 + ai-readiness-accelerator/package.json | 33 ++ ai-readiness-accelerator/postcss.config.js | 6 + .../src/components/ui/Badge.tsx | 55 ++ .../src/components/ui/Button.tsx | 96 ++++ .../src/components/ui/Card.tsx | 44 ++ .../src/components/ui/Input.tsx | 114 +++++ .../src/components/ui/LoadingSpinner.tsx | 42 ++ .../src/components/ui/ProgressBar.tsx | 75 +++ .../src/components/ui/Select.tsx | 143 ++++++ .../src/components/ui/Slider.tsx | 126 +++++ .../src/components/ui/index.ts | 9 + .../src/constants/index.ts | 76 +++ .../src/constants/pillars.ts | 255 ++++++++++ .../src/constants/roadmap-templates.ts | 474 ++++++++++++++++++ .../src/constants/scoring.ts | 203 ++++++++ ai-readiness-accelerator/src/index.css | 154 ++++++ ai-readiness-accelerator/src/main.tsx | 10 + .../src/services/gemini.service.ts | 454 +++++++++++++++++ .../src/services/scoring.service.ts | 291 +++++++++++ .../src/types/assessment.types.ts | 179 +++++++ .../src/types/firm.types.ts | 137 +++++ ai-readiness-accelerator/src/types/index.ts | 143 ++++++ .../src/types/results.types.ts | 308 ++++++++++++ .../src/types/roi.types.ts | 334 ++++++++++++ ai-readiness-accelerator/tailwind.config.js | 30 ++ ai-readiness-accelerator/tsconfig.json | 25 + ai-readiness-accelerator/tsconfig.node.json | 11 + ai-readiness-accelerator/vite.config.ts | 10 + 31 files changed, 3890 insertions(+) create mode 100644 ai-readiness-accelerator/.env.example create mode 100644 ai-readiness-accelerator/.gitignore create mode 100644 ai-readiness-accelerator/index.html create mode 100644 ai-readiness-accelerator/package.json create mode 100644 ai-readiness-accelerator/postcss.config.js create mode 100644 ai-readiness-accelerator/src/components/ui/Badge.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/Button.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/Card.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/Input.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/LoadingSpinner.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/ProgressBar.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/Select.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/Slider.tsx create mode 100644 ai-readiness-accelerator/src/components/ui/index.ts create mode 100644 ai-readiness-accelerator/src/constants/index.ts create mode 100644 ai-readiness-accelerator/src/constants/pillars.ts create mode 100644 ai-readiness-accelerator/src/constants/roadmap-templates.ts create mode 100644 ai-readiness-accelerator/src/constants/scoring.ts create mode 100644 ai-readiness-accelerator/src/index.css create mode 100644 ai-readiness-accelerator/src/main.tsx create mode 100644 ai-readiness-accelerator/src/services/gemini.service.ts create mode 100644 ai-readiness-accelerator/src/services/scoring.service.ts create mode 100644 ai-readiness-accelerator/src/types/assessment.types.ts create mode 100644 ai-readiness-accelerator/src/types/firm.types.ts create mode 100644 ai-readiness-accelerator/src/types/index.ts create mode 100644 ai-readiness-accelerator/src/types/results.types.ts create mode 100644 ai-readiness-accelerator/src/types/roi.types.ts create mode 100644 ai-readiness-accelerator/tailwind.config.js create mode 100644 ai-readiness-accelerator/tsconfig.json create mode 100644 ai-readiness-accelerator/tsconfig.node.json create mode 100644 ai-readiness-accelerator/vite.config.ts diff --git a/ai-readiness-accelerator/.env.example b/ai-readiness-accelerator/.env.example new file mode 100644 index 0000000..6345af2 --- /dev/null +++ b/ai-readiness-accelerator/.env.example @@ -0,0 +1 @@ +VITE_GEMINI_API_KEY=your_gemini_api_key_here diff --git a/ai-readiness-accelerator/.gitignore b/ai-readiness-accelerator/.gitignore new file mode 100644 index 0000000..77bdac0 --- /dev/null +++ b/ai-readiness-accelerator/.gitignore @@ -0,0 +1,35 @@ +# Dependencies +node_modules +.pnp +.pnp.js + +# Build +dist +dist-ssr +*.local + +# Environment +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Editor +.vscode/* +!.vscode/extensions.json +.idea +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Testing +coverage diff --git a/ai-readiness-accelerator/index.html b/ai-readiness-accelerator/index.html new file mode 100644 index 0000000..fa93dd3 --- /dev/null +++ b/ai-readiness-accelerator/index.html @@ -0,0 +1,17 @@ + + + + + + + + AI Readiness Accelerator | BizDeedz + + + + + +
+ + + diff --git a/ai-readiness-accelerator/package.json b/ai-readiness-accelerator/package.json new file mode 100644 index 0000000..785fdc6 --- /dev/null +++ b/ai-readiness-accelerator/package.json @@ -0,0 +1,33 @@ +{ + "name": "ai-readiness-accelerator", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0" + }, + "dependencies": { + "lucide-react": "^0.344.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "recharts": "^2.12.0" + }, + "devDependencies": { + "@types/react": "^18.2.55", + "@types/react-dom": "^18.2.19", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.17", + "eslint": "^8.56.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "typescript": "^5.3.3", + "vite": "^5.1.0" + } +} diff --git a/ai-readiness-accelerator/postcss.config.js b/ai-readiness-accelerator/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/ai-readiness-accelerator/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/ai-readiness-accelerator/src/components/ui/Badge.tsx b/ai-readiness-accelerator/src/components/ui/Badge.tsx new file mode 100644 index 0000000..95125b7 --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/Badge.tsx @@ -0,0 +1,55 @@ +import React from 'react'; + +export interface BadgeProps { + /** Visual style variant */ + variant?: 'success' | 'warning' | 'error' | 'info' | 'neutral'; + /** Size of the badge */ + size?: 'sm' | 'md' | 'lg'; + /** Badge content */ + children: React.ReactNode; + /** Additional CSS classes */ + className?: string; +} + +const variantClasses: Record, string> = { + success: 'bg-green-100 text-green-800 border-green-200', + warning: 'bg-yellow-100 text-yellow-800 border-yellow-200', + error: 'bg-red-100 text-red-800 border-red-200', + info: 'bg-blue-100 text-blue-800 border-blue-200', + neutral: 'bg-gray-100 text-gray-800 border-gray-200', +}; + +const sizeClasses: Record, string> = { + sm: 'px-2 py-0.5 text-xs', + md: 'px-2.5 py-1 text-sm', + lg: 'px-3 py-1.5 text-base', +}; + +/** + * Badge component for displaying status, labels, or tags. + * Supports multiple color variants and sizes. + */ +export const Badge: React.FC = ({ + variant = 'neutral', + size = 'md', + children, + className = '', +}) => { + return ( + + {children} + + ); +}; + +export default Badge; diff --git a/ai-readiness-accelerator/src/components/ui/Button.tsx b/ai-readiness-accelerator/src/components/ui/Button.tsx new file mode 100644 index 0000000..e6e26cb --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/Button.tsx @@ -0,0 +1,96 @@ +import React, { forwardRef } from 'react'; +import { LoadingSpinner } from './LoadingSpinner'; + +export interface ButtonProps extends React.ButtonHTMLAttributes { + /** Visual style variant */ + variant?: 'primary' | 'secondary' | 'ghost'; + /** Size of the button */ + size?: 'sm' | 'md' | 'lg'; + /** Whether the button is in a loading state */ + loading?: boolean; + /** Button content */ + children: React.ReactNode; +} + +const variantClasses: Record, string> = { + primary: ` + bg-primary-600 text-white + hover:bg-primary-700 + focus:ring-primary-500 + disabled:bg-primary-300 + `, + secondary: ` + bg-white text-primary-700 + border border-primary-300 + hover:bg-primary-50 + focus:ring-primary-500 + disabled:bg-gray-100 disabled:text-gray-400 disabled:border-gray-200 + `, + ghost: ` + bg-transparent text-primary-600 + hover:bg-primary-50 + focus:ring-primary-500 + disabled:text-gray-400 disabled:hover:bg-transparent + `, +}; + +const sizeClasses: Record, string> = { + sm: 'px-3 py-1.5 text-sm', + md: 'px-4 py-2 text-base', + lg: 'px-6 py-3 text-lg', +}; + +/** + * Button component with multiple variants, sizes, and loading state support. + * Uses forwardRef for proper ref forwarding to the underlying button element. + */ +export const Button = forwardRef( + ( + { + variant = 'primary', + size = 'md', + loading = false, + disabled = false, + children, + className = '', + type = 'button', + ...props + }, + ref + ) => { + const isDisabled = disabled || loading; + + return ( + + ); + } +); + +Button.displayName = 'Button'; + +export default Button; diff --git a/ai-readiness-accelerator/src/components/ui/Card.tsx b/ai-readiness-accelerator/src/components/ui/Card.tsx new file mode 100644 index 0000000..a4b6e77 --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/Card.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +export interface CardProps { + /** Card content */ + children: React.ReactNode; + /** Additional CSS classes */ + className?: string; + /** Padding size */ + padding?: 'none' | 'sm' | 'md' | 'lg'; +} + +const paddingClasses: Record, string> = { + none: 'p-0', + sm: 'p-3', + md: 'p-4 sm:p-6', + lg: 'p-6 sm:p-8', +}; + +/** + * Card component provides a clean container with shadow and border. + * Useful for grouping related content together. + */ +export const Card: React.FC = ({ + children, + className = '', + padding = 'md', +}) => { + return ( +
+ {children} +
+ ); +}; + +export default Card; diff --git a/ai-readiness-accelerator/src/components/ui/Input.tsx b/ai-readiness-accelerator/src/components/ui/Input.tsx new file mode 100644 index 0000000..a8698e0 --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/Input.tsx @@ -0,0 +1,114 @@ +import React, { forwardRef, useId } from 'react'; +import { AlertCircle } from 'lucide-react'; + +export interface InputProps extends Omit, 'id'> { + /** Label text for the input */ + label?: string; + /** Error message to display */ + error?: string; + /** Help text displayed below the input */ + helpText?: string; + /** Custom ID (auto-generated if not provided) */ + id?: string; +} + +/** + * Input component with label, error, and help text support. + * Properly associates labels with inputs for accessibility. + */ +export const Input = forwardRef( + ( + { + label, + error, + helpText, + id: customId, + className = '', + required, + ...props + }, + ref + ) => { + const generatedId = useId(); + const inputId = customId || generatedId; + const errorId = `${inputId}-error`; + const helpTextId = `${inputId}-help`; + + const hasError = Boolean(error); + const hasHelpText = Boolean(helpText); + + // Build aria-describedby based on what's present + const describedByIds: string[] = []; + if (hasError) describedByIds.push(errorId); + if (hasHelpText) describedByIds.push(helpTextId); + const ariaDescribedBy = describedByIds.length > 0 ? describedByIds.join(' ') : undefined; + + return ( +
+ {label && ( + + )} +
+ + {hasError && ( +
+
+ )} +
+ {hasError && ( + + )} + {hasHelpText && !hasError && ( +

+ {helpText} +

+ )} +
+ ); + } +); + +Input.displayName = 'Input'; + +export default Input; diff --git a/ai-readiness-accelerator/src/components/ui/LoadingSpinner.tsx b/ai-readiness-accelerator/src/components/ui/LoadingSpinner.tsx new file mode 100644 index 0000000..105761e --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/LoadingSpinner.tsx @@ -0,0 +1,42 @@ +import React from 'react'; + +export interface LoadingSpinnerProps { + /** Size of the spinner */ + size?: 'sm' | 'md' | 'lg'; + /** Additional CSS classes */ + className?: string; +} + +const sizeClasses: Record, string> = { + sm: 'w-4 h-4 border-2', + md: 'w-6 h-6 border-2', + lg: 'w-8 h-8 border-3', +}; + +/** + * LoadingSpinner component displays an animated spinner for loading states. + * Includes proper accessibility attributes for screen readers. + */ +export const LoadingSpinner: React.FC = ({ + size = 'md', + className = '', +}) => { + return ( +
+ Loading... +
+ ); +}; + +export default LoadingSpinner; diff --git a/ai-readiness-accelerator/src/components/ui/ProgressBar.tsx b/ai-readiness-accelerator/src/components/ui/ProgressBar.tsx new file mode 100644 index 0000000..00ac494 --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/ProgressBar.tsx @@ -0,0 +1,75 @@ +import React from 'react'; + +export interface ProgressBarProps { + /** Progress value between 0 and 100 */ + value: number; + /** Optional label text */ + label?: string; + /** Whether to show the percentage value */ + showPercentage?: boolean; + /** Additional CSS classes for the container */ + className?: string; + /** Color variant based on progress */ + variant?: 'default' | 'success' | 'warning' | 'error'; +} + +const variantClasses: Record, string> = { + default: 'bg-primary-600', + success: 'bg-green-500', + warning: 'bg-yellow-500', + error: 'bg-red-500', +}; + +/** + * ProgressBar component displays progress with optional label and percentage. + * Includes proper accessibility attributes for screen readers. + */ +export const ProgressBar: React.FC = ({ + value, + label, + showPercentage = false, + className = '', + variant = 'default', +}) => { + // Clamp value between 0 and 100 + const clampedValue = Math.min(100, Math.max(0, value)); + const roundedValue = Math.round(clampedValue); + + return ( +
+ {(label || showPercentage) && ( +
+ {label && ( + + {label} + + )} + {showPercentage && ( + + {roundedValue}% + + )} +
+ )} +
+
+
+
+ ); +}; + +export default ProgressBar; diff --git a/ai-readiness-accelerator/src/components/ui/Select.tsx b/ai-readiness-accelerator/src/components/ui/Select.tsx new file mode 100644 index 0000000..fc40419 --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/Select.tsx @@ -0,0 +1,143 @@ +import React, { forwardRef, useId } from 'react'; +import { AlertCircle, ChevronDown } from 'lucide-react'; + +export interface SelectOption { + value: string; + label: string; +} + +export interface SelectProps extends Omit, 'id'> { + /** Label text for the select */ + label?: string; + /** Array of options to display */ + options: SelectOption[]; + /** Error message to display */ + error?: string; + /** Help text displayed below the select */ + helpText?: string; + /** Custom ID (auto-generated if not provided) */ + id?: string; + /** Placeholder text shown when no option is selected */ + placeholder?: string; +} + +/** + * Select component with label, options, error, and help text support. + * Supports both single and multiple selection modes. + */ +export const Select = forwardRef( + ( + { + label, + options, + error, + helpText, + id: customId, + className = '', + required, + placeholder, + multiple, + ...props + }, + ref + ) => { + const generatedId = useId(); + const selectId = customId || generatedId; + const errorId = `${selectId}-error`; + const helpTextId = `${selectId}-help`; + + const hasError = Boolean(error); + const hasHelpText = Boolean(helpText); + + // Build aria-describedby based on what's present + const describedByIds: string[] = []; + if (hasError) describedByIds.push(errorId); + if (hasHelpText) describedByIds.push(helpTextId); + const ariaDescribedBy = describedByIds.length > 0 ? describedByIds.join(' ') : undefined; + + return ( +
+ {label && ( + + )} +
+ + {!multiple && ( +
+ {hasError ? ( +
+ )} +
+ {hasError && ( + + )} + {hasHelpText && !hasError && ( +

+ {helpText} +

+ )} +
+ ); + } +); + +Select.displayName = 'Select'; + +export default Select; diff --git a/ai-readiness-accelerator/src/components/ui/Slider.tsx b/ai-readiness-accelerator/src/components/ui/Slider.tsx new file mode 100644 index 0000000..2643abc --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/Slider.tsx @@ -0,0 +1,126 @@ +import React, { forwardRef, useId } from 'react'; + +export interface SliderProps extends Omit, 'type' | 'id'> { + /** Label text for the slider */ + label?: string; + /** Minimum value */ + min?: number; + /** Maximum value */ + max?: number; + /** Step increment */ + step?: number; + /** Current value */ + value?: number; + /** Whether to show the current value */ + showValue?: boolean; + /** Custom function to format the displayed value */ + formatValue?: (value: number) => string; + /** Custom ID (auto-generated if not provided) */ + id?: string; +} + +/** + * Slider component with label and value display. + * Includes proper accessibility attributes for screen readers. + */ +export const Slider = forwardRef( + ( + { + label, + min = 0, + max = 100, + step = 1, + value = 0, + showValue = true, + formatValue, + id: customId, + className = '', + onChange, + ...props + }, + ref + ) => { + const generatedId = useId(); + const sliderId = customId || generatedId; + + const displayValue = formatValue ? formatValue(value) : String(value); + + // Calculate percentage for custom styling + const percentage = ((value - min) / (max - min)) * 100; + + return ( +
+ {(label || showValue) && ( +
+ {label && ( + + )} + {showValue && ( + + )} +
+ )} + +
+ ); + } +); + +Slider.displayName = 'Slider'; + +export default Slider; diff --git a/ai-readiness-accelerator/src/components/ui/index.ts b/ai-readiness-accelerator/src/components/ui/index.ts new file mode 100644 index 0000000..af8efd1 --- /dev/null +++ b/ai-readiness-accelerator/src/components/ui/index.ts @@ -0,0 +1,9 @@ +// UI Components +export { Button, type ButtonProps } from './Button'; +export { Card, type CardProps } from './Card'; +export { Input, type InputProps } from './Input'; +export { Select, type SelectProps, type SelectOption } from './Select'; +export { Slider, type SliderProps } from './Slider'; +export { ProgressBar, type ProgressBarProps } from './ProgressBar'; +export { Badge, type BadgeProps } from './Badge'; +export { LoadingSpinner, type LoadingSpinnerProps } from './LoadingSpinner'; diff --git a/ai-readiness-accelerator/src/constants/index.ts b/ai-readiness-accelerator/src/constants/index.ts new file mode 100644 index 0000000..9e32659 --- /dev/null +++ b/ai-readiness-accelerator/src/constants/index.ts @@ -0,0 +1,76 @@ +/** + * Constants for the AI Readiness Accelerator application + */ + +import type { PillarStatus, ReadinessLevel } from '../types'; + +/** + * Score thresholds for pillar status determination + * Boundary values are inclusive of the lower bound + */ +export const PILLAR_STATUS_THRESHOLDS: Record = { + 'critical': { min: 0, max: 1.5 }, + 'needs-work': { min: 1.5, max: 2.5 }, + 'adequate': { min: 2.5, max: 3.5 }, + 'strong': { min: 3.5, max: 4.5 }, + 'excellent': { min: 4.5, max: 5 }, +}; + +/** + * Score thresholds for overall readiness level determination + */ +export const READINESS_LEVEL_THRESHOLDS: Record = { + 'not-ready': { min: 0, max: 1.0 }, + 'foundational': { min: 1.1, max: 2.0 }, + 'developing': { min: 2.1, max: 3.0 }, + 'ready': { min: 3.1, max: 4.0 }, + 'optimized': { min: 4.1, max: 5.0 }, +}; + +/** + * Critical pillar IDs that are blockers for AI deployment + */ +export const CRITICAL_PILLAR_IDS = ['risk', 'data'] as const; + +/** + * Minimum score threshold to not be considered a blocker + */ +export const BLOCKER_SCORE_THRESHOLD = 3; + +/** + * Number of top/bottom pillars to identify as strengths/gaps + */ +export const STRENGTHS_GAPS_COUNT = 3; + +/** + * Human-readable labels for pillar statuses + */ +export const PILLAR_STATUS_LABELS: Record = { + 'critical': 'Critical', + 'needs-work': 'Needs Work', + 'adequate': 'Adequate', + 'strong': 'Strong', + 'excellent': 'Excellent', +}; + +/** + * Human-readable labels for readiness levels + */ +export const READINESS_LEVEL_LABELS: Record = { + 'not-ready': 'Not Ready', + 'foundational': 'Foundational', + 'developing': 'Developing', + 'ready': 'Ready', + 'optimized': 'Optimized', +}; + +/** + * Descriptions for each pillar status level + */ +export const PILLAR_STATUS_DESCRIPTIONS: Record = { + 'critical': 'requires immediate attention and significant improvement', + 'needs-work': 'needs focused development and enhancement', + 'adequate': 'meets basic requirements but has room for improvement', + 'strong': 'demonstrates solid capabilities with minor refinements needed', + 'excellent': 'is a key competitive advantage and industry-leading', +}; diff --git a/ai-readiness-accelerator/src/constants/pillars.ts b/ai-readiness-accelerator/src/constants/pillars.ts new file mode 100644 index 0000000..3863854 --- /dev/null +++ b/ai-readiness-accelerator/src/constants/pillars.ts @@ -0,0 +1,255 @@ +/** + * Pillar definitions and assessment questions for the AI Readiness Accelerator + * + * These pillars form the core assessment framework for evaluating law firm + * readiness for AI adoption and automation initiatives. + */ + +import type { PillarDefinition } from '../types'; + +/** + * Lucide icon name type for pillar visualization + */ +export type PillarIcon = 'Workflow' | 'Database' | 'BookOpen' | 'Settings' | 'Shield' | 'TrendingUp'; + +/** + * Extended pillar definition including icon information + */ +export interface ExtendedPillarDefinition extends PillarDefinition { + /** Lucide icon name for visual representation */ + icon: PillarIcon; +} + +/** + * Array of all assessment pillar definitions with their questions. + * Each pillar represents a critical dimension of AI readiness for law firms. + */ +export const PILLAR_DEFINITIONS: ExtendedPillarDefinition[] = [ + { + id: 'process', + name: 'Process Maturity', + description: 'Evaluates the consistency and documentation of core legal workflows, from client intake through case resolution.', + icon: 'Workflow', + questions: [ + { + id: 'process-1', + text: 'How standardized is your client intake process across all practice areas?', + category: 'intake', + }, + { + id: 'process-2', + text: 'Do you have documented, repeatable procedures for case setup and matter opening?', + category: 'case-setup', + }, + { + id: 'process-3', + text: 'How consistently do attorneys follow established drafting workflows for common document types?', + category: 'drafting', + }, + { + id: 'process-4', + text: 'Are your court filing and service procedures standardized with clear checklists?', + category: 'filing', + }, + { + id: 'process-5', + text: 'Do you have systematic follow-up procedures after filings, hearings, and case milestones?', + category: 'follow-up', + }, + ], + }, + { + id: 'data', + name: 'Data Quality', + description: 'Assesses the cleanliness, consistency, and completeness of data across practice management and document systems.', + icon: 'Database', + questions: [ + { + id: 'data-1', + text: 'How consistent are required fields populated across your matter database (client name, matter type, responsible attorney)?', + category: 'field-consistency', + }, + { + id: 'data-2', + text: 'What is your estimated rate of duplicate contacts, matters, or documents in your systems?', + category: 'duplicates', + }, + { + id: 'data-3', + text: 'Do you enforce standardized naming conventions for documents, folders, and matter descriptions?', + category: 'naming-conventions', + }, + { + id: 'data-4', + text: 'How complete is critical case information (key dates, opposing counsel, judge assignments) in your matters?', + category: 'completeness', + }, + { + id: 'data-5', + text: 'Do you use standardized practice area codes, matter types, and document taxonomies firm-wide?', + category: 'taxonomy', + }, + ], + }, + { + id: 'knowledge', + name: 'Knowledge System', + description: 'Measures the organization, accessibility, and currency of institutional knowledge including templates, SOPs, and training materials.', + icon: 'BookOpen', + questions: [ + { + id: 'knowledge-1', + text: 'Can staff easily locate the correct, approved template for any standard document type?', + category: 'templates', + }, + { + id: 'knowledge-2', + text: 'Are standard operating procedures documented and accessible for key firm processes?', + category: 'sops', + }, + { + id: 'knowledge-3', + text: 'How current are your practice area playbooks and procedural guides?', + category: 'playbooks', + }, + { + id: 'knowledge-4', + text: 'Do staff have easy access to FAQs and quick-reference guides for common questions?', + category: 'faqs', + }, + { + id: 'knowledge-5', + text: 'Is there a structured onboarding curriculum with documented training materials for new hires?', + category: 'training', + }, + ], + }, + { + id: 'tooling', + name: 'Tooling & Integrations', + description: 'Evaluates the adoption, integration, and effective use of legal technology across the firm.', + icon: 'Settings', + questions: [ + { + id: 'tooling-1', + text: 'What percentage of firm workflows actively utilize your practice management system?', + category: 'practice-management', + }, + { + id: 'tooling-2', + text: 'Is your document management system consistently used for all client-related documents?', + category: 'document-management', + }, + { + id: 'tooling-3', + text: 'Are emails automatically or routinely captured and linked to relevant matters?', + category: 'email-integration', + }, + { + id: 'tooling-4', + text: 'How integrated is your billing system with time tracking and matter management?', + category: 'billing', + }, + { + id: 'tooling-5', + text: 'Do you currently use any automation tools (document assembly, workflow automation, e-signatures)?', + category: 'automation', + }, + ], + }, + { + id: 'risk', + name: 'Risk & Governance', + description: 'Examines security controls, compliance frameworks, and governance structures essential for responsible AI deployment.', + icon: 'Shield', + questions: [ + { + id: 'risk-1', + text: 'Do you have role-based access controls limiting who can view sensitive client data?', + category: 'access-controls', + }, + { + id: 'risk-2', + text: 'Has your firm established a formal policy governing the use of AI tools with client data?', + category: 'ai-policy', + }, + { + id: 'risk-3', + text: 'Can you produce audit trails showing who accessed or modified matter information?', + category: 'audit-trails', + }, + { + id: 'risk-4', + text: 'Are data retention and destruction policies documented and consistently enforced?', + category: 'retention', + }, + { + id: 'risk-5', + text: 'Do all staff receive regular training on confidentiality obligations and data handling?', + category: 'confidentiality-training', + }, + ], + }, + { + id: 'change', + name: 'Change Capacity', + description: 'Assesses organizational readiness for change, including training infrastructure, leadership support, and staff adaptability.', + icon: 'TrendingUp', + questions: [ + { + id: 'change-1', + text: 'Does your firm have dedicated resources or infrastructure for delivering technology training?', + category: 'training-infrastructure', + }, + { + id: 'change-2', + text: 'How would you rate your firm\'s track record of successfully adopting new technology in the past 3 years?', + category: 'adoption-track-record', + }, + { + id: 'change-3', + text: 'Is there clear ownership and accountability for technology initiatives at your firm?', + category: 'role-clarity', + }, + { + id: 'change-4', + text: 'Do firm leadership actively champion and participate in technology adoption efforts?', + category: 'executive-sponsorship', + }, + { + id: 'change-5', + text: 'How receptive is your staff generally to learning and using new tools and processes?', + category: 'staff-appetite', + }, + ], + }, +]; + +/** + * Mapping of pillar IDs to their icon names for easy lookup + */ +export const PILLAR_ICONS: Record = { + process: 'Workflow', + data: 'Database', + knowledge: 'BookOpen', + tooling: 'Settings', + risk: 'Shield', + change: 'TrendingUp', +}; + +/** + * Total number of questions across all pillars + */ +export const TOTAL_QUESTIONS = PILLAR_DEFINITIONS.reduce( + (sum, pillar) => sum + (pillar.questions?.length || 0), + 0 +); + +/** + * Helper to get a pillar definition by ID + * @param id - The pillar ID to look up + * @returns The pillar definition or undefined if not found + */ +export function getPillarById(id: string): ExtendedPillarDefinition | undefined { + return PILLAR_DEFINITIONS.find(pillar => pillar.id === id); +} diff --git a/ai-readiness-accelerator/src/constants/roadmap-templates.ts b/ai-readiness-accelerator/src/constants/roadmap-templates.ts new file mode 100644 index 0000000..eafbe94 --- /dev/null +++ b/ai-readiness-accelerator/src/constants/roadmap-templates.ts @@ -0,0 +1,474 @@ +/** + * Roadmap task templates for the AI Readiness Accelerator + * + * Tasks are organized into 30/60/90 day phases and are conditionally + * included based on assessment scores. Lower scores in specific pillars + * trigger relevant remediation tasks. + */ + +/** + * Pillar IDs for type safety + */ +export type PillarId = 'process' | 'data' | 'knowledge' | 'tooling' | 'risk' | 'change'; + +/** + * Scores mapped by pillar ID + */ +export type PillarScores = Record; + +/** + * Task priority levels + */ +export type TaskPriority = 'critical' | 'high' | 'medium' | 'low'; + +/** + * Roadmap task definition + */ +export interface RoadmapTask { + /** Unique task identifier */ + id: string; + /** Task title */ + title: string; + /** Detailed task description */ + description: string; + /** Responsible party or role */ + owner: string; + /** Task priority level */ + priority: TaskPriority; + /** Function to determine if task applies based on scores */ + applicableWhen: (scores: PillarScores) => boolean; + /** Related pillar IDs for grouping and filtering */ + relatedPillars: PillarId[]; +} + +// ============================================================================ +// Phase 1: First 30 Days - Foundation & Quick Wins +// ============================================================================ + +/** + * Tasks for the first 30 days of the AI readiness roadmap. + * Focus: Critical gaps, governance basics, and quick wins. + */ +export const PHASE_30_TASKS: RoadmapTask[] = [ + // Risk & Governance Tasks + { + id: '30-risk-policy', + title: 'Establish AI Usage Policy', + description: 'Draft and implement a firm-wide policy governing the use of AI tools with client data, including approved tools, prohibited uses, and review requirements.', + owner: 'Managing Partner / IT Director', + priority: 'critical', + applicableWhen: (scores) => scores.risk < 3, + relatedPillars: ['risk'], + }, + { + id: '30-risk-access', + title: 'Audit Data Access Controls', + description: 'Review and document current access permissions across all systems. Identify and remediate inappropriate access to sensitive client data.', + owner: 'IT Director', + priority: 'critical', + applicableWhen: (scores) => scores.risk < 2.5, + relatedPillars: ['risk'], + }, + { + id: '30-risk-training', + title: 'Schedule Confidentiality Refresher Training', + description: 'Organize mandatory training sessions on data handling, confidentiality obligations, and the new AI usage policy for all staff.', + owner: 'HR / Compliance', + priority: 'high', + applicableWhen: (scores) => scores.risk < 3.5, + relatedPillars: ['risk', 'change'], + }, + + // Data Quality Tasks + { + id: '30-data-audit', + title: 'Conduct Data Quality Assessment', + description: 'Sample 50 recent matters to assess field completion rates, naming convention adherence, and data accuracy. Document baseline metrics.', + owner: 'Operations Manager', + priority: 'high', + applicableWhen: (scores) => scores.data < 3, + relatedPillars: ['data'], + }, + { + id: '30-data-duplicates', + title: 'Identify and Merge Duplicate Records', + description: 'Run duplicate detection reports on contacts and matters. Establish a process for merging duplicates and preventing future occurrences.', + owner: 'Database Administrator', + priority: 'high', + applicableWhen: (scores) => scores.data < 2.5, + relatedPillars: ['data'], + }, + { + id: '30-data-naming', + title: 'Document Naming Convention Standards', + description: 'Create and distribute a firm-wide naming convention guide for documents, matters, and folders. Include examples for each practice area.', + owner: 'Knowledge Manager', + priority: 'medium', + applicableWhen: (scores) => scores.data < 3.5, + relatedPillars: ['data', 'knowledge'], + }, + + // Process Tasks + { + id: '30-process-intake', + title: 'Standardize Client Intake Form', + description: 'Create a unified intake form capturing all required information across practice areas. Implement in practice management system.', + owner: 'Practice Group Leaders', + priority: 'high', + applicableWhen: (scores) => scores.process < 3, + relatedPillars: ['process'], + }, + { + id: '30-process-checklist', + title: 'Create Matter Opening Checklist', + description: 'Document required steps for matter setup including conflict checks, engagement letters, and system setup. Make accessible to all staff.', + owner: 'Operations Manager', + priority: 'medium', + applicableWhen: (scores) => scores.process < 3.5, + relatedPillars: ['process', 'knowledge'], + }, + + // Change Capacity Tasks + { + id: '30-change-champion', + title: 'Identify AI Champions', + description: 'Select 2-3 tech-savvy individuals from different practice areas to serve as AI adoption champions and early feedback providers.', + owner: 'Managing Partner', + priority: 'high', + applicableWhen: (scores) => scores.change < 3.5, + relatedPillars: ['change'], + }, + { + id: '30-change-sponsor', + title: 'Secure Executive Sponsorship', + description: 'Brief firm leadership on AI initiative and obtain formal commitment to champion adoption, allocate resources, and model desired behaviors.', + owner: 'Project Lead', + priority: 'critical', + applicableWhen: (scores) => scores.change < 3, + relatedPillars: ['change'], + }, +]; + +// ============================================================================ +// Phase 2: Days 31-60 - Building Infrastructure +// ============================================================================ + +/** + * Tasks for days 31-60 of the AI readiness roadmap. + * Focus: Systems integration, knowledge organization, and process documentation. + */ +export const PHASE_60_TASKS: RoadmapTask[] = [ + // Tooling Tasks + { + id: '60-tooling-audit', + title: 'Complete Technology Stack Audit', + description: 'Document all current tools, their usage rates, integration points, and gaps. Identify redundancies and consolidation opportunities.', + owner: 'IT Director', + priority: 'high', + applicableWhen: (scores) => scores.tooling < 3.5, + relatedPillars: ['tooling'], + }, + { + id: '60-tooling-email', + title: 'Implement Email-to-Matter Linking', + description: 'Configure automatic or one-click email capture to relevant matters. Train staff on proper email filing procedures.', + owner: 'IT Director', + priority: 'high', + applicableWhen: (scores) => scores.tooling < 3, + relatedPillars: ['tooling', 'data'], + }, + { + id: '60-tooling-dms', + title: 'Enforce Document Management Compliance', + description: 'Establish policy requiring all client documents be saved to DMS. Configure desktop save locations and provide refresher training.', + owner: 'Knowledge Manager', + priority: 'medium', + applicableWhen: (scores) => scores.tooling < 3, + relatedPillars: ['tooling', 'data'], + }, + + // Knowledge System Tasks + { + id: '60-knowledge-templates', + title: 'Organize and Update Template Library', + description: 'Audit all document templates for currency and accuracy. Organize into logical structure with clear naming. Remove outdated versions.', + owner: 'Practice Group Leaders', + priority: 'high', + applicableWhen: (scores) => scores.knowledge < 3.5, + relatedPillars: ['knowledge'], + }, + { + id: '60-knowledge-sops', + title: 'Document Critical Process SOPs', + description: 'Write standard operating procedures for top 10 most common firm processes. Format consistently and store in accessible location.', + owner: 'Operations Manager', + priority: 'high', + applicableWhen: (scores) => scores.knowledge < 3, + relatedPillars: ['knowledge', 'process'], + }, + { + id: '60-knowledge-faq', + title: 'Create Staff FAQ Resource', + description: 'Compile answers to frequently asked questions about firm procedures, systems, and policies. Make searchable and easily accessible.', + owner: 'Knowledge Manager', + priority: 'medium', + applicableWhen: (scores) => scores.knowledge < 3, + relatedPillars: ['knowledge'], + }, + + // Process Tasks + { + id: '60-process-workflow', + title: 'Map Key Legal Workflows', + description: 'Document step-by-step workflows for common matter types including decision points, templates used, and handoffs between team members.', + owner: 'Practice Group Leaders', + priority: 'high', + applicableWhen: (scores) => scores.process < 3, + relatedPillars: ['process', 'knowledge'], + }, + { + id: '60-process-filing', + title: 'Standardize Filing Procedures', + description: 'Create checklists and procedures for court filings including deadline tracking, service requirements, and confirmation processes.', + owner: 'Paralegal Supervisor', + priority: 'medium', + applicableWhen: (scores) => scores.process < 3.5, + relatedPillars: ['process'], + }, + + // Data Tasks + { + id: '60-data-cleanup', + title: 'Execute Data Cleanup Sprint', + description: 'Dedicate resources to clean up historical data based on audit findings. Focus on active matters and high-value closed matters.', + owner: 'Database Administrator', + priority: 'medium', + applicableWhen: (scores) => scores.data < 2.5, + relatedPillars: ['data'], + }, + { + id: '60-data-validation', + title: 'Implement Data Validation Rules', + description: 'Configure practice management system to require critical fields and enforce formatting standards on new matter creation.', + owner: 'IT Director', + priority: 'high', + applicableWhen: (scores) => scores.data < 3, + relatedPillars: ['data', 'tooling'], + }, + + // Risk Tasks + { + id: '60-risk-audit-trail', + title: 'Enable Comprehensive Audit Logging', + description: 'Configure systems to log all access and modifications to client data. Establish review procedures and retention policies.', + owner: 'IT Director', + priority: 'high', + applicableWhen: (scores) => scores.risk < 3, + relatedPillars: ['risk', 'tooling'], + }, +]; + +// ============================================================================ +// Phase 3: Days 61-90 - Optimization & Pilot Readiness +// ============================================================================ + +/** + * Tasks for days 61-90 of the AI readiness roadmap. + * Focus: Optimization, training infrastructure, and pilot preparation. + */ +export const PHASE_90_TASKS: RoadmapTask[] = [ + // Change Capacity Tasks + { + id: '90-change-training', + title: 'Establish Training Program Infrastructure', + description: 'Set up learning management system or structured training program. Create schedule for ongoing technology training sessions.', + owner: 'HR / IT Director', + priority: 'high', + applicableWhen: (scores) => scores.change < 3.5, + relatedPillars: ['change'], + }, + { + id: '90-change-metrics', + title: 'Define Adoption Success Metrics', + description: 'Establish KPIs for measuring technology adoption success including usage rates, efficiency gains, and user satisfaction.', + owner: 'Operations Manager', + priority: 'medium', + applicableWhen: (scores) => scores.change < 4, + relatedPillars: ['change'], + }, + { + id: '90-change-feedback', + title: 'Implement Feedback Collection Process', + description: 'Create channels for staff to provide ongoing feedback on tools and processes. Establish regular review cadence.', + owner: 'Project Lead', + priority: 'medium', + applicableWhen: (scores) => scores.change < 3.5, + relatedPillars: ['change'], + }, + + // Tooling Tasks + { + id: '90-tooling-automation', + title: 'Identify Automation Opportunities', + description: 'Based on documented workflows, identify 3-5 processes suitable for automation. Prioritize by impact and implementation complexity.', + owner: 'Operations Manager', + priority: 'high', + applicableWhen: (scores) => scores.tooling < 4 && scores.process >= 2.5, + relatedPillars: ['tooling', 'process'], + }, + { + id: '90-tooling-pilot', + title: 'Select AI Pilot Use Case', + description: 'Choose initial AI tool pilot based on readiness assessment. Select use case with clear success criteria and limited risk.', + owner: 'Project Lead', + priority: 'high', + applicableWhen: (scores) => scores.risk >= 2.5 && scores.data >= 2.5, + relatedPillars: ['tooling', 'risk'], + }, + { + id: '90-tooling-integration', + title: 'Plan System Integration Requirements', + description: 'Document integration requirements for potential AI tools including data flows, authentication, and API capabilities.', + owner: 'IT Director', + priority: 'medium', + applicableWhen: (scores) => scores.tooling < 3.5, + relatedPillars: ['tooling'], + }, + + // Knowledge Tasks + { + id: '90-knowledge-playbooks', + title: 'Develop Practice Area Playbooks', + description: 'Create comprehensive guides for each major practice area including workflows, templates, deadlines, and best practices.', + owner: 'Practice Group Leaders', + priority: 'medium', + applicableWhen: (scores) => scores.knowledge < 3.5 && scores.process >= 2.5, + relatedPillars: ['knowledge', 'process'], + }, + { + id: '90-knowledge-onboarding', + title: 'Revamp New Hire Onboarding', + description: 'Create structured onboarding program incorporating documented SOPs, system training, and mentorship assignments.', + owner: 'HR', + priority: 'medium', + applicableWhen: (scores) => scores.knowledge < 3 || scores.change < 3, + relatedPillars: ['knowledge', 'change'], + }, + + // Process Tasks + { + id: '90-process-metrics', + title: 'Establish Process Efficiency Baselines', + description: 'Measure current time and effort for key processes to establish baselines for measuring future AI-driven improvements.', + owner: 'Operations Manager', + priority: 'medium', + applicableWhen: (scores) => scores.process >= 2.5, + relatedPillars: ['process'], + }, + { + id: '90-process-governance', + title: 'Create Process Governance Committee', + description: 'Establish cross-functional team responsible for process standardization, documentation maintenance, and continuous improvement.', + owner: 'Managing Partner', + priority: 'medium', + applicableWhen: (scores) => scores.process < 3.5, + relatedPillars: ['process', 'change'], + }, + + // Risk Tasks + { + id: '90-risk-retention', + title: 'Formalize Data Retention Policy', + description: 'Document and implement data retention and destruction policies aligned with ethical obligations and business needs.', + owner: 'Compliance Officer', + priority: 'high', + applicableWhen: (scores) => scores.risk < 3.5, + relatedPillars: ['risk'], + }, + { + id: '90-risk-vendor', + title: 'Develop AI Vendor Evaluation Criteria', + description: 'Create checklist for evaluating AI vendors including security certifications, data handling practices, and compliance capabilities.', + owner: 'IT Director / Compliance', + priority: 'medium', + applicableWhen: (scores) => scores.risk >= 2.5 && scores.tooling >= 2.5, + relatedPillars: ['risk', 'tooling'], + }, + + // Data Tasks + { + id: '90-data-governance', + title: 'Establish Data Governance Framework', + description: 'Define data ownership, quality standards, and stewardship responsibilities. Create ongoing data quality monitoring process.', + owner: 'Operations Manager', + priority: 'high', + applicableWhen: (scores) => scores.data < 3.5, + relatedPillars: ['data'], + }, + { + id: '90-data-taxonomy', + title: 'Standardize Firm-Wide Taxonomy', + description: 'Implement consistent practice area codes, matter types, and document categories across all systems.', + owner: 'Knowledge Manager', + priority: 'medium', + applicableWhen: (scores) => scores.data < 3, + relatedPillars: ['data', 'knowledge'], + }, +]; + +/** + * Get all tasks for a specific phase + * @param phase - Phase number (30, 60, or 90) + * @returns Array of tasks for that phase + */ +export function getTasksByPhase(phase: 30 | 60 | 90): RoadmapTask[] { + switch (phase) { + case 30: + return PHASE_30_TASKS; + case 60: + return PHASE_60_TASKS; + case 90: + return PHASE_90_TASKS; + default: + return []; + } +} + +/** + * Get all applicable tasks for given scores across all phases + * @param scores - The pillar scores from assessment + * @returns Object with tasks grouped by phase + */ +export function getApplicableTasks(scores: PillarScores): { + phase30: RoadmapTask[]; + phase60: RoadmapTask[]; + phase90: RoadmapTask[]; +} { + return { + phase30: PHASE_30_TASKS.filter(task => task.applicableWhen(scores)), + phase60: PHASE_60_TASKS.filter(task => task.applicableWhen(scores)), + phase90: PHASE_90_TASKS.filter(task => task.applicableWhen(scores)), + }; +} + +/** + * Get tasks filtered by pillar + * @param pillarId - The pillar to filter by + * @param scores - Optional scores to filter by applicability + * @returns Tasks related to the specified pillar + */ +export function getTasksByPillar( + pillarId: PillarId, + scores?: PillarScores +): RoadmapTask[] { + const allTasks = [...PHASE_30_TASKS, ...PHASE_60_TASKS, ...PHASE_90_TASKS]; + const pillarTasks = allTasks.filter(task => + task.relatedPillars.includes(pillarId) + ); + + if (scores) { + return pillarTasks.filter(task => task.applicableWhen(scores)); + } + + return pillarTasks; +} diff --git a/ai-readiness-accelerator/src/constants/scoring.ts b/ai-readiness-accelerator/src/constants/scoring.ts new file mode 100644 index 0000000..1fe9a8d --- /dev/null +++ b/ai-readiness-accelerator/src/constants/scoring.ts @@ -0,0 +1,203 @@ +/** + * Scoring configuration for the AI Readiness Accelerator + * + * Defines thresholds, levels, and visual styling for assessment scoring. + * All scores use a 1-5 scale where 1 is lowest and 5 is highest. + */ + +import type { PillarStatus, ReadinessLevel } from '../types'; + +/** + * Score threshold definition for pillar status classification + */ +export interface ScoreThreshold { + /** Status classification */ + status: PillarStatus; + /** Minimum score (inclusive) */ + min: number; + /** Maximum score (exclusive, except for last tier which is inclusive) */ + max: number; + /** Human-readable label for this threshold */ + label: string; +} + +/** + * Score thresholds for classifying individual pillar performance. + * Thresholds are evaluated in order; first matching range wins. + */ +export const SCORE_THRESHOLDS: ScoreThreshold[] = [ + { + status: 'critical', + min: 0, + max: 1.5, + label: 'Critical', + }, + { + status: 'needs-work', + min: 1.5, + max: 2.5, + label: 'Needs Work', + }, + { + status: 'adequate', + min: 2.5, + max: 3.5, + label: 'Adequate', + }, + { + status: 'strong', + min: 3.5, + max: 4.5, + label: 'Strong', + }, + { + status: 'excellent', + min: 4.5, + max: 5, + label: 'Excellent', + }, +]; + +/** + * Extended readiness level definition with metadata + */ +export interface ReadinessLevelDefinition { + /** Numeric level (1-5) */ + level: number; + /** Internal identifier matching ReadinessLevel type */ + id: ReadinessLevel; + /** Display label */ + label: string; + /** Score range as [min, max] tuple (inclusive) */ + scoreRange: [number, number]; + /** Description of what this level means for the organization */ + description: string; + /** Tailwind CSS color class for visual styling */ + color: string; +} + +/** + * Overall readiness level definitions. + * These classify the firm's aggregate readiness for AI adoption. + */ +export const READINESS_LEVELS: ReadinessLevelDefinition[] = [ + { + level: 1, + id: 'not-ready', + label: 'Not Ready', + scoreRange: [1, 1.5], + description: 'Significant foundational work needed before AI adoption. Focus on basic process documentation and data cleanup.', + color: 'text-red-600 bg-red-50', + }, + { + level: 2, + id: 'foundational', + label: 'Foundational', + scoreRange: [1.5, 2.5], + description: 'Early stage readiness with gaps in multiple areas. Prioritize addressing critical weaknesses before piloting AI tools.', + color: 'text-orange-600 bg-orange-50', + }, + { + level: 3, + id: 'developing', + label: 'Developing', + scoreRange: [2.5, 3.5], + description: 'Moderate readiness with room for improvement. Good candidate for targeted AI pilots in stronger areas.', + color: 'text-yellow-600 bg-yellow-50', + }, + { + level: 4, + id: 'ready', + label: 'Ready', + scoreRange: [3.5, 4.5], + description: 'Well-positioned for AI adoption. Solid foundations in place; focus on optimization and strategic deployment.', + color: 'text-green-600 bg-green-50', + }, + { + level: 5, + id: 'optimized', + label: 'Optimized', + scoreRange: [4.5, 5], + description: 'Excellent readiness across all dimensions. Ideal candidate for advanced AI implementations and innovation.', + color: 'text-blue-600 bg-blue-50', + }, +]; + +/** + * Tailwind CSS color classes mapped to pillar status. + * Use these for consistent status visualization across the application. + */ +export const STATUS_COLORS: Record = { + critical: { + text: 'text-red-700', + bg: 'bg-red-100', + border: 'border-red-300', + badge: 'bg-red-600 text-white', + }, + 'needs-work': { + text: 'text-orange-700', + bg: 'bg-orange-100', + border: 'border-orange-300', + badge: 'bg-orange-500 text-white', + }, + adequate: { + text: 'text-yellow-700', + bg: 'bg-yellow-100', + border: 'border-yellow-300', + badge: 'bg-yellow-500 text-white', + }, + strong: { + text: 'text-green-700', + bg: 'bg-green-100', + border: 'border-green-300', + badge: 'bg-green-600 text-white', + }, + excellent: { + text: 'text-blue-700', + bg: 'bg-blue-100', + border: 'border-blue-300', + badge: 'bg-blue-600 text-white', + }, +}; + +/** + * Get the status for a given score + * @param score - The numeric score to classify (1-5 scale) + * @returns The PillarStatus corresponding to the score + */ +export function getStatusForScore(score: number): PillarStatus { + for (const threshold of SCORE_THRESHOLDS) { + if (score >= threshold.min && score < threshold.max) { + return threshold.status; + } + } + // Handle edge case of exactly 5 + if (score >= 4.5) { + return 'excellent'; + } + return 'critical'; +} + +/** + * Get the readiness level for a given overall score + * @param score - The overall assessment score (1-5 scale) + * @returns The ReadinessLevelDefinition for the score + */ +export function getReadinessLevel(score: number): ReadinessLevelDefinition { + for (const level of READINESS_LEVELS) { + if (score >= level.scoreRange[0] && score <= level.scoreRange[1]) { + return level; + } + } + // Default to lowest level if somehow out of range + return READINESS_LEVELS[0]; +} + +/** + * Get display colors for a given status + * @param status - The pillar status + * @returns Object containing Tailwind color classes + */ +export function getStatusColors(status: PillarStatus): typeof STATUS_COLORS[PillarStatus] { + return STATUS_COLORS[status]; +} diff --git a/ai-readiness-accelerator/src/index.css b/ai-readiness-accelerator/src/index.css new file mode 100644 index 0000000..b491ba8 --- /dev/null +++ b/ai-readiness-accelerator/src/index.css @@ -0,0 +1,154 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html { + scroll-behavior: smooth; + } + + body { + @apply antialiased text-slate-900 bg-slate-50; + } + + /* Focus styles for accessibility */ + :focus-visible { + @apply outline-2 outline-offset-2 outline-primary-500; + } +} + +@layer components { + /* Card component base */ + .card { + @apply bg-white rounded-xl shadow-sm border border-slate-200 p-6; + } + + /* Button variants */ + .btn { + @apply inline-flex items-center justify-center font-medium rounded-lg + transition-all duration-200 focus:outline-none focus-visible:ring-2 + focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed; + } + + .btn-primary { + @apply btn bg-primary-600 text-white hover:bg-primary-700 + focus-visible:ring-primary-500 px-6 py-3; + } + + .btn-secondary { + @apply btn bg-white text-slate-700 border border-slate-300 + hover:bg-slate-50 focus-visible:ring-slate-500 px-6 py-3; + } + + .btn-ghost { + @apply btn text-slate-600 hover:text-slate-900 hover:bg-slate-100 px-4 py-2; + } + + /* Form inputs */ + .input { + @apply w-full px-4 py-2.5 border border-slate-300 rounded-lg + focus:ring-2 focus:ring-primary-500 focus:border-primary-500 + placeholder:text-slate-400 transition-colors; + } + + .input-error { + @apply input border-red-500 focus:ring-red-500 focus:border-red-500; + } + + .label { + @apply block text-sm font-medium text-slate-700 mb-1.5; + } + + /* Likert scale */ + .likert-container { + @apply flex gap-2; + } + + .likert-option { + @apply flex-1 p-3 text-center border border-slate-200 rounded-lg + cursor-pointer transition-all hover:border-primary-300 hover:bg-primary-50; + } + + .likert-option-selected { + @apply likert-option border-primary-500 bg-primary-50 text-primary-700 font-medium; + } + + /* Progress bar */ + .progress-bar { + @apply h-2 bg-slate-200 rounded-full overflow-hidden; + } + + .progress-fill { + @apply h-full bg-primary-600 transition-all duration-300 ease-out; + } + + /* Tabs */ + .tab-list { + @apply flex gap-4 border-b border-slate-200; + } + + .tab { + @apply pb-3 px-1 font-medium text-sm transition-colors border-b-2 + border-transparent text-slate-500 hover:text-slate-700; + } + + .tab-active { + @apply tab border-primary-600 text-primary-600; + } + + /* Radar chart container */ + .radar-container { + @apply aspect-square max-w-md mx-auto; + } + + /* Score badge */ + .score-badge { + @apply inline-flex items-center px-3 py-1 rounded-full text-sm font-medium; + } + + .score-critical { + @apply score-badge bg-red-100 text-red-800; + } + + .score-needs-work { + @apply score-badge bg-orange-100 text-orange-800; + } + + .score-adequate { + @apply score-badge bg-yellow-100 text-yellow-800; + } + + .score-strong { + @apply score-badge bg-green-100 text-green-800; + } + + .score-excellent { + @apply score-badge bg-emerald-100 text-emerald-800; + } +} + +@layer utilities { + /* Loading spinner */ + .spinner { + @apply animate-spin h-5 w-5 border-2 border-primary-600 border-t-transparent rounded-full; + } + + /* Gradient backgrounds */ + .gradient-hero { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + } + + .gradient-cta { + @apply bg-gradient-to-r from-primary-600 to-primary-800; + } + + /* Section spacing */ + .section { + @apply py-16 md:py-24; + } + + /* Container */ + .container-app { + @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8; + } +} diff --git a/ai-readiness-accelerator/src/main.tsx b/ai-readiness-accelerator/src/main.tsx new file mode 100644 index 0000000..964aeb4 --- /dev/null +++ b/ai-readiness-accelerator/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/ai-readiness-accelerator/src/services/gemini.service.ts b/ai-readiness-accelerator/src/services/gemini.service.ts new file mode 100644 index 0000000..796ced7 --- /dev/null +++ b/ai-readiness-accelerator/src/services/gemini.service.ts @@ -0,0 +1,454 @@ +/** + * Gemini API Service for AI Readiness Accelerator + * + * This service handles communication with Google's Gemini API to generate + * AI-powered executive summaries based on assessment scores and firm profiles. + */ + +import type { + PillarScores, + FirmProfile, + ExecutiveSummary, + GeminiResponse, + GeminiError, +} from '../types'; + +/** Gemini API endpoint for content generation */ +const GEMINI_API_URL = + 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent'; + +/** Request timeout in milliseconds */ +const REQUEST_TIMEOUT_MS = 30000; + +/** + * JSON Schema for Gemini's structured output. + * This schema ensures the API returns data matching our ExecutiveSummary interface. + */ +const EXECUTIVE_SUMMARY_SCHEMA = { + type: 'object', + properties: { + overallAssessment: { + type: 'string', + description: '2-3 sentence executive summary of the assessment', + }, + keyFindings: { + type: 'array', + items: { type: 'string' }, + description: '3-4 bullet points of main observations', + }, + priorityActions: { + type: 'array', + items: { type: 'string' }, + description: '3 specific next steps ordered by importance', + }, + recommendedFirstMove: { + type: 'string', + description: 'Single most important action for the next 30 days', + }, + riskConsiderations: { + type: 'array', + items: { type: 'string' }, + description: '2-3 risks to be aware of', + }, + }, + required: [ + 'overallAssessment', + 'keyFindings', + 'priorityActions', + 'recommendedFirstMove', + 'riskConsiderations', + ], +}; + +/** + * Builds the detailed prompt for Gemini API based on scores and firm profile. + * + * @param scores - The pillar scores from the assessment + * @param firmProfile - The law firm's profile information + * @returns Formatted prompt string for the API + */ +function buildPrompt(scores: PillarScores, firmProfile: FirmProfile): string { + const pillarDetails = scores.pillars + .map((p) => `- ${p.name}: ${p.score}/100 (Status: ${p.status})`) + .join('\n'); + + const practiceAreas = firmProfile.practiceAreas.join(', '); + const currentTools = firmProfile.currentTools.length > 0 + ? firmProfile.currentTools.join(', ') + : 'None specified'; + const aiGoals = firmProfile.aiGoals?.length + ? firmProfile.aiGoals.join(', ') + : 'Not specified'; + const attorneyCount = firmProfile.attorneyCount + ? `${firmProfile.attorneyCount} attorneys` + : firmProfile.size; + + return `You are an AI readiness consultant specializing in helping law firms adopt artificial intelligence technologies. Your role is to provide strategic, actionable guidance based on assessment data. + +## Firm Profile +- **Firm Name:** ${firmProfile.name} +- **Practice Areas:** ${practiceAreas} +- **Firm Size:** ${attorneyCount} +- **Current Technology Tools:** ${currentTools} +- **AI Adoption Goals:** ${aiGoals} + +## Assessment Results +**Overall AI Readiness Score:** ${scores.overall}/100 +**Readiness Level:** ${scores.readinessLevel} + +### Pillar Scores: +${pillarDetails} + +## Task +Based on the assessment data above, generate an executive summary for this law firm. Your analysis should be: +- Specific to their practice areas and firm size +- Actionable with concrete next steps +- Realistic about challenges they may face +- Focused on quick wins and high-impact improvements + +## Required Output Format +Provide your response as a JSON object with the following structure: + +1. **overallAssessment**: Write a 2-3 sentence executive summary that captures the firm's current AI readiness state and potential trajectory. Be direct and specific to this firm. + +2. **keyFindings**: Provide 3-4 bullet points highlighting the most important observations from the assessment. Each finding should reference specific pillar scores or firm characteristics. + +3. **priorityActions**: List exactly 3 specific, actionable next steps ordered by importance. Each action should be concrete enough to implement within 30-90 days. + +4. **recommendedFirstMove**: Identify the single most important action this firm should take in the next 30 days. This should be achievable, high-impact, and build momentum for further AI adoption. + +5. **riskConsiderations**: List 2-3 risks or challenges the firm should be aware of as they pursue AI adoption. These should be relevant to their specific situation. + +Remember: This is for a law firm, so consider ethical obligations, client confidentiality requirements, and the conservative nature of legal practice in your recommendations.`; +} + +/** + * Validates and normalizes the API response to ensure it matches ExecutiveSummary interface. + * Fills in defaults for any missing fields. + * + * @param data - The parsed response data from the API + * @returns A validated ExecutiveSummary object with defaults for missing fields + */ +function validateAndNormalizeResponse(data: unknown): ExecutiveSummary { + const response = data as Partial; + + return { + overallAssessment: + response.overallAssessment || + 'Assessment analysis is currently unavailable. Please review your pillar scores directly.', + keyFindings: + Array.isArray(response.keyFindings) && response.keyFindings.length > 0 + ? response.keyFindings.slice(0, 4) + : ['Assessment data has been recorded', 'Review individual pillar scores for detailed insights'], + priorityActions: + Array.isArray(response.priorityActions) && response.priorityActions.length > 0 + ? response.priorityActions.slice(0, 3) + : [ + 'Review assessment results with leadership team', + 'Identify quick-win opportunities in highest-scoring areas', + 'Develop an AI adoption roadmap', + ], + recommendedFirstMove: + response.recommendedFirstMove || + 'Schedule a team meeting to review assessment results and align on AI adoption priorities.', + riskConsiderations: + Array.isArray(response.riskConsiderations) && response.riskConsiderations.length > 0 + ? response.riskConsiderations.slice(0, 3) + : [ + 'Ensure compliance with ethical obligations when implementing AI tools', + 'Consider data security implications for client information', + ], + }; +} + +/** + * Creates a fallback executive summary when the API call fails. + * This ensures users always receive some guidance even when the AI service is unavailable. + * + * @param scores - The pillar scores from the assessment + * @param firmProfile - The law firm's profile information + * @returns A basic ExecutiveSummary based on available data + */ +function createFallbackSummary( + scores: PillarScores, + firmProfile: FirmProfile +): ExecutiveSummary { + const lowestPillar = [...scores.pillars].sort((a, b) => a.score - b.score)[0]; + const highestPillar = [...scores.pillars].sort((a, b) => b.score - a.score)[0]; + + const sizeContext = + firmProfile.size === 'Solo' || firmProfile.size === 'Small' + ? 'smaller firm' + : 'firm of your size'; + + return { + overallAssessment: `${firmProfile.name} achieved an overall AI readiness score of ${scores.overall}/100, placing you at the "${scores.readinessLevel}" level. This assessment provides a baseline for your AI adoption journey.`, + keyFindings: [ + `Your strongest area is ${highestPillar.name} with a score of ${highestPillar.score}/100`, + `${lowestPillar.name} presents the greatest opportunity for improvement at ${lowestPillar.score}/100`, + `As a ${sizeContext}, focusing on targeted improvements can yield significant results`, + `Current tool adoption: ${firmProfile.currentTools.length > 0 ? firmProfile.currentTools.join(', ') : 'Limited technology stack identified'}`, + ], + priorityActions: [ + `Address gaps in ${lowestPillar.name} to strengthen your overall AI readiness`, + `Build on your strength in ${highestPillar.name} to create quick wins`, + 'Develop a phased AI adoption roadmap aligned with your practice areas', + ], + recommendedFirstMove: `Focus on improving ${lowestPillar.name} by identifying one specific, low-risk AI tool or process that can demonstrate value within 30 days.`, + riskConsiderations: [ + 'Ensure all AI tools comply with bar association ethics rules and client confidentiality requirements', + 'Start with internal processes before client-facing AI applications to build confidence and expertise', + 'Plan for staff training and change management to ensure successful adoption', + ], + }; +} + +/** + * Fetches with a timeout wrapper. + * + * @param url - The URL to fetch + * @param options - Fetch options + * @param timeoutMs - Timeout in milliseconds + * @returns Promise resolving to the fetch Response + * @throws Error if the request times out + */ +async function fetchWithTimeout( + url: string, + options: RequestInit, + timeoutMs: number +): Promise { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + try { + const response = await fetch(url, { + ...options, + signal: controller.signal, + }); + return response; + } finally { + clearTimeout(timeoutId); + } +} + +/** + * Generates an AI-powered executive summary based on assessment scores and firm profile. + * + * This function calls the Gemini API to analyze the assessment data and generate + * personalized recommendations for the law firm. If the API call fails, it returns + * a fallback summary based on the available data. + * + * @param scores - The pillar scores from the AI readiness assessment + * @param firmProfile - The law firm's profile information + * @returns Promise resolving to an ExecutiveSummary object + * + * @example + * ```typescript + * const scores: PillarScores = { + * pillars: [{ id: '1', name: 'Data Infrastructure', score: 75, status: 'strong' }], + * overall: 72, + * readinessLevel: 'developing' + * }; + * + * const firmProfile: FirmProfile = { + * name: 'Smith & Associates', + * practiceAreas: ['Corporate Law', 'Litigation'], + * size: 'Mid-size', + * currentTools: ['Clio', 'NetDocuments'] + * }; + * + * const summary = await generateExecutiveSummary(scores, firmProfile); + * ``` + */ +export async function generateExecutiveSummary( + scores: PillarScores, + firmProfile: FirmProfile +): Promise { + const apiKey = import.meta.env.VITE_GEMINI_API_KEY; + + // If no API key is configured, return the fallback summary + if (!apiKey) { + console.warn( + 'Gemini API key not configured (VITE_GEMINI_API_KEY). Using fallback summary.' + ); + return createFallbackSummary(scores, firmProfile); + } + + const prompt = buildPrompt(scores, firmProfile); + + const requestBody = { + contents: [ + { + parts: [ + { + text: prompt, + }, + ], + }, + ], + generationConfig: { + temperature: 0.7, + topK: 40, + topP: 0.95, + maxOutputTokens: 2048, + responseMimeType: 'application/json', + responseSchema: EXECUTIVE_SUMMARY_SCHEMA, + }, + }; + + try { + const response = await fetchWithTimeout( + `${GEMINI_API_URL}?key=${apiKey}`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), + }, + REQUEST_TIMEOUT_MS + ); + + if (!response.ok) { + const errorData = (await response.json()) as GeminiError; + const errorMessage = errorData.error?.message || 'Unknown API error'; + console.error('Gemini API error:', errorMessage); + throw new Error(`AI service error: ${errorMessage}`); + } + + const data = (await response.json()) as GeminiResponse; + + // Extract the text content from the response + const textContent = data.candidates?.[0]?.content?.parts?.[0]?.text; + + if (!textContent) { + console.error('Gemini API returned empty response'); + throw new Error('AI service returned an empty response'); + } + + // Parse the JSON response + let parsedResponse: unknown; + try { + parsedResponse = JSON.parse(textContent); + } catch (parseError) { + console.error('Failed to parse Gemini response as JSON:', parseError); + throw new Error('AI service returned invalid response format'); + } + + // Validate and normalize the response + return validateAndNormalizeResponse(parsedResponse); + } catch (error) { + // Handle abort (timeout) errors + if (error instanceof Error && error.name === 'AbortError') { + console.error('Gemini API request timed out after', REQUEST_TIMEOUT_MS, 'ms'); + console.warn('Returning fallback summary due to timeout'); + return createFallbackSummary(scores, firmProfile); + } + + // Handle network errors + if (error instanceof TypeError && error.message.includes('fetch')) { + console.error('Network error connecting to Gemini API:', error); + console.warn('Returning fallback summary due to network error'); + return createFallbackSummary(scores, firmProfile); + } + + // Log and re-throw other errors, but still provide fallback + console.error('Error generating executive summary:', error); + console.warn('Returning fallback summary due to error'); + return createFallbackSummary(scores, firmProfile); + } +} + +/** + * Mock function for development and testing without a Gemini API key. + * + * This function simulates the API response with realistic data based on + * the provided scores and firm profile. Useful for: + * - Development without API costs + * - Unit testing + * - Demo environments + * + * @param scores - The pillar scores from the AI readiness assessment + * @param firmProfile - The law firm's profile information + * @param delay - Optional delay in milliseconds to simulate API latency (default: 1500) + * @returns Promise resolving to a mock ExecutiveSummary object + * + * @example + * ```typescript + * // Use mock in development + * const summary = await generateExecutiveSummaryMock(scores, firmProfile); + * + * // Simulate slower response + * const summary = await generateExecutiveSummaryMock(scores, firmProfile, 3000); + * ``` + */ +export async function generateExecutiveSummaryMock( + scores: PillarScores, + firmProfile: FirmProfile, + delay: number = 1500 +): Promise { + // Simulate API latency + await new Promise((resolve) => setTimeout(resolve, delay)); + + const lowestPillar = [...scores.pillars].sort((a, b) => a.score - b.score)[0]; + const highestPillar = [...scores.pillars].sort((a, b) => b.score - a.score)[0]; + const midPillars = [...scores.pillars] + .sort((a, b) => a.score - b.score) + .slice(1, -1); + + const readinessDescriptions: Record = { + 'not-ready': 'early stages of AI readiness', + foundational: 'building foundational AI capabilities', + developing: 'actively developing AI readiness', + ready: 'well-positioned for AI adoption', + optimized: 'leading the way in AI adoption', + }; + + const readinessDesc = + readinessDescriptions[scores.readinessLevel] || 'developing AI readiness'; + + const sizeRecommendations: Record = { + Solo: 'Focus on AI tools that can multiply your individual productivity', + Small: 'Prioritize tools that enhance collaboration and reduce administrative burden', + 'Mid-size': 'Consider department-specific AI solutions with firm-wide integration', + Large: 'Develop a comprehensive AI governance framework alongside tool adoption', + Enterprise: 'Establish an AI Center of Excellence to coordinate firm-wide initiatives', + }; + + const sizeRec = + sizeRecommendations[firmProfile.size] || + 'Develop a phased approach to AI adoption'; + + return { + overallAssessment: `${firmProfile.name} scored ${scores.overall}/100 on the AI Readiness Assessment, indicating the firm is ${readinessDesc}. With strengths in ${highestPillar.name} and opportunities for growth in ${lowestPillar.name}, ${firmProfile.name} has a clear path forward for strategic AI adoption that can enhance both efficiency and client service quality.`, + keyFindings: [ + `Strong foundation in ${highestPillar.name} (${highestPillar.score}/100) provides a solid base for AI initiatives`, + `${lowestPillar.name} at ${lowestPillar.score}/100 represents the greatest opportunity for improvement`, + midPillars.length > 0 + ? `${midPillars[0].name} shows moderate readiness (${midPillars[0].score}/100) and could benefit from targeted enhancements` + : `Overall pillar scores show room for improvement across multiple areas`, + `Current technology stack (${firmProfile.currentTools.length > 0 ? firmProfile.currentTools.slice(0, 2).join(', ') : 'limited tools'}) provides ${firmProfile.currentTools.length > 2 ? 'a good' : 'a basic'} foundation for AI integration`, + ], + priorityActions: [ + `Invest in ${lowestPillar.name} improvements: Identify specific gaps and implement targeted solutions within Q1`, + `Leverage your ${highestPillar.name} strength: ${sizeRec}`, + `Establish AI governance: Create clear policies for AI tool evaluation, data handling, and ethical use in client matters`, + ], + recommendedFirstMove: `Within the next 30 days, conduct a focused assessment of ${lowestPillar.name} to identify 2-3 specific, low-risk AI tools that can address current gaps. Start with internal processes before expanding to client-facing applications.`, + riskConsiderations: [ + `Client confidentiality: Ensure all AI tools meet bar association requirements and client data protection standards before deployment`, + `Change management: Plan for attorney and staff training to maximize adoption and minimize resistance to new AI-powered workflows`, + `Vendor selection: Carefully evaluate AI vendors for legal-specific experience, security certifications, and long-term viability`, + ], + }; +} + +/** + * Checks if the Gemini API key is configured in the environment. + * + * @returns True if the API key is present and non-empty + */ +export function isGeminiConfigured(): boolean { + const apiKey = import.meta.env.VITE_GEMINI_API_KEY; + return typeof apiKey === 'string' && apiKey.length > 0; +} diff --git a/ai-readiness-accelerator/src/services/scoring.service.ts b/ai-readiness-accelerator/src/services/scoring.service.ts new file mode 100644 index 0000000..5fda6f8 --- /dev/null +++ b/ai-readiness-accelerator/src/services/scoring.service.ts @@ -0,0 +1,291 @@ +/** + * Scoring Service for the AI Readiness Accelerator + * + * This service provides pure functions for calculating assessment scores, + * determining readiness levels, and identifying strengths and gaps. + */ + +import type { + QuestionResponse, + AssessmentResponses, + PillarDefinition, + PillarScores, + PillarScore, + PillarStatus, + ReadinessLevel, + StrengthsGaps, + StrengthGapItem, +} from '../types'; + +import { + CRITICAL_PILLAR_IDS, + BLOCKER_SCORE_THRESHOLD, + STRENGTHS_GAPS_COUNT, + PILLAR_STATUS_DESCRIPTIONS, +} from '../constants'; + +/** + * Calculates the score for a single pillar based on question responses. + * + * @param responses - Array of question responses for the pillar + * @returns The average score rounded to 1 decimal place, or 0 if no responses + * + * @example + * ```ts + * const responses = [ + * { questionId: 'q1', value: 4 }, + * { questionId: 'q2', value: 3 }, + * { questionId: 'q3', value: 5 }, + * ]; + * const score = calculatePillarScore(responses); // 4.0 + * ``` + */ +export function calculatePillarScore(responses: QuestionResponse[]): number { + if (!responses || responses.length === 0) { + return 0; + } + + const sum = responses.reduce((acc, response) => acc + response.value, 0); + const average = sum / responses.length; + + // Round to 1 decimal place + return Math.round(average * 10) / 10; +} + +/** + * Determines the status level for a pillar based on its score. + * + * @param score - The pillar's score (0-5 scale) + * @returns The status level: 'critical', 'needs-work', 'adequate', 'strong', or 'excellent' + * + * @example + * ```ts + * getPillarStatus(1.2); // 'critical' + * getPillarStatus(2.0); // 'needs-work' + * getPillarStatus(3.0); // 'adequate' + * getPillarStatus(4.0); // 'strong' + * getPillarStatus(4.8); // 'excellent' + * ``` + */ +export function getPillarStatus(score: number): PillarStatus { + if (score < 1.5) { + return 'critical'; + } + if (score < 2.5) { + return 'needs-work'; + } + if (score < 3.5) { + return 'adequate'; + } + if (score < 4.5) { + return 'strong'; + } + return 'excellent'; +} + +/** + * Determines the overall readiness level based on the average score. + * + * @param overallScore - The overall average score (0-5 scale) + * @returns The readiness level: 'not-ready', 'foundational', 'developing', 'ready', or 'optimized' + * + * @example + * ```ts + * getReadinessLevel(0.5); // 'not-ready' + * getReadinessLevel(1.5); // 'foundational' + * getReadinessLevel(2.5); // 'developing' + * getReadinessLevel(3.5); // 'ready' + * getReadinessLevel(4.5); // 'optimized' + * ``` + */ +export function getReadinessLevel(overallScore: number): ReadinessLevel { + if (overallScore <= 1.0) { + return 'not-ready'; + } + if (overallScore <= 2.0) { + return 'foundational'; + } + if (overallScore <= 3.0) { + return 'developing'; + } + if (overallScore <= 4.0) { + return 'ready'; + } + return 'optimized'; +} + +/** + * Calculates scores for all pillars and determines overall readiness. + * + * @param responses - Map of pillar IDs to their question responses + * @param pillarDefinitions - Array of pillar definitions with id and name + * @returns Complete scoring results including pillar scores, overall score, and readiness level + * + * @example + * ```ts + * const responses = { + * 'data': [{ questionId: 'q1', value: 4 }, { questionId: 'q2', value: 3 }], + * 'risk': [{ questionId: 'q1', value: 2 }, { questionId: 'q2', value: 3 }], + * }; + * const pillars = [ + * { id: 'data', name: 'Data Foundation' }, + * { id: 'risk', name: 'Risk Management' }, + * ]; + * const scores = calculateAllScores(responses, pillars); + * // { + * // pillars: [ + * // { id: 'data', name: 'Data Foundation', score: 3.5, status: 'strong' }, + * // { id: 'risk', name: 'Risk Management', score: 2.5, status: 'adequate' }, + * // ], + * // overall: 3.0, + * // readinessLevel: 'developing' + * // } + * ``` + */ +export function calculateAllScores( + responses: AssessmentResponses, + pillarDefinitions: PillarDefinition[] +): PillarScores { + const pillarScores: PillarScore[] = pillarDefinitions.map((pillar) => { + const pillarResponses = responses[pillar.id] || []; + const score = calculatePillarScore(pillarResponses); + const status = getPillarStatus(score); + + return { + id: pillar.id, + name: pillar.name, + score, + status, + }; + }); + + // Calculate overall score as average of all pillar scores + const overall = + pillarScores.length > 0 + ? Math.round( + (pillarScores.reduce((acc, p) => acc + p.score, 0) / pillarScores.length) * 10 + ) / 10 + : 0; + + const readinessLevel = getReadinessLevel(overall); + + return { + pillars: pillarScores, + overall, + readinessLevel, + }; +} + +/** + * Generates a description for a pillar based on its score level. + * + * @param pillarName - The name of the pillar + * @param status - The pillar's status level + * @returns A description string for the pillar + */ +function generatePillarDescription(pillarName: string, status: PillarStatus): string { + return `${pillarName} ${PILLAR_STATUS_DESCRIPTIONS[status]}`; +} + +/** + * Identifies the top strengths and gaps from pillar scores. + * + * @param pillarScores - Array of pillar scores to analyze + * @returns Object containing top 3 strengths and bottom 3 gaps with descriptions + * + * @example + * ```ts + * const pillarScores = [ + * { id: 'data', name: 'Data Foundation', score: 4.5, status: 'excellent' }, + * { id: 'risk', name: 'Risk Management', score: 2.0, status: 'needs-work' }, + * { id: 'talent', name: 'Talent', score: 3.5, status: 'strong' }, + * ]; + * const { strengths, gaps } = identifyStrengthsGaps(pillarScores); + * // strengths: [{ pillarId: 'data', pillarName: 'Data Foundation', score: 4.5, description: '...' }, ...] + * // gaps: [{ pillarId: 'risk', pillarName: 'Risk Management', score: 2.0, description: '...' }, ...] + * ``` + */ +export function identifyStrengthsGaps(pillarScores: PillarScore[]): StrengthsGaps { + if (!pillarScores || pillarScores.length === 0) { + return { strengths: [], gaps: [] }; + } + + // Sort by score descending for strengths + const sortedByScoreDesc = [...pillarScores].sort((a, b) => b.score - a.score); + + // Sort by score ascending for gaps + const sortedByScoreAsc = [...pillarScores].sort((a, b) => a.score - b.score); + + // Take top N as strengths + const strengths: StrengthGapItem[] = sortedByScoreDesc + .slice(0, STRENGTHS_GAPS_COUNT) + .map((pillar) => ({ + pillarId: pillar.id, + pillarName: pillar.name, + score: pillar.score, + description: generatePillarDescription(pillar.name, pillar.status), + })); + + // Take bottom N as gaps + const gaps: StrengthGapItem[] = sortedByScoreAsc + .slice(0, STRENGTHS_GAPS_COUNT) + .map((pillar) => ({ + pillarId: pillar.id, + pillarName: pillar.name, + score: pillar.score, + description: generatePillarDescription(pillar.name, pillar.status), + })); + + return { strengths, gaps }; +} + +/** + * Identifies blocking issues for AI deployment based on pillar scores. + * + * @param pillarScores - Array of pillar scores to analyze + * @returns Array of blocker messages for any pillar with score below threshold, + * with special emphasis on critical pillars (risk and data) + * + * @example + * ```ts + * const pillarScores = [ + * { id: 'data', name: 'Data Foundation', score: 2.0, status: 'needs-work' }, + * { id: 'risk', name: 'Risk Management', score: 2.5, status: 'adequate' }, + * { id: 'talent', name: 'Talent', score: 2.8, status: 'adequate' }, + * ]; + * const blockers = getBlockers(pillarScores); + * // [ + * // 'CRITICAL: Data Foundation score (2.0) is below minimum threshold. This is a critical blocker for AI deployment.', + * // 'CRITICAL: Risk Management score (2.5) is below minimum threshold. This is a critical blocker for AI deployment.', + * // 'Talent score (2.8) is below the recommended threshold of 3.0' + * // ] + * ``` + */ +export function getBlockers(pillarScores: PillarScore[]): string[] { + if (!pillarScores || pillarScores.length === 0) { + return []; + } + + const blockers: string[] = []; + + for (const pillar of pillarScores) { + if (pillar.score < BLOCKER_SCORE_THRESHOLD) { + const isCriticalPillar = CRITICAL_PILLAR_IDS.includes( + pillar.id as (typeof CRITICAL_PILLAR_IDS)[number] + ); + + if (isCriticalPillar) { + blockers.push( + `CRITICAL: ${pillar.name} score (${pillar.score}) is below minimum threshold. ` + + `This is a critical blocker for AI deployment.` + ); + } else { + blockers.push( + `${pillar.name} score (${pillar.score}) is below the recommended threshold of ${BLOCKER_SCORE_THRESHOLD}` + ); + } + } + } + + return blockers; +} diff --git a/ai-readiness-accelerator/src/types/assessment.types.ts b/ai-readiness-accelerator/src/types/assessment.types.ts new file mode 100644 index 0000000..1e15012 --- /dev/null +++ b/ai-readiness-accelerator/src/types/assessment.types.ts @@ -0,0 +1,179 @@ +/** + * Type definitions for the 6-pillar AI readiness assessment + * @module assessment.types + */ + +/** + * Identifiers for each of the six assessment pillars + * - process: Business process documentation and standardization + * - data: Data quality, organization, and accessibility + * - knowledge: Institutional knowledge capture and management + * - tooling: Technology infrastructure and integration capabilities + * - risk: Risk management and compliance considerations + * - change: Change management and organizational readiness + */ +export type PillarId = + | 'process' + | 'data' + | 'knowledge' + | 'tooling' + | 'risk' + | 'change'; + +/** + * Likert scale value for assessment questions + * 0 = Not applicable / Don't know + * 1 = Strongly disagree / Never + * 2 = Disagree / Rarely + * 3 = Neutral / Sometimes + * 4 = Agree / Often + * 5 = Strongly agree / Always + */ +export type LikertValue = 0 | 1 | 2 | 3 | 4 | 5; + +/** + * Individual assessment question within a pillar + */ +export interface Question { + /** Unique identifier for the question (e.g., "process-1", "data-3") */ + id: string; + + /** The question text presented to the user */ + text: string; + + /** Optional contextual help explaining what the question is asking */ + helpText?: string; + + /** Sub-category within the pillar for grouping related questions */ + category: string; +} + +/** + * Definition of an assessment pillar including its questions + */ +export interface PillarDefinition { + /** Unique identifier for the pillar */ + id: PillarId; + + /** Full display name of the pillar */ + name: string; + + /** Abbreviated name for compact displays */ + shortName: string; + + /** Detailed description of what this pillar assesses */ + description: string; + + /** Icon identifier (e.g., "workflow", "database", "brain") */ + icon: string; + + /** Array of questions for this pillar */ + questions: Question[]; +} + +/** + * User's response to a single assessment question + */ +export interface QuestionResponse { + /** ID of the question being answered */ + questionId: string; + + /** Selected Likert scale value */ + value: LikertValue; + + /** Optional notes or comments from the user */ + notes?: string; +} + +/** + * Collection of all assessment responses organized by pillar + * Maps each pillar ID to an array of question responses + */ +export type AssessmentResponses = Record; + +/** + * Current state of the assessment workflow + */ +export interface AssessmentState { + /** + * Current step in the assessment process + * 0 = Firm profile + * 1-6 = Pillar assessments (process, data, knowledge, tooling, risk, change) + * 7 = Review/complete + */ + currentStep: number; + + /** All collected responses organized by pillar */ + responses: AssessmentResponses; + + /** Whether all required questions have been answered */ + isComplete: boolean; + + /** ISO timestamp when the assessment was started */ + startedAt: string; + + /** ISO timestamp when the assessment was completed (if finished) */ + completedAt?: string; +} + +/** + * Likert scale labels for display + */ +export const LIKERT_LABELS: Record = { + 0: 'N/A', + 1: 'Strongly Disagree', + 2: 'Disagree', + 3: 'Neutral', + 4: 'Agree', + 5: 'Strongly Agree', +}; + +/** + * Short Likert scale labels for compact display + */ +export const LIKERT_SHORT_LABELS: Record = { + 0: 'N/A', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', +}; + +/** + * All pillar IDs in assessment order + */ +export const PILLAR_ORDER: PillarId[] = [ + 'process', + 'data', + 'knowledge', + 'tooling', + 'risk', + 'change', +]; + +/** + * Creates an empty assessment responses object + */ +export function createEmptyAssessmentResponses(): AssessmentResponses { + return { + process: [], + data: [], + knowledge: [], + tooling: [], + risk: [], + change: [], + }; +} + +/** + * Creates an initial assessment state + */ +export function createInitialAssessmentState(): AssessmentState { + return { + currentStep: 0, + responses: createEmptyAssessmentResponses(), + isComplete: false, + startedAt: new Date().toISOString(), + }; +} diff --git a/ai-readiness-accelerator/src/types/firm.types.ts b/ai-readiness-accelerator/src/types/firm.types.ts new file mode 100644 index 0000000..821602f --- /dev/null +++ b/ai-readiness-accelerator/src/types/firm.types.ts @@ -0,0 +1,137 @@ +/** + * Type definitions for law firm profile and configuration + * @module firm.types + */ + +/** + * Practice areas that a law firm may specialize in + */ +export type PracticeArea = + | 'bankruptcy' + | 'family-law' + | 'estate-planning' + | 'personal-injury' + | 'civil-litigation' + | 'criminal-defense' + | 'immigration' + | 'real-estate' + | 'other'; + +/** + * Practice management software tools commonly used by law firms + */ +export type PracticeManagementTool = + | 'clio' + | 'mycase' + | 'practicepanther' + | 'smokeball' + | 'filevine' + | 'cosmolex' + | 'none' + | 'other'; + +/** + * Maturity levels for firm operations based on capability maturity model + * - chaotic: No defined processes, ad-hoc operations + * - informal: Some processes exist but are inconsistently followed + * - defined: Documented processes that are generally followed + * - consistent: Standardized processes with regular compliance + * - optimized: Continuous improvement with metrics-driven optimization + */ +export type OperationsMaturity = + | 'chaotic' + | 'informal' + | 'defined' + | 'consistent' + | 'optimized'; + +/** + * Complete profile information for a law firm + * Used to customize assessment questions and recommendations + */ +export interface FirmProfile { + /** Legal name of the firm */ + firmName: string; + + /** Primary practice areas the firm handles */ + practiceAreas: PracticeArea[]; + + /** Number of attorneys (partners and associates) */ + attorneyCount: number; + + /** Number of paralegals and legal assistants */ + paralegalCount: number; + + /** Number of intake and client services staff */ + intakeStaffCount: number; + + /** Number of administrative and support staff */ + adminCount: number; + + /** Current practice management software in use */ + practiceManagement: PracticeManagementTool; + + /** Document management system name (free text, e.g., "NetDocuments", "iManage", "None") */ + documentManagement: string; + + /** Self-assessed current operational maturity level */ + currentOperationsMaturity: OperationsMaturity; +} + +/** + * Display labels for practice areas + */ +export const PRACTICE_AREA_LABELS: Record = { + 'bankruptcy': 'Bankruptcy', + 'family-law': 'Family Law', + 'estate-planning': 'Estate Planning', + 'personal-injury': 'Personal Injury', + 'civil-litigation': 'Civil Litigation', + 'criminal-defense': 'Criminal Defense', + 'immigration': 'Immigration', + 'real-estate': 'Real Estate', + 'other': 'Other', +}; + +/** + * Display labels for practice management tools + */ +export const PRACTICE_MANAGEMENT_LABELS: Record = { + 'clio': 'Clio', + 'mycase': 'MyCase', + 'practicepanther': 'PracticePanther', + 'smokeball': 'Smokeball', + 'filevine': 'Filevine', + 'cosmolex': 'CosmoLex', + 'none': 'None', + 'other': 'Other', +}; + +/** + * Display labels and descriptions for operations maturity levels + */ +export const OPERATIONS_MATURITY_INFO: Record< + OperationsMaturity, + { label: string; description: string } +> = { + 'chaotic': { + label: 'Chaotic', + description: 'No defined processes, ad-hoc operations', + }, + 'informal': { + label: 'Informal', + description: 'Some processes exist but are inconsistently followed', + }, + 'defined': { + label: 'Defined', + description: 'Documented processes that are generally followed', + }, + 'consistent': { + label: 'Consistent', + description: 'Standardized processes with regular compliance', + }, + 'optimized': { + label: 'Optimized', + description: 'Continuous improvement with metrics-driven optimization', + }, +}; diff --git a/ai-readiness-accelerator/src/types/index.ts b/ai-readiness-accelerator/src/types/index.ts new file mode 100644 index 0000000..861b621 --- /dev/null +++ b/ai-readiness-accelerator/src/types/index.ts @@ -0,0 +1,143 @@ +/** + * Types for the AI Readiness Accelerator application + */ + +/** + * Represents a single response to an assessment question + */ +export interface QuestionResponse { + questionId: string; + value: number; // 1-5 scale +} + +/** + * Map of pillar IDs to their question responses + */ +export interface AssessmentResponses { + [pillarId: string]: QuestionResponse[]; +} + +/** + * Definition of an assessment pillar + */ +export interface PillarDefinition { + id: string; + name: string; + description?: string; + questions?: Question[]; +} + +/** + * Assessment question definition + */ +export interface Question { + id: string; + text: string; + category?: string; +} + +/** + * Status levels for individual pillars + */ +export type PillarStatus = 'critical' | 'needs-work' | 'adequate' | 'strong' | 'excellent'; + +/** + * Overall readiness levels + */ +export type ReadinessLevel = 'not-ready' | 'foundational' | 'developing' | 'ready' | 'optimized'; + +/** + * Individual pillar score result + */ +export interface PillarScore { + id: string; + name: string; + score: number; + status: PillarStatus; +} + +/** + * Complete scoring results for all pillars + */ +export interface PillarScores { + pillars: PillarScore[]; + overall: number; + readinessLevel: ReadinessLevel; +} + +/** + * Strength or gap item with description + */ +export interface StrengthGapItem { + pillarId: string; + pillarName: string; + score: number; + description: string; +} + +/** + * Identified strengths and gaps from assessment + */ +export interface StrengthsGaps { + strengths: StrengthGapItem[]; + gaps: StrengthGapItem[]; +} + +/** + * Law firm profile information + */ +export interface FirmProfile { + /** Name of the law firm */ + name: string; + /** Practice areas the firm specializes in */ + practiceAreas: string[]; + /** Size category of the firm */ + size: 'Solo' | 'Small' | 'Mid-size' | 'Large' | 'Enterprise'; + /** Number of attorneys (optional) */ + attorneyCount?: number; + /** Current technology tools in use */ + currentTools: string[]; + /** Primary goals for AI adoption (optional) */ + aiGoals?: string[]; +} + +/** + * Executive summary generated by AI analysis + */ +export interface ExecutiveSummary { + /** 2-3 sentence executive summary of the assessment */ + overallAssessment: string; + /** 3-4 bullet points of main observations */ + keyFindings: string[]; + /** 3 specific next steps ordered by importance */ + priorityActions: string[]; + /** Single most important action for the next 30 days */ + recommendedFirstMove: string; + /** 2-3 risks to be aware of */ + riskConsiderations: string[]; +} + +/** + * API response wrapper for Gemini + */ +export interface GeminiResponse { + candidates: Array<{ + content: { + parts: Array<{ + text: string; + }>; + }; + finishReason: string; + }>; +} + +/** + * Error response from Gemini API + */ +export interface GeminiError { + error: { + code: number; + message: string; + status: string; + }; +} diff --git a/ai-readiness-accelerator/src/types/results.types.ts b/ai-readiness-accelerator/src/types/results.types.ts new file mode 100644 index 0000000..6d1ac89 --- /dev/null +++ b/ai-readiness-accelerator/src/types/results.types.ts @@ -0,0 +1,308 @@ +/** + * Type definitions for assessment results and dashboard + * @module results.types + */ + +import type { PillarId } from './assessment.types'; + +/** + * Overall AI readiness level based on assessment scores + * - not-ready: Significant gaps that must be addressed before AI adoption + * - foundational: Basic capabilities in place, major improvements needed + * - developing: Making progress, some areas need attention + * - ready: Well-positioned for AI adoption with minor improvements + * - optimized: Fully prepared for advanced AI implementations + */ +export type ReadinessLevel = + | 'not-ready' + | 'foundational' + | 'developing' + | 'ready' + | 'optimized'; + +/** + * Detailed information about a readiness level for display + */ +export interface ReadinessLevelInfo { + /** The readiness level identifier */ + level: ReadinessLevel; + + /** Human-readable label */ + label: string; + + /** Score range that maps to this level [min, max] */ + scoreRange: [number, number]; + + /** Detailed description of what this level means */ + description: string; + + /** CSS color class or hex code for visual representation */ + color: string; +} + +/** + * Status classification for individual pillar scores + * - critical: Immediate attention required (0-20%) + * - needs-work: Significant improvement needed (21-40%) + * - adequate: Meets basic requirements (41-60%) + * - strong: Good capabilities (61-80%) + * - excellent: Best-in-class (81-100%) + */ +export type PillarStatus = + | 'critical' + | 'needs-work' + | 'adequate' + | 'strong' + | 'excellent'; + +/** + * Individual question score within a pillar + */ +export interface QuestionScore { + /** Question identifier */ + questionId: string; + + /** Achieved score */ + score: number; + + /** Maximum possible score */ + maxScore: number; + + /** Category the question belongs to */ + category: string; +} + +/** + * Calculated score and status for a single pillar + */ +export interface PillarScore { + /** Identifier of the pillar */ + pillarId: PillarId; + + /** Display name of the pillar */ + pillarName: string; + + /** Calculated score for this pillar */ + score: number; + + /** Maximum possible score for this pillar */ + maxScore: number; + + /** Status classification based on score percentage */ + status: PillarStatus; + + /** Individual question scores for detailed breakdown */ + questionScores: QuestionScore[]; +} + +/** + * Complete scoring results across all pillars + */ +export interface PillarScores { + /** Individual scores for each pillar */ + pillars: PillarScore[]; + + /** Overall composite score (0-100) */ + overall: number; + + /** Determined readiness level based on overall score */ + readinessLevel: ReadinessLevel; +} + +/** + * Identified strength or gap from the assessment + */ +export interface StrengthGap { + /** Pillar this strength/gap relates to */ + pillarId: PillarId; + + /** Display name of the pillar */ + pillarName: string; + + /** Score percentage (0-100) */ + score: number; + + /** Descriptive text explaining the strength or gap */ + description: string; +} + +/** + * Collection of identified strengths and gaps + */ +export interface StrengthsGaps { + /** Top-performing areas */ + strengths: StrengthGap[]; + + /** Areas needing improvement */ + gaps: StrengthGap[]; +} + +/** + * Executive summary of assessment results + */ +export interface ExecutiveSummary { + /** High-level assessment narrative (2-3 sentences) */ + overallAssessment: string; + + /** Key findings from the assessment (3-5 items) */ + keyFindings: string[]; + + /** Recommended priority actions (3-5 items) */ + priorityActions: string[]; + + /** Single recommended first step to begin AI journey */ + recommendedFirstMove: string; + + /** Risk factors to consider during AI adoption */ + riskConsiderations: string[]; +} + +/** + * Individual task within a roadmap phase + */ +export interface RoadmapTask { + /** Brief title of the task */ + title: string; + + /** Detailed description of what needs to be done */ + description: string; + + /** Responsible party or role (e.g., "IT Lead", "Managing Partner") */ + owner: string; + + /** Priority level for sequencing */ + priority: 'critical' | 'high' | 'medium' | 'low'; + + /** Related pillar if applicable */ + pillarId?: PillarId; +} + +/** + * Phase within the implementation roadmap + */ +export interface RoadmapPhase { + /** Phase number (1-based) */ + phase: number; + + /** High-level objective for this phase */ + objective: string; + + /** Tasks to complete in this phase */ + tasks: RoadmapTask[]; + + /** Measurable criteria for phase completion */ + successCriteria: string[]; +} + +/** + * Complete implementation roadmap + */ +export interface Roadmap { + /** Ordered phases of implementation */ + phases: RoadmapPhase[]; + + /** Firm name this roadmap was generated for */ + generatedFor: string; +} + +/** + * Readiness level configuration data + */ +export const READINESS_LEVELS: ReadinessLevelInfo[] = [ + { + level: 'not-ready', + label: 'Not Ready', + scoreRange: [0, 20], + description: + 'Significant foundational gaps exist that must be addressed before AI adoption. Focus on establishing basic processes and data practices.', + color: '#dc2626', // red-600 + }, + { + level: 'foundational', + label: 'Foundational', + scoreRange: [21, 40], + description: + 'Basic capabilities are in place but major improvements are needed. Prioritize process documentation and data organization.', + color: '#ea580c', // orange-600 + }, + { + level: 'developing', + label: 'Developing', + scoreRange: [41, 60], + description: + 'Making solid progress toward AI readiness. Some areas need focused attention before implementing advanced AI tools.', + color: '#ca8a04', // yellow-600 + }, + { + level: 'ready', + label: 'Ready', + scoreRange: [61, 80], + description: + 'Well-positioned for AI adoption. Minor improvements will enhance success. Consider starting with targeted AI implementations.', + color: '#16a34a', // green-600 + }, + { + level: 'optimized', + label: 'Optimized', + scoreRange: [81, 100], + description: + 'Fully prepared for advanced AI implementations. Strong foundation across all pillars enables sophisticated AI adoption.', + color: '#0891b2', // cyan-600 + }, +]; + +/** + * Pillar status configuration data + */ +export const PILLAR_STATUS_INFO: Record< + PillarStatus, + { label: string; color: string; description: string } +> = { + critical: { + label: 'Critical', + color: '#dc2626', + description: 'Immediate attention required', + }, + 'needs-work': { + label: 'Needs Work', + color: '#ea580c', + description: 'Significant improvement needed', + }, + adequate: { + label: 'Adequate', + color: '#ca8a04', + description: 'Meets basic requirements', + }, + strong: { + label: 'Strong', + color: '#16a34a', + description: 'Good capabilities in place', + }, + excellent: { + label: 'Excellent', + color: '#0891b2', + description: 'Best-in-class capabilities', + }, +}; + +/** + * Determines pillar status based on score percentage + */ +export function getPillarStatus(scorePercent: number): PillarStatus { + if (scorePercent <= 20) return 'critical'; + if (scorePercent <= 40) return 'needs-work'; + if (scorePercent <= 60) return 'adequate'; + if (scorePercent <= 80) return 'strong'; + return 'excellent'; +} + +/** + * Determines readiness level based on overall score + */ +export function getReadinessLevel(overallScore: number): ReadinessLevel { + if (overallScore <= 20) return 'not-ready'; + if (overallScore <= 40) return 'foundational'; + if (overallScore <= 60) return 'developing'; + if (overallScore <= 80) return 'ready'; + return 'optimized'; +} diff --git a/ai-readiness-accelerator/src/types/roi.types.ts b/ai-readiness-accelerator/src/types/roi.types.ts new file mode 100644 index 0000000..6a38bc0 --- /dev/null +++ b/ai-readiness-accelerator/src/types/roi.types.ts @@ -0,0 +1,334 @@ +/** + * Type definitions for ROI calculator functionality + * @module roi.types + */ + +/** + * Input parameters for ROI calculation + * All monetary values are in USD + */ +export interface ROIInputs { + /** + * Number of new client intakes processed per week + * Used to calculate time savings from automated intake + */ + weeklyIntakeVolume: number; + + /** + * Average time spent per intake in minutes + * Includes data entry, initial consultation scheduling, conflict checks + */ + avgMinutesPerIntake: number; + + /** + * Number of document drafting tasks per week + * Includes contracts, pleadings, letters, and other standard documents + */ + weeklyDraftingTasks: number; + + /** + * Average time spent per drafting task in minutes + * From initial template selection to final review + */ + avgMinutesPerDraft: number; + + /** + * Fully-loaded hourly cost for staff performing these tasks + * Should include salary, benefits, overhead + */ + staffHourlyRate: number; + + /** + * Billable rate for attorney time in USD/hour + * Used to calculate value of freed-up attorney capacity + */ + billableRate: number; + + /** + * Expected percentage of time savings from AI implementation + * Typical range: 20-50% + */ + projectedTimeSavingsPercent: number; + + /** + * Expected percentage reduction in errors/rework + * Typical range: 30-60% + */ + projectedErrorReductionPercent: number; + + /** + * One-time implementation cost (training, setup, consulting) + * In USD + */ + implementationCost: number; + + /** + * Monthly subscription/licensing cost for AI tools + * In USD per month + */ + monthlyToolCost: number; +} + +/** + * Projected ROI values for a single scenario + */ +export interface ROIProjection { + /** + * Total hours saved annually from AI implementation + */ + annualHoursSaved: number; + + /** + * Annual savings from reduced labor costs + * Calculated from hours saved * staff hourly rate + */ + annualLaborSavings: number; + + /** + * Annual value of increased capacity for billable work + * Calculated from freed attorney hours * billable rate + */ + annualCapacityValue: number; + + /** + * Total annual benefit (labor savings + capacity value) + */ + totalAnnualBenefit: number; + + /** + * Net value in year 1 after subtracting implementation and tool costs + */ + year1NetValue: number; + + /** + * Number of months to recoup implementation investment + */ + paybackMonths: number; + + /** + * Three-year return on investment percentage + * ((3-year benefit - 3-year cost) / 3-year cost) * 100 + */ + threeYearROI: number; +} + +/** + * Complete ROI breakdown with multiple scenarios + */ +export interface ROIBreakdown { + /** Input parameters used for calculation */ + inputs: ROIInputs; + + /** + * Conservative estimate (lower bound) + * Uses 70% of projected savings percentages + */ + conservative: ROIProjection; + + /** + * Moderate estimate (expected case) + * Uses 100% of projected savings percentages + */ + moderate: ROIProjection; + + /** + * Optimistic estimate (upper bound) + * Uses 130% of projected savings percentages + */ + optimistic: ROIProjection; +} + +/** + * Default ROI input values for small law firms + */ +export const DEFAULT_ROI_INPUTS: ROIInputs = { + weeklyIntakeVolume: 10, + avgMinutesPerIntake: 30, + weeklyDraftingTasks: 15, + avgMinutesPerDraft: 45, + staffHourlyRate: 35, + billableRate: 250, + projectedTimeSavingsPercent: 35, + projectedErrorReductionPercent: 40, + implementationCost: 5000, + monthlyToolCost: 500, +}; + +/** + * ROI input field metadata for form generation + */ +export interface ROIInputField { + key: keyof ROIInputs; + label: string; + description: string; + unit: string; + min: number; + max: number; + step: number; +} + +/** + * Field definitions for ROI calculator form + */ +export const ROI_INPUT_FIELDS: ROIInputField[] = [ + { + key: 'weeklyIntakeVolume', + label: 'Weekly Intake Volume', + description: 'Number of new client intakes per week', + unit: 'intakes/week', + min: 1, + max: 200, + step: 1, + }, + { + key: 'avgMinutesPerIntake', + label: 'Time per Intake', + description: 'Average minutes spent per intake', + unit: 'minutes', + min: 5, + max: 120, + step: 5, + }, + { + key: 'weeklyDraftingTasks', + label: 'Weekly Drafting Tasks', + description: 'Number of documents drafted per week', + unit: 'documents/week', + min: 1, + max: 100, + step: 1, + }, + { + key: 'avgMinutesPerDraft', + label: 'Time per Draft', + description: 'Average minutes per document draft', + unit: 'minutes', + min: 10, + max: 240, + step: 5, + }, + { + key: 'staffHourlyRate', + label: 'Staff Hourly Rate', + description: 'Fully-loaded cost per hour for staff', + unit: '$/hour', + min: 15, + max: 150, + step: 5, + }, + { + key: 'billableRate', + label: 'Attorney Billable Rate', + description: 'Billable rate for attorney time', + unit: '$/hour', + min: 100, + max: 1000, + step: 25, + }, + { + key: 'projectedTimeSavingsPercent', + label: 'Time Savings', + description: 'Expected percentage of time saved with AI', + unit: '%', + min: 10, + max: 70, + step: 5, + }, + { + key: 'projectedErrorReductionPercent', + label: 'Error Reduction', + description: 'Expected reduction in errors/rework', + unit: '%', + min: 10, + max: 80, + step: 5, + }, + { + key: 'implementationCost', + label: 'Implementation Cost', + description: 'One-time setup, training, and consulting', + unit: '$', + min: 0, + max: 50000, + step: 500, + }, + { + key: 'monthlyToolCost', + label: 'Monthly Tool Cost', + description: 'Monthly AI tool subscription cost', + unit: '$/month', + min: 0, + max: 5000, + step: 50, + }, +]; + +/** + * Calculates ROI projection for given inputs and savings multiplier + */ +export function calculateROIProjection( + inputs: ROIInputs, + savingsMultiplier: number = 1.0 +): ROIProjection { + const adjustedTimeSavings = + inputs.projectedTimeSavingsPercent * savingsMultiplier; + + // Calculate weekly time spent + const weeklyIntakeMinutes = + inputs.weeklyIntakeVolume * inputs.avgMinutesPerIntake; + const weeklyDraftingMinutes = + inputs.weeklyDraftingTasks * inputs.avgMinutesPerDraft; + const totalWeeklyMinutes = weeklyIntakeMinutes + weeklyDraftingMinutes; + + // Calculate annual hours and savings + const annualMinutes = totalWeeklyMinutes * 52; + const annualHours = annualMinutes / 60; + const annualHoursSaved = annualHours * (adjustedTimeSavings / 100); + + const annualLaborSavings = annualHoursSaved * inputs.staffHourlyRate; + const annualCapacityValue = annualHoursSaved * 0.3 * inputs.billableRate; // 30% of saved time becomes billable + + const totalAnnualBenefit = annualLaborSavings + annualCapacityValue; + + // Calculate costs + const annualToolCost = inputs.monthlyToolCost * 12; + const year1TotalCost = inputs.implementationCost + annualToolCost; + const year1NetValue = totalAnnualBenefit - year1TotalCost; + + // Calculate payback period + const monthlyBenefit = totalAnnualBenefit / 12; + const paybackMonths = + monthlyBenefit > 0 + ? Math.ceil(inputs.implementationCost / monthlyBenefit) + : 999; + + // Calculate 3-year ROI + const threeYearBenefit = totalAnnualBenefit * 3; + const threeYearCost = inputs.implementationCost + annualToolCost * 3; + const threeYearROI = + threeYearCost > 0 + ? ((threeYearBenefit - threeYearCost) / threeYearCost) * 100 + : 0; + + return { + annualHoursSaved: Math.round(annualHoursSaved), + annualLaborSavings: Math.round(annualLaborSavings), + annualCapacityValue: Math.round(annualCapacityValue), + totalAnnualBenefit: Math.round(totalAnnualBenefit), + year1NetValue: Math.round(year1NetValue), + paybackMonths, + threeYearROI: Math.round(threeYearROI), + }; +} + +/** + * Calculates complete ROI breakdown with all three scenarios + */ +export function calculateROIBreakdown(inputs: ROIInputs): ROIBreakdown { + return { + inputs, + conservative: calculateROIProjection(inputs, 0.7), + moderate: calculateROIProjection(inputs, 1.0), + optimistic: calculateROIProjection(inputs, 1.3), + }; +} diff --git a/ai-readiness-accelerator/tailwind.config.js b/ai-readiness-accelerator/tailwind.config.js new file mode 100644 index 0000000..0ba59ab --- /dev/null +++ b/ai-readiness-accelerator/tailwind.config.js @@ -0,0 +1,30 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: { + colors: { + primary: { + 50: '#eef2ff', + 100: '#e0e7ff', + 200: '#c7d2fe', + 300: '#a5b4fc', + 400: '#818cf8', + 500: '#6366f1', + 600: '#4f46e5', + 700: '#4338ca', + 800: '#3730a3', + 900: '#312e81', + 950: '#1e1b4b', + }, + }, + fontFamily: { + sans: ['Inter', 'system-ui', 'sans-serif'], + }, + }, + }, + plugins: [], +} diff --git a/ai-readiness-accelerator/tsconfig.json b/ai-readiness-accelerator/tsconfig.json new file mode 100644 index 0000000..5413626 --- /dev/null +++ b/ai-readiness-accelerator/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/ai-readiness-accelerator/tsconfig.node.json b/ai-readiness-accelerator/tsconfig.node.json new file mode 100644 index 0000000..97ede7e --- /dev/null +++ b/ai-readiness-accelerator/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/ai-readiness-accelerator/vite.config.ts b/ai-readiness-accelerator/vite.config.ts new file mode 100644 index 0000000..9494ffe --- /dev/null +++ b/ai-readiness-accelerator/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + server: { + port: 3000, + open: true + } +}) From af35d89eb664acee9fb706753804c15da498e33c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Feb 2026 13:28:10 +0000 Subject: [PATCH 3/7] Add React components and hooks - work in progress Components added: - Landing: Hero, ValueProposition, PillarOverview, CTASection - Assessment: LikertScale, AssessmentNavigation, QuestionCard, PillarSection - Results: ScoreSummaryCard, RadarChartSection - Layout: Header, Footer, Container - Shared: ErrorBoundary Hooks added: - useLocalStorage, useAssessment, useResults, useROICalculator Main App component created with view routing. https://claude.ai/code/session_019DXrMJ4k9ujmA3BDgUNzHn --- ai-readiness-accelerator/package-lock.json | 4515 +++++++++++++++++ ai-readiness-accelerator/src/App.tsx | 128 + .../assessment/AssessmentNavigation.tsx | 85 + .../src/components/assessment/LikertScale.tsx | 171 + .../components/assessment/PillarSection.tsx | 121 + .../components/assessment/QuestionCard.tsx | 177 + .../src/components/landing/CTASection.tsx | 50 + .../src/components/landing/Hero.tsx | 57 + .../src/components/landing/PillarOverview.tsx | 90 + .../components/landing/ValueProposition.tsx | 72 + .../src/components/landing/index.ts | 9 + .../src/components/layout/Container.tsx | 41 + .../src/components/layout/Footer.tsx | 19 + .../src/components/layout/Header.tsx | 48 + .../src/components/layout/index.ts | 7 + .../components/results/RadarChartSection.tsx | 176 + .../components/results/ScoreSummaryCard.tsx | 143 + .../src/components/shared/ErrorBoundary.tsx | 103 + .../src/components/shared/index.ts | 2 + ai-readiness-accelerator/src/hooks/index.ts | 39 + .../src/hooks/useAssessment.ts | 458 ++ .../src/hooks/useGeminiSummary.ts | 280 + .../src/hooks/useLocalStorage.ts | 161 + .../src/hooks/useROICalculator.ts | 260 + .../src/hooks/useResults.ts | 215 + 25 files changed, 7427 insertions(+) create mode 100644 ai-readiness-accelerator/package-lock.json create mode 100644 ai-readiness-accelerator/src/App.tsx create mode 100644 ai-readiness-accelerator/src/components/assessment/AssessmentNavigation.tsx create mode 100644 ai-readiness-accelerator/src/components/assessment/LikertScale.tsx create mode 100644 ai-readiness-accelerator/src/components/assessment/PillarSection.tsx create mode 100644 ai-readiness-accelerator/src/components/assessment/QuestionCard.tsx create mode 100644 ai-readiness-accelerator/src/components/landing/CTASection.tsx create mode 100644 ai-readiness-accelerator/src/components/landing/Hero.tsx create mode 100644 ai-readiness-accelerator/src/components/landing/PillarOverview.tsx create mode 100644 ai-readiness-accelerator/src/components/landing/ValueProposition.tsx create mode 100644 ai-readiness-accelerator/src/components/landing/index.ts create mode 100644 ai-readiness-accelerator/src/components/layout/Container.tsx create mode 100644 ai-readiness-accelerator/src/components/layout/Footer.tsx create mode 100644 ai-readiness-accelerator/src/components/layout/Header.tsx create mode 100644 ai-readiness-accelerator/src/components/layout/index.ts create mode 100644 ai-readiness-accelerator/src/components/results/RadarChartSection.tsx create mode 100644 ai-readiness-accelerator/src/components/results/ScoreSummaryCard.tsx create mode 100644 ai-readiness-accelerator/src/components/shared/ErrorBoundary.tsx create mode 100644 ai-readiness-accelerator/src/components/shared/index.ts create mode 100644 ai-readiness-accelerator/src/hooks/index.ts create mode 100644 ai-readiness-accelerator/src/hooks/useAssessment.ts create mode 100644 ai-readiness-accelerator/src/hooks/useGeminiSummary.ts create mode 100644 ai-readiness-accelerator/src/hooks/useLocalStorage.ts create mode 100644 ai-readiness-accelerator/src/hooks/useROICalculator.ts create mode 100644 ai-readiness-accelerator/src/hooks/useResults.ts diff --git a/ai-readiness-accelerator/package-lock.json b/ai-readiness-accelerator/package-lock.json new file mode 100644 index 0000000..6c0323d --- /dev/null +++ b/ai-readiness-accelerator/package-lock.json @@ -0,0 +1,4515 @@ +{ + "name": "ai-readiness-accelerator", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ai-readiness-accelerator", + "version": "1.0.0", + "dependencies": { + "lucide-react": "^0.344.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "recharts": "^2.12.0" + }, + "devDependencies": { + "@types/react": "^18.2.55", + "@types/react-dom": "^18.2.19", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.17", + "eslint": "^8.56.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "typescript": "^5.3.3", + "vite": "^5.1.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001767", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.344.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.344.0.tgz", + "integrity": "sha512-6YyBnn91GB45VuVT96bYCOKElbJzUHqp65vX8cDcu55MQL9T969v4dhGClpljamuI/+KMO9P6w9Acq1CVQGvIQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/ai-readiness-accelerator/src/App.tsx b/ai-readiness-accelerator/src/App.tsx new file mode 100644 index 0000000..a10afa4 --- /dev/null +++ b/ai-readiness-accelerator/src/App.tsx @@ -0,0 +1,128 @@ +import { useState, useCallback } from 'react'; +import { Header, Footer } from './components/layout'; +import { ErrorBoundary } from './components/shared'; +import { LandingView, AssessmentView, ResultsView } from './views'; +import type { AssessmentResponses } from './types/assessment.types'; +import type { FirmProfile } from './types/firm.types'; + +/** + * View state for the application + * - landing: Initial landing page with value proposition + * - assessment: Multi-step assessment questionnaire + * - results: Assessment results and recommendations + */ +type ViewState = 'landing' | 'assessment' | 'results'; + +/** + * Data collected during the assessment process + */ +interface AssessmentData { + responses: AssessmentResponses; + firmProfile: FirmProfile; +} + +/** + * Main application component for the AI Readiness Accelerator + * Manages view routing and assessment state + */ +function App() { + // Current view state + const [currentView, setCurrentView] = useState('landing'); + + // Assessment data collected during the assessment process + const [assessmentData, setAssessmentData] = useState(null); + + /** + * Navigate to the assessment view + */ + const handleStartAssessment = useCallback(() => { + setCurrentView('assessment'); + }, []); + + /** + * Handle assessment completion - save data and navigate to results + */ + const handleAssessmentComplete = useCallback( + (responses: AssessmentResponses, firmProfile: FirmProfile) => { + setAssessmentData({ responses, firmProfile }); + setCurrentView('results'); + }, + [] + ); + + /** + * Reset application state and return to landing page + */ + const handleReset = useCallback(() => { + setAssessmentData(null); + setCurrentView('landing'); + }, []); + + /** + * Navigate back from assessment to landing page + */ + const handleBack = useCallback(() => { + setCurrentView('landing'); + }, []); + + /** + * Render the appropriate view based on current state + */ + const renderView = () => { + switch (currentView) { + case 'landing': + return ; + + case 'assessment': + return ( + + ); + + case 'results': + if (!assessmentData) { + // If somehow we're on results without data, go back to landing + setCurrentView('landing'); + return null; + } + return ( + + ); + + default: + return ; + } + }; + + return ( + +
+ {/* Header - always visible, shows reset button when not on landing */} +
+ + {/* Main content area */} +
+ {renderView()} +
+ + {/* Footer - always visible */} +
+
+
+ ); +} + +export default App; diff --git a/ai-readiness-accelerator/src/components/assessment/AssessmentNavigation.tsx b/ai-readiness-accelerator/src/components/assessment/AssessmentNavigation.tsx new file mode 100644 index 0000000..2bddd02 --- /dev/null +++ b/ai-readiness-accelerator/src/components/assessment/AssessmentNavigation.tsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { ChevronLeft, ChevronRight, Send, Save } from 'lucide-react'; +import { Button } from '../ui'; + +export interface AssessmentNavigationProps { + /** Whether the Previous button should be enabled */ + canGoPrev: boolean; + /** Whether the Next button should be enabled */ + canGoNext: boolean; + /** Whether this is the last step (shows Submit instead of Next) */ + isLastStep: boolean; + /** Callback for Previous button */ + onPrev: () => void; + /** Callback for Next button */ + onNext: () => void; + /** Callback for Submit button (only used on last step) */ + onSubmit: () => void; + /** Whether submission is in progress */ + isSubmitting?: boolean; +} + +/** + * AssessmentNavigation provides navigation controls for the assessment flow. + * Shows Previous/Next buttons with Submit on the final step. + * Includes an auto-save indicator. + */ +export const AssessmentNavigation: React.FC = ({ + canGoPrev, + canGoNext, + isLastStep, + onPrev, + onNext, + onSubmit, + isSubmitting = false, +}) => { + return ( +
+ {/* Auto-save indicator */} +
+
+ + {/* Navigation buttons */} +
+ {/* Previous button */} + + + {/* Next or Submit button */} + {isLastStep ? ( + + ) : ( + + )} +
+
+ ); +}; + +export default AssessmentNavigation; diff --git a/ai-readiness-accelerator/src/components/assessment/LikertScale.tsx b/ai-readiness-accelerator/src/components/assessment/LikertScale.tsx new file mode 100644 index 0000000..dbd9dd4 --- /dev/null +++ b/ai-readiness-accelerator/src/components/assessment/LikertScale.tsx @@ -0,0 +1,171 @@ +import React, { useId } from 'react'; + +/** + * Likert scale labels for the maturity assessment + * 0 = Non-existent, 5 = Optimized + */ +export const MATURITY_LABELS: Record = { + 0: 'Non-existent', + 1: 'Ad-hoc', + 2: 'Defined', + 3: 'Followed', + 4: 'Consistent', + 5: 'Optimized', +}; + +export interface LikertScaleProps { + /** Current selected value (0-5 or undefined if not answered) */ + value: 0 | 1 | 2 | 3 | 4 | 5 | undefined; + /** Callback when value changes */ + onChange: (value: 0 | 1 | 2 | 3 | 4 | 5) => void; + /** Optional custom labels (defaults to MATURITY_LABELS) */ + labels?: Record; + /** Unique name for the radio group */ + name?: string; + /** Whether the scale is disabled */ + disabled?: boolean; +} + +/** + * LikertScale component renders a 6-point scale (0-5) as radio buttons. + * Used for assessment questions to rate maturity levels. + * Fully accessible with proper radio group semantics. + */ +export const LikertScale: React.FC = ({ + value, + onChange, + labels = MATURITY_LABELS, + name, + disabled = false, +}) => { + const generatedId = useId(); + const groupName = name || `likert-${generatedId}`; + const groupLabelId = `${groupName}-label`; + + const scaleValues = [0, 1, 2, 3, 4, 5] as const; + + return ( +
+ {/* Screen reader only label */} + + Rate on a scale from 0 (Non-existent) to 5 (Optimized) + + + {/* Desktop layout - horizontal */} +
+ {scaleValues.map((scaleValue) => { + const isSelected = value === scaleValue; + const labelText = labels[scaleValue] || String(scaleValue); + const inputId = `${groupName}-${scaleValue}`; + + return ( + + ); + })} +
+ + {/* Mobile layout - stacked */} +
+ {scaleValues.map((scaleValue) => { + const isSelected = value === scaleValue; + const labelText = labels[scaleValue] || String(scaleValue); + const inputId = `${groupName}-mobile-${scaleValue}`; + + return ( + + ); + })} +
+
+ ); +}; + +export default LikertScale; diff --git a/ai-readiness-accelerator/src/components/assessment/PillarSection.tsx b/ai-readiness-accelerator/src/components/assessment/PillarSection.tsx new file mode 100644 index 0000000..8d4427a --- /dev/null +++ b/ai-readiness-accelerator/src/components/assessment/PillarSection.tsx @@ -0,0 +1,121 @@ +import React from 'react'; +import { + Workflow, + Database, + BookOpen, + Settings, + Shield, + TrendingUp, + type LucideIcon, +} from 'lucide-react'; +import type { PillarDefinition, Question } from '../../types'; +import { QuestionCard, type QuestionResponse } from './QuestionCard'; +import { ProgressBar } from '../ui'; + +/** + * Map of pillar icon names to Lucide components + */ +const ICON_MAP: Record = { + Workflow, + Database, + BookOpen, + Settings, + Shield, + TrendingUp, +}; + +export interface PillarSectionProps { + /** Pillar definition with questions */ + pillar: PillarDefinition; + /** Array of responses for this pillar's questions */ + responses: QuestionResponse[]; + /** Callback when a response changes */ + onResponseChange: (response: QuestionResponse) => void; +} + +/** + * PillarSection displays all questions for a single assessment pillar. + * Includes pillar header with icon, description, and progress indicator. + */ +export const PillarSection: React.FC = ({ + pillar, + responses, + onResponseChange, +}) => { + const questions = pillar.questions || []; + const answeredCount = responses.filter((r) => r.value !== undefined).length; + const totalCount = questions.length; + const progressPercent = totalCount > 0 ? (answeredCount / totalCount) * 100 : 0; + + // Get the icon component + const iconName = (pillar as { icon?: string }).icon || 'Settings'; + const IconComponent = ICON_MAP[iconName] || Settings; + + // Find response for a specific question + const getResponseForQuestion = (questionId: string): QuestionResponse | undefined => { + return responses.find((r) => r.questionId === questionId); + }; + + return ( +
+ {/* Pillar header */} +
+
+ {/* Icon */} +
+
+ + {/* Title and description */} +
+

{pillar.name}

+ {pillar.description && ( +

{pillar.description}

+ )} +
+
+ + {/* Progress indicator */} +
+
+ + Progress: {answeredCount} of {totalCount} questions answered + + + {Math.round(progressPercent)}% + +
+ +
+
+ + {/* Questions list */} +
+ {questions.map((question: Question, index: number) => ( +
+ +
+ ))} +
+ + {/* Empty state */} + {questions.length === 0 && ( +
+

No questions available for this pillar.

+
+ )} +
+ ); +}; + +export default PillarSection; diff --git a/ai-readiness-accelerator/src/components/assessment/QuestionCard.tsx b/ai-readiness-accelerator/src/components/assessment/QuestionCard.tsx new file mode 100644 index 0000000..2636757 --- /dev/null +++ b/ai-readiness-accelerator/src/components/assessment/QuestionCard.tsx @@ -0,0 +1,177 @@ +import React, { useState, useId } from 'react'; +import { HelpCircle, ChevronDown, ChevronUp, MessageSquare } from 'lucide-react'; +import type { Question } from '../../types'; +import { LikertScale } from './LikertScale'; + +export interface QuestionResponse { + questionId: string; + value: 0 | 1 | 2 | 3 | 4 | 5; + notes?: string; +} + +export interface QuestionCardProps { + /** The question to display */ + question: Question; + /** Current response (if any) */ + response: QuestionResponse | undefined; + /** Callback when the response changes */ + onChange: (response: QuestionResponse) => void; + /** Question number for display */ + questionNumber?: number; +} + +/** + * QuestionCard displays an individual assessment question with a Likert scale + * and an optional collapsible notes section. + */ +export const QuestionCard: React.FC = ({ + question, + response, + onChange, + questionNumber, +}) => { + const [showNotes, setShowNotes] = useState(Boolean(response?.notes)); + const [showTooltip, setShowTooltip] = useState(false); + const tooltipId = useId(); + const notesId = useId(); + + const handleValueChange = (value: 0 | 1 | 2 | 3 | 4 | 5) => { + onChange({ + questionId: question.id, + value, + notes: response?.notes, + }); + }; + + const handleNotesChange = (e: React.ChangeEvent) => { + if (response) { + onChange({ + ...response, + notes: e.target.value || undefined, + }); + } else { + // If no response yet but user types notes, don't create response + // Notes can only be saved with a value + } + }; + + const toggleNotes = () => { + setShowNotes(!showNotes); + }; + + return ( +
+ {/* Question header */} +
+
+ {questionNumber && ( + + {questionNumber} + + )} +
+
+

+ {question.text} +

+ {question.helpText && ( +
+ + {showTooltip && ( + + )} +
+ {question.category && ( + + {question.category} + + )} +
+
+
+ + {/* Likert scale */} +
+ +
+ + {/* Notes toggle and textarea */} +
+ + + {showNotes && ( +
+ +