diff --git a/app/globals.css b/app/globals.css index 554cbb4..81f050f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,38 +1,131 @@ @import 'tailwindcss'; :root { - --background: #171717; + --background: #0b0b0d; + --foreground: #eceae0; } @theme inline { + --color-bg: #0b0b0d; + --color-surface: #111115; + --color-surface2: #18181e; + --color-bdr: #26262e; + --color-accent: #f4a229; + --color-accent2: #ff6b35; + --color-ink: #eceae0; + --color-muted: #72706a; + --color-danger: #e84040; --color-background: var(--background); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); - --color-coffee-50: #f8f8f8; - --color-coffee-100: #f1eff0; - --color-coffee-200: #e6e2e4; - --color-coffee-300: #d8d2d5; - --color-coffee-400: #baafb5; - --color-coffee-500: #a0939a; - --color-coffee-600: #887a81; - --color-coffee-700: #70656b; - --color-coffee-800: #5f555a; - --color-coffee-900: #524a4e; - --color-coffee-950: #2a2528; - --transparent: #1717178d; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; + --font-sans: var(--font-syne-family); + --font-mono: var(--font-jetbrains-mono); + --font-syne: var(--font-syne-family); + --animate-fade-up-1: fade-up 0.6s ease forwards 0.2s; + --animate-fade-up-2: fade-up 0.7s ease forwards 0.4s; + --animate-fade-up-3: fade-up 0.7s ease forwards 0.6s; + --animate-fade-up-4: fade-up 0.7s ease forwards 0.8s; + --animate-fade-up-5: fade-up 0.7s ease forwards 1s; + --animate-fade-up-6: fade-up 0.7s ease forwards 1.2s; +} + +@keyframes fade-up { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); } } +/* Grid noise background */ +body::before { + content: ''; + position: fixed; + inset: 0; + background-image: + linear-gradient(#26262e 1px, transparent 1px), + linear-gradient(90deg, #26262e 1px, transparent 1px); + background-size: 40px 40px; + opacity: 0.25; + pointer-events: none; + z-index: 0; +} + +/* Scroll-triggered fade-in */ +.fade-in { + opacity: 0; + transform: translateY(16px); + transition: + opacity 0.6s ease, + transform 0.6s ease; +} +.fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +/* Photo frame — offset accent border */ +.photo-frame::after { + content: ''; + position: absolute; + inset: 0; + border: 1px solid #f4a229; + border-radius: 4px; + transform: translate(8px, 8px); + pointer-events: none; +} + +/* Project card — top accent line on hover */ +.project-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: #26262e; + transition: background 0.2s; +} +.project-card:hover::before { + background: #f4a229; +} + +/* Hero scroll — vertical trailing line */ +.hero-scroll::after { + content: ''; + display: block; + width: 1px; + height: 60px; + background: linear-gradient(to bottom, #72706a, transparent); + margin: 0.5rem auto 0; +} + +.stats-note code { + color: #f4a229; + background: rgba(244, 162, 41, 0.08); + padding: 0.1rem 0.3rem; + border-radius: 2px; +} + +::-webkit-scrollbar { + width: 6px; +} +::-webkit-scrollbar-track { + background: #0b0b0d; +} +::-webkit-scrollbar-thumb { + background: #26262e; + border-radius: 3px; +} +::-webkit-scrollbar-thumb:hover { + background: #72706a; +} + body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + overflow-x: hidden; } p { diff --git a/app/layout.tsx b/app/layout.tsx index 2682dc6..1296f3a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,16 +1,18 @@ import type { Metadata } from 'next'; -import { Geist, Geist_Mono } from 'next/font/google'; +import { JetBrains_Mono, Syne } from 'next/font/google'; import './globals.css'; import { Analytics } from '@vercel/analytics/next'; -const geistSans = Geist({ - variable: '--font-geist-sans', +const syne = Syne({ + variable: '--font-syne-family', subsets: ['latin'], + weight: ['400', '500', '600', '700', '800'], }); -const geistMono = Geist_Mono({ - variable: '--font-geist-mono', +const jetbrainsMono = JetBrains_Mono({ + variable: '--font-jetbrains-mono', subsets: ['latin'], + weight: ['300', '400', '500'], }); export const metadata: Metadata = { @@ -27,7 +29,7 @@ export default function RootLayout({ return ( {children} diff --git a/app/page.tsx b/app/page.tsx index 408365d..15828be 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,17 +1,23 @@ +import Nav from '../components/nav'; import Header from '../components/header'; -import Projects from '../components/projects'; import About from '../components/about'; +import Stats from '../components/stats'; +import Projects from '../components/projects'; +import Stack from '../components/stack'; +import Contact from '../components/contact'; +import Footer from '../components/footer'; export default function Home() { return ( -
-
-
-
- - -
-
+
+
); } diff --git a/components/about.tsx b/components/about.tsx index 1d106cb..f6e83f2 100644 --- a/components/about.tsx +++ b/components/about.tsx @@ -1,63 +1,91 @@ import Image from 'next/image'; +import FadeIn from './fade-in'; + +const skills = [ + 'JavaScript', + 'Next.js', + 'React', + 'React Native', + 'Playwright', + 'ISTQB', + 'MySQL', + 'REST APIs', + 'Git', +]; interface AboutProps { id: string; } -export default function about({ id }: AboutProps) { +export default function About({ id }: AboutProps) { return ( -
-
-
- {/* Image */} -
+
+ +
+ 01 +

+ About Me +

+
+
+
+ +
+
+
Portrait of Torun Alenius Wikström
+
- {/* Text */} -
-

About Me

- -
-

- I’m an ISTQB Certified QA professional with a background in full - stack development. I work mainly with JavaScript and Next.js, - and I’ve built and deployed both web and mobile applications, - including projects with database integrations, API connections, - and payment systems. -

- -

- I started learning web development through documentation, online - resources, and mentorship from a senior developer. After - building several projects and releasing a mobile app, I became - increasingly interested in quality, edge cases, and system - behavior. That curiosity led me to study software testing more - seriously and earn my ISTQB Foundation Level certification. -

- -

- Having written production code myself, I understand how features - are structured, where complexity hides, and how small changes - can affect the whole system. I now want to work in QA, combining - structured testing knowledge with hands on development - experience. -

+ +

+ Hey, I'm Torun Alenius Wikström — +

+

+ I'm an ISTQB Certified QA professional with a background in + full stack development. I work mainly with JavaScript and Next.js, + and I've built and deployed both web and mobile applications, + including projects with database integrations, API connections, and + payment systems. +

+

+ I started learning web development through documentation, online + resources, and mentorship from a senior developer. After building + several projects and releasing a mobile app, I became increasingly + interested in quality, edge cases, and system behavior. That + curiosity led me to study software testing more seriously and earn + my ISTQB Foundation Level certification. +

+

+ Having written production code myself, I understand how features are + structured, where complexity hides, and how small changes can affect + the whole system. I now want to work in QA, combining structured + testing knowledge with hands on development experience. +

+

+ Outside of tech, I design knitting patterns, which, much like + writing test cases, requires translating complex structures into + clear, logical, and reproducible instructions. +

-

- Outside of tech, I design knitting patterns, which, much like - writing test cases, requires translating complex structures into - clear, logical, and reproducible instructions. -

-
+
+ {skills.map((skill) => ( + + {skill} + + ))}
-
+
); diff --git a/components/contact.tsx b/components/contact.tsx new file mode 100644 index 0000000..ed1a0d5 --- /dev/null +++ b/components/contact.tsx @@ -0,0 +1,100 @@ +import Link from 'next/link'; +import FadeIn from './fade-in'; + +const contacts = [ + { + href: 'https://github.com/TorunW', + label: 'github.com/TorunW', + icon: '⎇', + external: true, + }, + { + href: 'https://linkedin.com/in/torun-wikström-a77011220', + label: 'linkedin.com/in/torun-wikström', + icon: 'in', + external: true, + boldIcon: true, + }, + { + href: '/cv', + label: 'Download Resume', + icon: '↓', + external: false, + }, +]; + +export default function Contact() { + return ( +
+ +
+ 05 +

+ Contact +

+
+
+
+ +
+ +

+ Let's build +
+ something +
+ worth shipping. +

+

+ Open to QA roles, full-time opportunities, and collaborations where + testing and development meet. +

+
+ + +
+ {contacts.map((item) => { + const className = + 'flex justify-between items-center px-5 py-4 border border-bdr rounded-[6px] no-underline text-muted text-[12px] transition hover:border-accent hover:text-accent hover:bg-accent/[0.04]'; + + const inner = ( + <> +
+ + {item.icon} + + {item.label} +
+ + + ); + + if (item.external) { + return ( + + {inner} + + ); + } + + return ( + + {inner} + + ); + })} +
+
+
+
+ ); +} diff --git a/components/fade-in.tsx b/components/fade-in.tsx new file mode 100644 index 0000000..a2d3062 --- /dev/null +++ b/components/fade-in.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { useEffect, useRef } from 'react'; + +export default function FadeIn({ + children, + className = '', +}: { + children: React.ReactNode; + className?: string; +}) { + const ref = useRef(null); + + useEffect(() => { + const el = ref.current; + if (!el) return; + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + } + }); + }, + { threshold: 0.1 }, + ); + + observer.observe(el); + return () => observer.disconnect(); + }, []); + + return ( +
+ {children} +
+ ); +} diff --git a/components/footer.tsx b/components/footer.tsx new file mode 100644 index 0000000..3927b69 --- /dev/null +++ b/components/footer.tsx @@ -0,0 +1,9 @@ +export default function Footer() { + return ( +
+ © {new Date().getFullYear()} Torun Wikström + {'///'} + Designed & built by hand +
+ ); +} diff --git a/components/header.tsx b/components/header.tsx index 18b6928..854e91e 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -1,61 +1,64 @@ -import { Github, Linkedin, NotepadText, User } from 'lucide-react'; -import Link from 'next/link'; - -export default function header() { +export default function Header() { return ( -
-
-
-

- Torun Alenius Wikström -

+
+
+ {'//'} junior QA engineer · ISTQB certified +
+ +

+ Torun +
+ Wikström +

-
-

- Web Developer & Software Tester -

+

+ Web developer & software tester. Junior QA Engineer (ISTQB + Certified) with a development background, focused on building and + validating reliable, well structured software systems. +

-

- Junior QA Engineer (ISTQB Certified) with a development - background, focused on building and validating reliable, well - structured software systems. -

-
- -
+
+ Scroll
); diff --git a/components/nav.tsx b/components/nav.tsx new file mode 100644 index 0000000..88eb1ad --- /dev/null +++ b/components/nav.tsx @@ -0,0 +1,52 @@ +import Link from 'next/link'; + +const navLinks = [ + { href: '#about', label: 'About' }, + { href: '#stats', label: 'Open Source' }, + { href: '#projects', label: 'Projects' }, + { href: '#stack', label: 'Stack' }, + { href: '#contact', label: 'Contact' }, +]; + +export default function Nav() { + return ( + + ); +} diff --git a/components/projects.tsx b/components/projects.tsx index f8c096f..bfde981 100644 --- a/components/projects.tsx +++ b/components/projects.tsx @@ -1,205 +1,169 @@ -import Image from 'next/image'; import Link from 'next/link'; +import FadeIn from './fade-in'; + +type Project = { + title: string; + category: string; + categoryTone: 'accent' | 'danger'; + description: string; + tags: string[]; + meta: string[]; + href: string; + secondaryHref?: string; + secondaryLabel?: string; +}; + +const projects: Project[] = [ + { + title: 'TicTacToe – Testing Playground', + category: 'QA / Testing', + categoryTone: 'danger', + description: + 'Built a TicTacToe web app with Next.js to practice structured software testing — requirements, test cases, white/black box techniques, and Playwright automation in progress.', + tags: ['Next.js', 'Playwright', 'Manual Testing', 'ISTQB'], + meta: ['✅ Test lifecycle', '⚡ Automation in progress'], + href: '/tictactoe-testing', + secondaryHref: 'https://github.com/TorunW/TicTacToe', + secondaryLabel: 'GitHub', + }, + { + title: 'Tempesta Bookmark Manager', + category: 'Open Source', + categoryTone: 'accent', + description: + 'Contributed testing to an open-source Rust bookmark manager — happy-path coverage for core features, and ongoing work to realign tests after a major refactor.', + tags: ['Rust', 'Testing', 'Open Source'], + meta: ['⎇ Fork with tests'], + href: 'https://github.com/TorunW/tempesta', + }, + { + title: 'NGO Organisation Website', + category: 'Web Dev', + categoryTone: 'accent', + description: + 'Migrated a full-stack NGO site from WordPress to Next.js and MySQL. Added Stripe donations, membership flows, an admin dashboard, and post-deploy workflow testing.', + tags: ['Next.js', 'MySQL', 'Stripe', 'Testing'], + meta: ['🌐 Live site'], + href: 'https://www.juedische-stimme.de/', + }, + { + title: 'Pixense Mobile Application', + category: 'Mobile', + categoryTone: 'accent', + description: + 'React Native Expo app with AI image generation (DALL·E 3) and Imagga tagging. Shipped to Google Play; demo available on Appetize.', + tags: ['React Native', 'Expo', 'OpenAI', 'Imagga'], + meta: ['📱 Mobile', '↗ Appetize demo'], + href: 'https://github.com/TorunW/pixense/', + secondaryHref: 'https://appetize.io/app/b_pszrvccbsdwxq4cxq6n2x5477e', + secondaryLabel: 'Appetize', + }, +]; + +function CategoryBadge({ + label, + tone, +}: { + label: string; + tone: 'accent' | 'danger'; +}) { + const classes = + tone === 'danger' + ? 'bg-danger/10 text-danger border-danger/20' + : 'bg-accent/10 text-accent border-accent/20'; -export default function projects() { return ( -
-

- Projects -

-
-
-
-
- image of tictactoe app -
-
-

- TicTacToe – Testing Playground -

-

- Built a TicTacToe web application using Next.js to apply - structured software testing practices in a controlled - environment. - - Defined functional requirements, created test cases and a test - plan, and applied both white box and black box static testing - techniques. The project focuses primarily on manual testing - methodology, with end to end test automation using Playwright - currently being implemented. - - Demonstrates the full manual testing lifecycle from requirement - analysis to execution, while progressively expanding into - automation practices. -

-
- - Testing showcase - - - Github - -
-
-
-
+ + {label} + + ); +} -
-
-
-

- Tempesta Bookmark Manager -

-

- Contributed testing work to an open source Rust based bookmark - management project. - - Performed early happy path testing of core features such as - bookmark creation and editing, and collaborated with developers - to verify expected behaviour.
- The project has undergone a major refactoring. As a result, the - existing tests require updates to match the new code structure. - I am currently reviewing the refactored architecture and - preparing updates to realign the automated tests. The repository - currently linked is my fork of the project, which showcases the - original testing implementation. - - This project provided experience working within an existing - codebase, validating functionality during development changes, - and understanding how refactoring impacts test suites. -

- - Github - -
-
- image -
-
+export default function Projects() { + return ( +
+ +
+ 03 +

+ Projects +

+
+
-
-
-
- image -
-
-

- NGO Organisation Website -

-

- Developed and migrated a full stack website from WordPress to a - custom Next.js and MySQL solution based on stakeholder - requirements gathered through planning meetings. Collaborated - with a senior developer who primarily focused on backend - architecture and acted as a technical mentor, while also - contributing to backend implementation. - - Implemented secure online donation functionality using Stripe, - improved membership and newsletter sign up workflows, and - introduced an administrative dashboard for managing content and - user data. Performed workflow based testing of payment - processes, authentication, and form validation following - deployment. - - Live site may experience occasional downtime due to external - factors. Public repository not available due to client - confidentiality and data protection requirements. Source code - available upon request. -

- - Website - -
-
-
+ +
+ {projects.map((project) => { + const isInternal = project.href.startsWith('/'); + const CardTag = isInternal ? Link : 'a'; + const cardProps = isInternal + ? { href: project.href } + : { + href: project.href, + target: '_blank' as const, + rel: 'noopener noreferrer', + }; -
-
-
-

- Pixense Mobile Application -

-

- Developed a mobile application using React Native Expo featuring - AI powered image generation and image recognition workflows. - Integrated OpenAI DALL E 3 for prompt based image generation and - the Imagga API for automated image tagging. - - Successfully managed the full release process to the Google Play - Store, including configuration, deployment, and compliance - requirements. The application was later removed due to ongoing - platform verification and maintenance demands that were not - feasible for a learning focused project. - - The project provided hands on experience with mobile - architecture, third party API integration, and production level - deployment workflows. A live demo is available via Appetize. -

-
- - Github - - + - Play around with the App on Appetize - +
+ + +
+
+ {project.title} +
+

+ {project.description} +

+
+ {project.tags.map((tag) => ( + + {tag} + + ))} +
+ + +
+ {project.meta.map((item) => ( + {item} + ))} + {project.secondaryHref && ( + + {project.secondaryLabel} ↗ + + )} +
-
-
- image -
-
+ ); + })}
-
-
+ +
); } diff --git a/components/stack.tsx b/components/stack.tsx new file mode 100644 index 0000000..6ecea30 --- /dev/null +++ b/components/stack.tsx @@ -0,0 +1,79 @@ +import FadeIn from './fade-in'; + +const stack = [ + { + title: 'Frontend', + items: [ + 'React / Next.js', + 'TypeScript / JavaScript', + 'React Native / Expo', + 'CSS / Tailwind', + ], + }, + { + title: 'Backend', + items: [ + 'Node.js', + 'MySQL', + 'REST APIs', + 'Stripe', + ], + }, + { + title: 'Testing & QA', + items: [ + 'ISTQB Foundation', + 'Playwright', + 'Manual test design', + 'White / black box', + ], + }, + { + title: 'DevOps & Tools', + items: [ + 'Git / GitHub', + 'Google Play release', + 'Vercel', + 'Linux / Bash', + ], + }, +]; + +export default function Stack() { + return ( +
+ +
+ 04 +

+ Tech Stack +

+
+
+
+ + +
+ {stack.map((column) => ( +
+

+ {column.title} +

+
+ {column.items.map((item) => ( +
+ + {item} +
+ ))} +
+
+ ))} +
+
+
+ ); +} diff --git a/components/stats.tsx b/components/stats.tsx new file mode 100644 index 0000000..0c9a476 --- /dev/null +++ b/components/stats.tsx @@ -0,0 +1,36 @@ +import FadeIn from './fade-in'; + +export default function Stats() { + return ( +
+ +
+ 02 +

+ Open Source +

+
+
+
+ + +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + GitHub Stats for TorunW + {/* eslint-disable-next-line @next/next/no-img-element */} + Top languages for TorunW +
+
+
+ ); +} diff --git a/package-lock.json b/package-lock.json index ceea636..4b06653 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3311,6 +3311,20 @@ "@svta/cml-utils": "1.0.1" } }, + "node_modules/@svta/cml-cta": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@svta/cml-cta/-/cml-cta-1.0.1.tgz", + "integrity": "sha512-jcXqNIPv26bmFxIOFh8/c3+6WLH4qBjKpq9qTQcggDPoHuV1YBydMsJLOnYPDeK8rNMKcAkFLbnDRvyJthu5yw==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@svta/cml-structured-field-values": "1.0.1", + "@svta/cml-utils": "1.0.1" + } + }, "node_modules/@svta/cml-dash": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@svta/cml-dash/-/cml-dash-1.0.1.tgz", @@ -3345,6 +3359,29 @@ "@svta/cml-xml": "1.0.1" } }, + "node_modules/@svta/cml-structured-field-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@svta/cml-structured-field-values/-/cml-structured-field-values-1.0.1.tgz", + "integrity": "sha512-Kibciki59Pon3Pn/sl5uyrbJcSpZQDKqdCfDrokBvOdLoqqcd0oFrkEPsZBiuuIODX1CB80612xe8hopeFDyBA==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@svta/cml-utils": "1.0.1" + } + }, + "node_modules/@svta/cml-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@svta/cml-utils/-/cml-utils-1.0.1.tgz", + "integrity": "sha512-kso3curTJfp00I1mKFoBliBApjn4aPE+wF8cPucf7TrSDVWZDeLLuF14ASmUE9m7rnrqTTK4878VvmXaXcCCfQ==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=20" + } + }, "node_modules/@svta/cml-xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@svta/cml-xml/-/cml-xml-1.0.1.tgz", @@ -3669,7 +3706,7 @@ "version": "19.2.7", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", - "dev": true, + "devOptional": true, "dependencies": { "csstype": "^3.2.2" } @@ -4561,7 +4598,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", - "dev": true, + "devOptional": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -4927,7 +4964,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true + "devOptional": true }, "node_modules/custom-media-element": { "version": "1.4.5", @@ -7394,6 +7431,19 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -7930,12 +7980,13 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -8010,6 +8061,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz", + "integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==", + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prettier-plugin-tailwindcss": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz", @@ -8919,18 +8986,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "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, - "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",