Index: .gitignore
===================================================================
--- .gitignore	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ .gitignore	(revision f41a3f0b4f9e00e589236ea75a868b2e4ef2286b)
@@ -1,36 +1,27 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+# See https://www.dartlang.org/guides/libraries/private-files
 
-# dependencies
-/node_modules
-/.pnp
-.pnp.js
+# Files and directories created by pub
+.dart_tool/
+.packages
+build/
+# If you're building an application, you may want to check-in your pubspec.lock
+pubspec.lock
 
-# testing
-/coverage
+# Directory created by dartdoc
+# If you don't generate documentation locally you can remove this line.
+doc/api/
 
-# next.js
-/.next/
-/out/
+# dotenv environment variables file
+.env*
 
-# production
-/build
+# Avoid committing generated Javascript files:
+*.dart.js
+*.info.json      # Produced by the --dump-info flag.
+*.js             # When generated by dart2js. Don't specify *.js if your
+                 # project includes source files written in JavaScript.
+*.js_
+*.js.deps
+*.js.map
 
-# misc
-.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# local env files
-.env*.local
-.env
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
-next-env.d.ts
+.flutter-plugins
+.flutter-plugins-dependencies
Index: LICENSE
===================================================================
--- LICENSE	(revision f41a3f0b4f9e00e589236ea75a868b2e4ef2286b)
+++ LICENSE	(revision f41a3f0b4f9e00e589236ea75a868b2e4ef2286b)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
Index: CENSE.md
===================================================================
--- LICENSE.md	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,129 +1,0 @@
-# PolyForm Perimeter License 1.0.0
-
-<https://polyformproject.org/licenses/perimeter/1.0.0>
-
-## Acceptance
-
-In order to get any license under these terms, you must agree
-to them as both strict obligations and conditions to all
-your licenses.
-
-## Copyright License
-
-The licensor grants you a copyright license for the
-software to do everything you might do with the software
-that would otherwise infringe the licensor's copyright
-in it for any permitted purpose.  However, you may
-only distribute the software according to [Distribution
-License](#distribution-license) and make changes or new works
-based on the software according to [Changes and New Works
-License](#changes-and-new-works-license).
-
-## Distribution License
-
-The licensor grants you an additional copyright license
-to distribute copies of the software.  Your license
-to distribute covers distributing the software with
-changes and new works permitted by [Changes and New Works
-License](#changes-and-new-works-license).
-
-## Notices
-
-You must ensure that anyone who gets a copy of any part of
-the software from you also gets a copy of these terms or the
-URL for them above, as well as copies of any plain-text lines
-beginning with `Required Notice:` that the licensor provided
-with the software.  For example:
-
-> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
-
-## Changes and New Works License
-
-The licensor grants you an additional copyright license to
-make changes and new works based on the software for any
-permitted purpose.
-
-## Patent License
-
-The licensor grants you a patent license for the software that
-covers patent claims the licensor can license, or becomes able
-to license, that you would infringe by using the software.
-
-## Noncompete
-
-Any purpose is a permitted purpose, except for providing to
-others any product that competes with the software.
-
-## Competition
-
-If you use this software to market a product as a substitute
-for the functionality or value of the software, it competes
-with the software. A product may compete regardless how it is
-designed or deployed. For example, a product may compete even
-if it provides its functionality via any kind of interface
-(including services, libraries or plug-ins), even if it is
-ported to a different platforms or programming languages,
-and even if it is provided free of charge.
-
-## Fair Use
-
-You may have "fair use" rights for the software under the
-law. These terms do not limit them.
-
-## No Other Rights
-
-These terms do not allow you to sublicense or transfer any of
-your licenses to anyone else, or prevent the licensor from
-granting licenses to anyone else.  These terms do not imply
-any other licenses.
-
-## Patent Defense
-
-If you make any written claim that the software infringes or
-contributes to infringement of any patent, your patent license
-for the software granted under these terms ends immediately. If
-your company makes such a claim, your patent license ends
-immediately for work on behalf of your company.
-
-## Violations
-
-The first time you are notified in writing that you have
-violated any of these terms, or done anything with the software
-not covered by your licenses, your licenses can nonetheless
-continue if you come into full compliance with these terms,
-and take practical steps to correct past violations, within
-32 days of receiving notice.  Otherwise, all your licenses
-end immediately.
-
-## No Liability
-
-***As far as the law allows, the software comes as is, without
-any warranty or condition, and the licensor will not be liable
-to you for any damages arising out of these terms or the use
-or nature of the software, under any kind of legal claim.***
-
-## Definitions
-
-The **licensor** is the individual or entity offering these
-terms, and the **software** is the software the licensor makes
-available under these terms.
-
-A **product** can be a good or service, or a combination
-of them.
-
-**You** refers to the individual or entity agreeing to these
-terms.
-
-**Your company** is any legal entity, sole proprietorship,
-or other kind of organization that you work for, plus all
-organizations that have control over, are under the control of,
-or are under common control with that organization.  **Control**
-means ownership of substantially all the assets of an entity,
-or the power to direct its management and policies by vote,
-contract, or otherwise.  Control can be direct or indirect.
-
-**Your licenses** are all the licenses granted to you for the
-software under these terms.
-
-**Use** means anything you do with the software requiring one
-of your licenses.
Index: README.md
===================================================================
--- README.md	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ README.md	(revision f41a3f0b4f9e00e589236ea75a868b2e4ef2286b)
@@ -1,2 +1,2 @@
 # FEiN
-Mobile-first web-application for personal finance tracking
+Mobile application for personal finance tracking
Index: p/(app)/add/actions.ts
===================================================================
--- app/(app)/add/actions.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,296 +1,0 @@
-'use server';
-
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { sql } from '@/app/lib/db';
-import { revalidatePath } from 'next/cache';
-
-// ─── Shared helpers ────────────────────────────────────────────
-
-export type ActionState = {
-    error?: string;
-    success?: string;
-} | undefined;
-
-async function requireUserId(): Promise<number> {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login');
-    }
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        redirect('/login');
-    }
-    return userId;
-}
-
-// ─── Add Transaction Account ───────────────────────────────────
-
-export async function addTransactionAccount(
-    _prev: ActionState,
-    formData: FormData,
-): Promise<ActionState> {
-    const userId = await requireUserId();
-
-    const name = String(formData.get('name') ?? '').trim();
-    const balanceRaw = String(formData.get('balance') ?? '0').trim();
-
-    if (!name) {
-        return { error: 'Account name is required.' };
-    }
-
-    const balance = Number(balanceRaw);
-    if (Number.isNaN(balance)) {
-        return { error: 'Balance must be a number.' };
-    }
-
-    try {
-        await sql`
-            INSERT INTO transaction_account (account_name, balance, user_id)
-            VALUES (${name}, ${balance}, ${userId})
-        `;
-    } catch {
-        return { error: 'Failed to create account.' };
-    }
-
-    revalidatePath('/dashboard');
-    revalidatePath('/add');
-    return { success: `Account "${name}" created.` };
-}
-
-// ─── Add Tag ───────────────────────────────────────────────────
-
-export async function addTag(
-    _prev: ActionState,
-    formData: FormData,
-): Promise<ActionState> {
-    await requireUserId(); // auth guard only
-
-    const name = String(formData.get('name') ?? '').trim().toLowerCase();
-
-    if (!name) {
-        return { error: 'Tag name is required.' };
-    }
-    if (name.startsWith('__note:')) {
-        return { error: 'Reserved tag prefix.' };
-    }
-
-    // Check duplicate (case-insensitive)
-    const existing = await sql`
-        SELECT tag_id FROM tag WHERE LOWER(tag_name) = ${name}
-    `;
-    if (existing.length > 0) {
-        return { error: `Tag "${name}" already exists.` };
-    }
-
-    try {
-        await sql`INSERT INTO tag (tag_name) VALUES (${name})`;
-    } catch {
-        return { error: 'Failed to create tag.' };
-    }
-
-    revalidatePath('/add');
-    return { success: `Tag "${name}" created.` };
-}
-
-// ─── Add Transaction ───────────────────────────────────────────
-
-type BreakdownInput = {
-    type: 'from' | 'to';
-    accountId: number;
-    amount: number;
-};
-
-export async function addTransaction(
-    _prev: ActionState,
-    formData: FormData,
-): Promise<ActionState> {
-    const userId = await requireUserId();
-
-    const name = String(formData.get('name') ?? '').trim();
-    const date = String(formData.get('date') ?? '').trim();
-    const amountRaw = String(formData.get('amount') ?? '').trim();
-    const tagsJson = String(formData.get('tags') ?? '[]');
-    const pendingTag = String(formData.get('pendingTag') ?? '').trim().toLowerCase();
-    const note = String(formData.get('note') ?? '').trim();
-    const breakdownsJson = String(formData.get('breakdowns') ?? '[]');
-
-    // ── Validation ──
-    if (!name) {
-        return { error: 'Transaction name is required.' };
-    }
-    if (!date) {
-        return { error: 'Date is required.' };
-    }
-
-    const amount = Number(amountRaw);
-    if (!amountRaw || Number.isNaN(amount)) {
-        return { error: 'Amount must be a number.' };
-    }
-
-    let tags: string[];
-    try {
-        tags = JSON.parse(tagsJson);
-        if (!Array.isArray(tags)) {
-            throw new Error();
-        }
-    } catch {
-        return { error: 'Invalid tags data.' };
-    }
-
-    // Include any tag the user typed but didn't press Enter for
-    if (pendingTag && !pendingTag.startsWith('__note:') && !tags.includes(pendingTag)) {
-        tags.push(pendingTag);
-    }
-
-    let breakdowns: BreakdownInput[];
-    try {
-        breakdowns = JSON.parse(breakdownsJson);
-        if (!Array.isArray(breakdowns)) {
-            throw new Error();
-        }
-    } catch {
-        return { error: 'Invalid breakdowns data.' };
-    }
-
-    // Validate each breakdown
-    for (const breakdown of breakdowns) {
-        if (!['from', 'to'].includes(breakdown.type)) {
-            return { error: 'Invalid breakdown type.' };
-        }
-        if (!Number.isFinite(breakdown.amount) || breakdown.amount <= 0) {
-            return { error: 'Breakdown amounts must be positive.' };
-        }
-        if (!Number.isInteger(breakdown.accountId)) {
-            return { error: 'Invalid account in breakdown.' };
-        }
-    }
-
-    // Verify all accounts belong to this user
-    if (breakdowns.length > 0) {
-        const accountIds = [...new Set(breakdowns.map((b) => b.accountId))];
-        const ownedAccounts = await sql`
-            SELECT transaction_account_id
-            FROM transaction_account
-            WHERE user_id = ${userId}
-              AND transaction_account_id = ANY(${accountIds}::int[])
-        `;
-        if (ownedAccounts.length !== accountIds.length) {
-            return { error: 'One or more accounts do not belong to you.' };
-        }
-    }
-
-    // Compute net_amount from breakdowns
-    let totalEarned = 0;
-    let totalSpent = 0;
-    for (const breakdown of breakdowns) {
-        if (breakdown.type === 'to') {
-            totalEarned += breakdown.amount;
-        }
-        else {
-            totalSpent += breakdown.amount;
-        }
-    }
-    const netAmount = totalEarned - totalSpent;
-
-    try {
-        // Use a SQL transaction for atomicity
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        await sql.begin(async (tx: any) => {
-            // 1. Insert transaction
-            const [txRow] = await tx`
-                INSERT INTO transaction (transaction_name, amount, net_amount, date)
-                VALUES (${name}, ${amount}, ${netAmount}, ${date})
-                RETURNING transaction_id
-            `;
-            const transactionId: number = txRow.transaction_id;
-
-            // 2. Insert breakdowns & update account balances
-            for (const breakdown of breakdowns) {
-                const spent = breakdown.type === 'from' ? breakdown.amount : 0;
-                const earned = breakdown.type === 'to' ? breakdown.amount : 0;
-
-                await tx`
-                    INSERT INTO transaction_breakdown
-                        (transaction_id, transaction_account_id, spent_amount, earned_amount)
-                    VALUES (${transactionId}, ${breakdown.accountId}, ${spent}, ${earned})
-                `;
-
-                // Update balance: earned increases, spent decreases
-                await tx`
-                    UPDATE transaction_account
-                    SET balance = balance + ${earned} - ${spent}
-                    WHERE transaction_account_id = ${breakdown.accountId}
-                `;
-            }
-
-            // 3. Handle tags
-            for (const tagName of tags) {
-                const trimmed = tagName.trim().toLowerCase();
-                if (!trimmed || trimmed.startsWith('__note:')) {
-                    continue;
-                }
-
-                // Find or insert tag
-                const existing = await tx`
-                    SELECT tag_id FROM tag WHERE LOWER(tag_name) = ${trimmed}
-                `;
-                let tagId: number;
-                if (existing.length > 0) {
-                    tagId = existing[0].tag_id;
-                } else {
-                    const [inserted] = await tx`
-                        INSERT INTO tag (tag_name) VALUES (${trimmed})
-                        RETURNING tag_id
-                    `;
-                    tagId = inserted.tag_id;
-                }
-
-                // Check if assignment already exists
-                const existingAssignment = await tx`
-                    SELECT tag_assigned_to_transaction_id
-                    FROM tag_assigned_to_transaction
-                    WHERE transaction_id = ${transactionId} AND tag_id = ${tagId}
-                `;
-                if (existingAssignment.length === 0) {
-                    await tx`
-                        INSERT INTO tag_assigned_to_transaction (transaction_id, tag_id)
-                        VALUES (${transactionId}, ${tagId})
-                    `;
-                }
-            }
-
-            // 4. Handle note as a special __note: tag
-            if (note) {
-                const noteTagName = `__note:${note}`;
-
-                const existingNote = await tx`
-                    SELECT tag_id FROM tag WHERE tag_name = ${noteTagName}
-                `;
-                let noteTagId: number;
-                if (existingNote.length > 0) {
-                    noteTagId = existingNote[0].tag_id;
-                } else {
-                    const [inserted] = await tx`
-                        INSERT INTO tag (tag_name) VALUES (${noteTagName})
-                        RETURNING tag_id
-                    `;
-                    noteTagId = inserted.tag_id;
-                }
-
-                await tx`
-                    INSERT INTO tag_assigned_to_transaction (transaction_id, tag_id)
-                    VALUES (${transactionId}, ${noteTagId})
-                `;
-            }
-        });
-    } catch (e) {
-        console.error('addTransaction error:', e);
-        return { error: 'Failed to create transaction.' };
-    }
-
-    revalidatePath('/dashboard');
-    revalidatePath('/history');
-    revalidatePath('/add');
-    return { success: `Transaction "${name}" created.` };
-}
Index: p/(app)/add/add-account-form.tsx
===================================================================
--- app/(app)/add/add-account-form.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,95 +1,0 @@
-'use client';
-
-import { useActionState, useEffect, useRef } from 'react';
-import { addTransactionAccount, type ActionState } from './actions';
-import { poppins } from '@/app/ui/fonts';
-import {
-    CurrencyDollarIcon,
-    ExclamationCircleIcon,
-    CheckCircleIcon,
-} from '@heroicons/react/24/outline';
-import { Button } from '@/app/ui/button';
-
-export default function AddAccountForm() {
-    const [state, formAction, isPending] = useActionState<ActionState, FormData>(
-        addTransactionAccount,
-        undefined,
-    );
-    const formRef = useRef<HTMLFormElement>(null);
-
-    useEffect(() => {
-        if (state?.success) {
-            formRef.current?.reset();
-        }
-    }, [state]);
-
-    return (
-        <form ref={formRef} action={formAction} className="space-y-4">
-            {/* Account Name */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Account Name
-                </label>
-                <input
-                    name="name"
-                    type="text"
-                    required
-                    placeholder="e.g. Cash, Bank Card…"
-                    className={`${poppins.className}
-                        w-full h-12 rounded-xl
-                        bg-white/10 border border-white/15
-                        px-4 text-white text-sm
-                        placeholder:text-white/40
-                        focus:outline-none focus:ring-2 focus:ring-blue-500/50
-                    `}
-                />
-            </div>
-
-            {/* Initial Balance */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Initial Balance (optional)
-                </label>
-                <div className="relative">
-                    <input
-                        name="balance"
-                        type="number"
-                        step="any"
-                        defaultValue="0"
-                        placeholder="0"
-                        className={`${poppins.className}
-                            w-full h-12 rounded-xl
-                            bg-white/10 border border-white/15
-                            pl-10 pr-4 text-white text-sm
-                            placeholder:text-white/40
-                            focus:outline-none focus:ring-2 focus:ring-blue-500/50
-                        `}
-                    />
-                    <CurrencyDollarIcon className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-white/40" />
-                </div>
-            </div>
-
-            {/* Feedback */}
-            {state?.error && (
-                <div className="flex items-center gap-2 text-red-400 text-sm">
-                    <ExclamationCircleIcon className="h-4 w-4 shrink-0" />
-                    {state.error}
-                </div>
-            )}
-            {state?.success && (
-                <div className="flex items-center gap-2 text-green-400 text-sm">
-                    <CheckCircleIcon className="h-4 w-4 shrink-0" />
-                    {state.success}
-                </div>
-            )}
-
-            <Button
-                type="submit"
-                aria-disabled={isPending}
-                className="w-full justify-center h-12 rounded-xl text-sm font-semibold"
-            >
-                {isPending ? 'Creating…' : 'Create Account'}
-            </Button>
-        </form>
-    );
-}
Index: p/(app)/add/add-page-client.tsx
===================================================================
--- app/(app)/add/add-page-client.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,54 +1,0 @@
-'use client';
-
-import { useState } from 'react';
-import FormSelector, { type FormType } from './form-selector';
-import AddAccountForm from './add-account-form';
-import AddTagForm from './add-tag-form';
-import AddTransactionForm from './add-transaction-form';
-import { poppins } from '@/app/ui/fonts';
-
-type AccountOption = { transaction_account_id: number; account_name: string | null };
-type TagOption = { tag_id: number; tag_name: string };
-
-export default function AddPageClient({
-    accounts,
-    allTags,
-}: {
-    accounts: AccountOption[];
-    allTags: TagOption[];
-}) {
-    const [formType, setFormType] = useState<FormType>('transaction');
-
-    const titles: Record<FormType, string> = {
-        transaction: 'Transaction',
-        account: 'Account',
-        tag: 'Tag',
-    };
-
-    return (
-        <div className="w-full overflow-hidden px-6 pt-10 pb-10">
-            <h1
-                className={`${poppins.className}
-                    text-[32px] leading-tight tracking-tight
-                    font-semibold text-center text-white mb-6
-                `}
-            >
-                Add
-            </h1>
-
-            {/* Selector */}
-            <div className="mb-6">
-                <FormSelector value={formType} onChange={setFormType} />
-            </div>
-
-            {/* Form card */}
-            <div className="rounded-2xl bg-white/5 border border-white/10 p-5">
-                {formType === 'transaction' && (
-                    <AddTransactionForm accounts={accounts} allTags={allTags} />
-                )}
-                {formType === 'account' && <AddAccountForm />}
-                {formType === 'tag' && <AddTagForm />}
-            </div>
-        </div>
-    );
-}
Index: p/(app)/add/add-tag-form.tsx
===================================================================
--- app/(app)/add/add-tag-form.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,77 +1,0 @@
-'use client';
-
-import { useActionState, useEffect, useRef } from 'react';
-import { addTag, type ActionState } from './actions';
-import { poppins } from '@/app/ui/fonts';
-import {
-    TagIcon,
-    ExclamationCircleIcon,
-    CheckCircleIcon,
-} from '@heroicons/react/24/outline';
-import { Button } from '@/app/ui/button';
-
-export default function AddTagForm() {
-    const [state, formAction, isPending] = useActionState<ActionState, FormData>(
-        addTag,
-        undefined,
-    );
-    const formRef = useRef<HTMLFormElement>(null);
-
-    useEffect(() => {
-        if (state?.success) {
-            formRef.current?.reset();
-        }
-    }, [state]);
-
-    return (
-        <form ref={formRef} action={formAction} className="space-y-4">
-            {/* Tag Name */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Tag Name
-                </label>
-                <div className="relative">
-                    <input
-                        name="name"
-                        type="text"
-                        required
-                        placeholder="e.g. food, rent, salary…"
-                        className={`${poppins.className}
-                            w-full h-12 rounded-xl
-                            bg-white/10 border border-white/15
-                            pl-10 pr-4 text-white text-sm
-                            placeholder:text-white/40
-                            focus:outline-none focus:ring-2 focus:ring-blue-500/50
-                        `}
-                    />
-                    <TagIcon className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-white/40" />
-                </div>
-                <p className="text-xs text-white/30 mt-1.5 pl-1">
-                    Tags are shared across all users. Will be lowercased.
-                </p>
-            </div>
-
-            {/* Feedback */}
-            {state?.error && (
-                <div className="flex items-center gap-2 text-red-400 text-sm">
-                    <ExclamationCircleIcon className="h-4 w-4 shrink-0" />
-                    {state.error}
-                </div>
-            )}
-            {state?.success && (
-                <div className="flex items-center gap-2 text-green-400 text-sm">
-                    <CheckCircleIcon className="h-4 w-4 shrink-0" />
-                    {state.success}
-                </div>
-            )}
-
-            <Button
-                type="submit"
-                aria-disabled={isPending}
-                className="w-full justify-center h-12 rounded-xl text-sm font-semibold"
-            >
-                {isPending ? 'Creating…' : 'Create Tag'}
-            </Button>
-        </form>
-    );
-}
Index: p/(app)/add/add-transaction-form.tsx
===================================================================
--- app/(app)/add/add-transaction-form.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,444 +1,0 @@
-'use client';
-
-import { useActionState, useEffect, useRef, useState } from 'react';
-import { addTransaction, type ActionState } from './actions';
-import { poppins } from '@/app/ui/fonts';
-import {
-    CalendarIcon,
-    PlusIcon,
-    XMarkIcon,
-    ExclamationCircleIcon,
-    CheckCircleIcon,
-    ArrowDownTrayIcon,
-    ArrowUpTrayIcon,
-} from '@heroicons/react/24/outline';
-import { Button } from '@/app/ui/button';
-
-type AccountOption = { transaction_account_id: number; account_name: string | null };
-type TagOption = { tag_id: number; tag_name: string };
-
-type Breakdown = {
-    id: number; // client-side key
-    type: 'from' | 'to';
-    accountId: number;
-    amount: string;
-};
-
-let nextId = 1;
-
-export default function AddTransactionForm({
-    accounts,
-    allTags,
-}: {
-    accounts: AccountOption[];
-    allTags: TagOption[];
-}) {
-    const [state, formAction, isPending] = useActionState<ActionState, FormData>(
-        addTransaction,
-        undefined,
-    );
-    const formRef = useRef<HTMLFormElement>(null);
-
-    // ── Breakdowns ──
-    const [breakdowns, setBreakdowns] = useState<Breakdown[]>([]);
-    const [showFieldMenu, setShowFieldMenu] = useState(false);
-    const fieldMenuRef = useRef<HTMLDivElement>(null);
-
-    function addBreakdown(type: 'from' | 'to') {
-        const defaultAccount = accounts[0]?.transaction_account_id ?? 0;
-        setBreakdowns((prev) => [
-            ...prev,
-            { id: nextId++, type, accountId: defaultAccount, amount: '' },
-        ]);
-        setShowFieldMenu(false);
-    }
-
-    function removeBreakdown(id: number) {
-        setBreakdowns((prev) => prev.filter((b) => b.id !== id));
-    }
-
-    function updateBreakdown(id: number, field: Partial<Breakdown>) {
-        setBreakdowns((prev) =>
-            prev.map((b) => (b.id === id ? { ...b, ...field } : b)),
-        );
-    }
-
-    // ── Tags ──
-    const [selectedTags, setSelectedTags] = useState<string[]>([]);
-    const [tagInput, setTagInput] = useState('');
-
-    function toggleTag(name: string) {
-        setSelectedTags((prev) =>
-            prev.includes(name)
-                ? prev.filter((t) => t !== name)
-                : [...prev, name],
-        );
-    }
-
-    function addCustomTag() {
-        const trimmed = tagInput.trim().toLowerCase();
-        if (trimmed && !selectedTags.includes(trimmed)) {
-            setSelectedTags((prev) => [...prev, trimmed]);
-        }
-        setTagInput('');
-    }
-
-    // ── Reset on success ──
-    useEffect(() => {
-        if (state?.success) {
-            formRef.current?.reset();
-            setBreakdowns([]);
-            setSelectedTags([]);
-            setTagInput('');
-        }
-    }, [state]);
-
-    // ── Close field menu on outside click ──
-    useEffect(() => {
-        function handler(e: MouseEvent) {
-            if (
-                fieldMenuRef.current &&
-                !fieldMenuRef.current.contains(e.target as Node)
-            ) {
-                setShowFieldMenu(false);
-            }
-        }
-        document.addEventListener('mousedown', handler);
-        return () => document.removeEventListener('mousedown', handler);
-    }, []);
-
-    // ── Build serialised data for hidden fields ──
-    const breakdownsPayload = breakdowns.map((b) => ({
-        type: b.type,
-        accountId: b.accountId,
-        amount: Number(b.amount) || 0,
-    }));
-
-    const inputClasses = `${poppins.className}
-        w-full min-w-0 max-w-full box-border h-12 rounded-xl
-        bg-white/10 border border-white/15
-        px-4 text-white text-sm
-        placeholder:text-white/40
-        focus:outline-none focus:ring-2 focus:ring-blue-500/50
-    `;
-
-    return (
-        <form ref={formRef} action={formAction} className="space-y-5">
-            {/* Hidden serialised fields */}
-            <input type="hidden" name="tags" value={JSON.stringify(selectedTags)} />
-            <input type="hidden" name="pendingTag" value={tagInput.trim().toLowerCase()} />
-            <input
-                type="hidden"
-                name="breakdowns"
-                value={JSON.stringify(breakdownsPayload)}
-            />
-
-            {/* Transaction Name */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Name
-                </label>
-                <input
-                    name="name"
-                    type="text"
-                    required
-                    placeholder="e.g. Grocery shopping"
-                    className={inputClasses}
-                />
-            </div>
-
-            {/* Date */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Date
-                </label>
-                <div className="relative overflow-hidden">
-                    <input
-                        name="date"
-                        type="date"
-                        required
-                        defaultValue={new Date().toISOString().slice(0, 10)}
-                        className={`${inputClasses} pl-10 [color-scheme:dark] [&::-webkit-date-and-time-value]:text-left`}
-                    />
-                    <CalendarIcon className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-white/40" />
-                </div>
-            </div>
-
-            {/* Amount */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Amount
-                </label>
-                <input
-                    name="amount"
-                    type="number"
-                    step="any"
-                    required
-                    placeholder="0"
-                    className={inputClasses}
-                />
-            </div>
-
-            {/* ── Breakdown fields ── */}
-            {breakdowns.length > 0 && (
-                <div className="space-y-3">
-                    <span className="block text-xs text-white/50 pl-1">
-                        Account Breakdowns
-                    </span>
-                    {breakdowns.map((bd) => (
-                        <div
-                            key={bd.id}
-                            className="
-                                flex items-center gap-2
-                                rounded-xl bg-white/5 border border-white/10
-                                p-3
-                            "
-                        >
-                            {/* Type badge */}
-                            <span
-                                className={`
-                                    shrink-0 flex items-center gap-1
-                                    text-xs font-medium px-2 py-1 rounded-lg
-                                    ${bd.type === 'from'
-                                        ? 'bg-red-500/20 text-red-400'
-                                        : 'bg-green-500/20 text-green-400'
-                                    }
-                                `}
-                            >
-                                {bd.type === 'from' ? (
-                                    <ArrowUpTrayIcon className="h-3.5 w-3.5" />
-                                ) : (
-                                    <ArrowDownTrayIcon className="h-3.5 w-3.5" />
-                                )}
-                                {bd.type === 'from' ? 'From' : 'To'}
-                            </span>
-
-                            {/* Account Select */}
-                            <select
-                                value={bd.accountId}
-                                onChange={(e) =>
-                                    updateBreakdown(bd.id, {
-                                        accountId: Number(e.target.value),
-                                    })
-                                }
-                                className={`${poppins.className}
-                                    flex-1 min-w-0 h-9 rounded-lg
-                                    bg-white/10 border border-white/15
-                                    px-2 text-white text-xs
-                                    focus:outline-none focus:ring-1 focus:ring-blue-500/50
-                                `}
-                            >
-                                {accounts.map((a) => (
-                                    <option
-                                        key={a.transaction_account_id}
-                                        value={a.transaction_account_id}
-                                        className="bg-[#1a1a2e] text-white"
-                                    >
-                                        {a.account_name ?? `Account #${a.transaction_account_id}`}
-                                    </option>
-                                ))}
-                            </select>
-
-                            {/* Amount */}
-                            <input
-                                type="number"
-                                step="any"
-                                placeholder="0"
-                                value={bd.amount}
-                                onChange={(e) =>
-                                    updateBreakdown(bd.id, { amount: e.target.value })
-                                }
-                                className={`${poppins.className}
-                                    w-20 h-9 rounded-lg
-                                    bg-white/10 border border-white/15
-                                    px-2 text-white text-xs text-right
-                                    placeholder:text-white/40
-                                    focus:outline-none focus:ring-1 focus:ring-blue-500/50
-                                `}
-                            />
-
-                            {/* Remove */}
-                            <button
-                                type="button"
-                                onClick={() => removeBreakdown(bd.id)}
-                                className="shrink-0 p-1 rounded-lg hover:bg-white/10 transition-colors"
-                            >
-                                <XMarkIcon className="h-4 w-4 text-white/40" />
-                            </button>
-                        </div>
-                    ))}
-                </div>
-            )}
-
-            {/* Add a Field button */}
-            <div ref={fieldMenuRef} className="relative">
-                <button
-                    type="button"
-                    onClick={() => setShowFieldMenu(!showFieldMenu)}
-                    className="
-                        flex items-center gap-1.5
-                        text-sm text-blue-400 hover:text-blue-300
-                        transition-colors
-                    "
-                >
-                    <PlusIcon className="h-4 w-4" />
-                    Add a field
-                </button>
-
-                {showFieldMenu && (
-                    <div
-                        className="
-                            absolute z-40 mt-1 left-0
-                            w-48 rounded-xl
-                            bg-[#1a1a2e] border border-white/15
-                            shadow-xl overflow-hidden
-                        "
-                    >
-                        <button
-                            type="button"
-                            onClick={() => addBreakdown('from')}
-                            className="
-                                w-full flex items-center gap-2 px-4 py-3
-                                text-sm text-white/80 hover:bg-white/10
-                                transition-colors
-                            "
-                        >
-                            <ArrowUpTrayIcon className="h-4 w-4 text-red-400" />
-                            From Account
-                        </button>
-                        <button
-                            type="button"
-                            onClick={() => addBreakdown('to')}
-                            className="
-                                w-full flex items-center gap-2 px-4 py-3
-                                text-sm text-white/80 hover:bg-white/10
-                                transition-colors
-                            "
-                        >
-                            <ArrowDownTrayIcon className="h-4 w-4 text-green-400" />
-                            To Account
-                        </button>
-                    </div>
-                )}
-            </div>
-
-            {/* ── Tags ── */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Tags
-                </label>
-
-                {/* Existing tags as toggleable pills */}
-                <div className="flex flex-wrap gap-1.5 mb-2">
-                    {allTags.map((t) => {
-                        const active = selectedTags.includes(t.tag_name);
-                        return (
-                            <button
-                                key={t.tag_id}
-                                type="button"
-                                onClick={() => toggleTag(t.tag_name)}
-                                className={`
-                                    px-2.5 py-1 rounded-full text-xs font-medium
-                                    transition-colors border
-                                    ${active
-                                        ? 'bg-blue-500/30 border-blue-400/50 text-blue-300'
-                                        : 'bg-white/5 border-white/10 text-white/50 hover:bg-white/10'
-                                    }
-                                `}
-                            >
-                                {t.tag_name}
-                            </button>
-                        );
-                    })}
-                </div>
-
-                {/* Custom tag pills (not from DB yet) */}
-                {selectedTags
-                    .filter((s) => !allTags.some((t) => t.tag_name === s))
-                    .map((custom) => (
-                        <span
-                            key={custom}
-                            className="
-                                inline-flex items-center gap-1
-                                mr-1.5 mb-1.5
-                                px-2.5 py-1 rounded-full text-xs font-medium
-                                bg-blue-500/30 border border-blue-400/50 text-blue-300
-                            "
-                        >
-                            {custom}
-                            <button
-                                type="button"
-                                onClick={() => toggleTag(custom)}
-                                className="hover:text-white"
-                            >
-                                <XMarkIcon className="h-3 w-3" />
-                            </button>
-                        </span>
-                    ))}
-
-                {/* Input to add new tag */}
-                <input
-                    type="text"
-                    value={tagInput}
-                    onChange={(e) => setTagInput(e.target.value)}
-                    onKeyDown={(e) => {
-                        if (e.key === 'Enter') {
-                            e.preventDefault();
-                            addCustomTag();
-                        }
-                    }}
-                    placeholder="Type a new tag + Enter"
-                    className={`${poppins.className}
-                        w-full h-10 rounded-xl
-                        bg-white/5 border border-white/10
-                        px-3 text-white text-xs
-                        placeholder:text-white/30
-                        focus:outline-none focus:ring-1 focus:ring-blue-500/50
-                    `}
-                />
-            </div>
-
-            {/* ── Note ── */}
-            <div>
-                <label className="block text-xs text-white/50 mb-1.5 pl-1">
-                    Note (optional)
-                </label>
-                <textarea
-                    name="note"
-                    rows={2}
-                    placeholder="Any extra details…"
-                    className={`${poppins.className}
-                        w-full rounded-xl
-                        bg-white/10 border border-white/15
-                        px-4 py-3 text-white text-sm
-                        placeholder:text-white/40
-                        focus:outline-none focus:ring-2 focus:ring-blue-500/50
-                        resize-none
-                    `}
-                />
-            </div>
-
-            {/* ── Feedback ── */}
-            {state?.error && (
-                <div className="flex items-center gap-2 text-red-400 text-sm">
-                    <ExclamationCircleIcon className="h-4 w-4 shrink-0" />
-                    {state.error}
-                </div>
-            )}
-            {state?.success && (
-                <div className="flex items-center gap-2 text-green-400 text-sm">
-                    <CheckCircleIcon className="h-4 w-4 shrink-0" />
-                    {state.success}
-                </div>
-            )}
-
-            <Button
-                type="submit"
-                aria-disabled={isPending}
-                className="w-full justify-center h-12 rounded-xl text-sm font-semibold"
-            >
-                {isPending ? 'Creating…' : 'Create Transaction'}
-            </Button>
-        </form>
-    );
-}
Index: p/(app)/add/form-selector.tsx
===================================================================
--- app/(app)/add/form-selector.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,88 +1,0 @@
-'use client';
-
-import { useState, useRef, useEffect } from 'react';
-import { ChevronDownIcon } from '@heroicons/react/24/outline';
-import { poppins } from '@/app/ui/fonts';
-
-const FORM_OPTIONS = [
-    { value: 'transaction', label: 'Transaction' },
-    { value: 'account', label: 'Transaction Account' },
-    { value: 'tag', label: 'Tag' },
-] as const;
-
-export type FormType = (typeof FORM_OPTIONS)[number]['value'];
-
-export default function FormSelector({
-    value,
-    onChange,
-}: {
-    value: FormType;
-    onChange: (v: FormType) => void;
-}) {
-    const [open, setOpen] = useState(false);
-    const ref = useRef<HTMLDivElement>(null);
-
-    useEffect(() => {
-        function handleClick(e: MouseEvent) {
-            if (ref.current && !ref.current.contains(e.target as Node)) {
-                setOpen(false);
-            }
-        }
-        document.addEventListener('mousedown', handleClick);
-        return () => document.removeEventListener('mousedown', handleClick);
-    }, []);
-
-    const currentLabel = FORM_OPTIONS.find((o) => o.value === value)?.label;
-
-    return (
-        <div ref={ref} className="relative w-full">
-            <button
-                type="button"
-                onClick={() => setOpen(!open)}
-                className={`${poppins.className}
-                    w-full flex items-center justify-center
-                    h-12 rounded-xl
-                    bg-white/10 border border-white/15
-                    px-4 text-white text-2xl
-                    transition-colors hover:bg-white/15
-                `}
-            >
-                <span className='pr-2'>{currentLabel}</span>
-                <ChevronDownIcon
-                    className={`h-4 w-4 text-white/60 transition-transform ${open ? 'rotate-180' : ''
-                        }`}
-                />
-            </button>
-
-            {open && (
-                <div
-                    className="
-                        absolute z-50 mt-1 w-full
-                        rounded-xl bg-[#1a1a2e] border border-white/15
-                        shadow-xl overflow-hidden
-                    "
-                >
-                    {FORM_OPTIONS.map((opt) => (
-                        <button
-                            key={opt.value}
-                            type="button"
-                            onClick={() => {
-                                onChange(opt.value);
-                                setOpen(false);
-                            }}
-                            className={`
-                                w-full text-left px-4 py-3 text-sm transition-colors
-                                ${opt.value === value
-                                    ? 'bg-blue-500/20 text-blue-400'
-                                    : 'text-white/80 hover:bg-white/10'
-                                }
-                            `}
-                        >
-                            {opt.label}
-                        </button>
-                    ))}
-                </div>
-            )}
-        </div>
-    );
-}
Index: p/(app)/add/page.tsx
===================================================================
--- app/(app)/add/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,23 +1,0 @@
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { getUserTransactionAccounts, getAllTags } from '@/app/lib/queries';
-import AddPageClient from './add-page-client';
-
-export default async function Page() {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login?callbackUrl=/add');
-    }
-
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        redirect('/login?callbackUrl=/add');
-    }
-
-    const [accounts, allTags] = await Promise.all([
-        getUserTransactionAccounts(userId),
-        getAllTags(),
-    ]);
-
-    return <AddPageClient accounts={accounts} allTags={allTags} />;
-}
Index: p/(app)/analytics/analytics-client.tsx
===================================================================
--- app/(app)/analytics/analytics-client.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,650 +1,0 @@
-"use client";
-
-import { useEffect, useMemo, useRef, useState } from 'react';
-import { usePathname, useRouter, useSearchParams } from 'next/navigation';
-import { CalendarDaysIcon, CheckIcon, XMarkIcon } from '@heroicons/react/24/outline';
-import { formatMKD } from '@/app/lib/utils';
-import UrlSearchInput from '@/app/ui/url-search-input';
-import AccountFilterIcon from '@/app/ui/account-filter-icon';
-import type { AnalyticsData, AnalyticsTagTotal, AnalyticsTrendPoint } from '@/app/lib/queries';
-
-const COLORS = ['#60a5fa', '#34d399', '#fbbf24', '#f472b6', '#a78bfa', '#fb7185', '#22d3ee', '#f97316'];
-const ANALYTICS_KEYS = ['query', 'accountId', 'period', 'startDate', 'endDate', 'focusTags'] as const;
-const NAVIGATION_START_EVENT = 'fein:navigation-start';
-
-export default function AnalyticsClient({
-    data,
-    userId,
-}: {
-    data: AnalyticsData;
-    userId: number;
-}) {
-    const searchParams = useSearchParams();
-    const pathname = usePathname();
-    const { replace } = useRouter();
-    const startInputRef = useRef<HTMLInputElement>(null);
-    const endInputRef = useRef<HTMLInputElement>(null);
-    const [trendZoomOpen, setTrendZoomOpen] = useState(false);
-
-    const query = searchParams.get('query') ?? '';
-    const period = (searchParams.get('period') ?? 'month') as 'month' | 'year' | 'range';
-    const startDate = searchParams.get('startDate') ?? '';
-    const endDate = searchParams.get('endDate') ?? '';
-    const selectedFocusTags = (searchParams.get('focusTags') ?? '').split(',').filter(Boolean);
-
-    const storageKey = `fein:analyticsState:v1:${userId}`;
-
-    function navigateWithIndicator(nextUrl: string) {
-        window.dispatchEvent(new Event(NAVIGATION_START_EVENT));
-        replace(nextUrl, { scroll: false });
-    }
-
-    useEffect(() => {
-        try {
-            const raw = localStorage.getItem(storageKey);
-            if (!raw) {
-                return;
-            }
-
-            const hasActiveParams = ANALYTICS_KEYS.some((key) => searchParams.get(key));
-            if (hasActiveParams) {
-                return;
-            }
-
-            const stored = JSON.parse(raw) as Record<string, string | undefined>;
-            const params = new URLSearchParams();
-            for (const key of ANALYTICS_KEYS) {
-                const value = stored[key];
-                if (value) {
-                    params.set(key, value);
-                }
-            }
-
-            const nextQuery = params.toString();
-            if (nextQuery) {
-                navigateWithIndicator(`${pathname}?${nextQuery}`);
-            }
-        } catch {
-            // ignore storage errors
-        }
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [storageKey, userId]);
-
-    useEffect(() => {
-        try {
-            const snapshot: Record<string, string | undefined> = {};
-            for (const key of ANALYTICS_KEYS) {
-                const value = searchParams.get(key) ?? undefined;
-                if (value) {
-                    snapshot[key] = value;
-                }
-            }
-
-            localStorage.setItem(storageKey, JSON.stringify(snapshot));
-        } catch {
-            // ignore storage errors
-        }
-    }, [searchParams, storageKey]);
-
-    const updateParams = (mutate: (params: URLSearchParams) => void) => {
-        const params = new URLSearchParams(searchParams);
-        mutate(params);
-        const nextQuery = params.toString();
-        navigateWithIndicator(nextQuery ? `${pathname}?${nextQuery}` : pathname);
-    };
-
-    const setPeriod = (value: 'month' | 'year' | 'range') => {
-        updateParams((params) => {
-            params.set('period', value);
-            if (value !== 'range') {
-                params.delete('startDate');
-                params.delete('endDate');
-            } else if (!params.get('startDate') || !params.get('endDate')) {
-                const now = new Date();
-                const start = new Date(now.getFullYear(), now.getMonth(), 1);
-                const end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
-                params.set('startDate', toDateInputValue(start));
-                params.set('endDate', toDateInputValue(end));
-            }
-        });
-    };
-
-    const setRangeDate = (key: 'startDate' | 'endDate', value: string) => {
-        updateParams((params) => {
-            params.set('period', 'range');
-            if (value) {
-                params.set(key, value);
-            } else {
-                params.delete(key);
-            }
-        });
-    };
-
-    const toggleFocusTag = (tag: string) => {
-        updateParams((params) => {
-            const current = (params.get('focusTags') ?? '').split(',').filter(Boolean);
-            const next = current.includes(tag)
-                ? current.filter((value) => value !== tag)
-                : [...current, tag];
-
-            if (next.length > 0) {
-                params.set('focusTags', next.join(','));
-            } else {
-                params.delete('focusTags');
-            }
-        });
-    };
-
-    const clearAllFilters = () => {
-        navigateWithIndicator(pathname);
-    };
-
-    const mainTagSlices = useMemo(() => toSlices(data.tagTotals), [data.tagTotals]);
-    const focusTagSlices = useMemo(() => toSlices(data.focusTagTotals), [data.focusTagTotals]);
-    const visibleTags = useMemo(() => {
-        if (!query.trim()) return data.tags;
-        const lowered = query.trim().toLowerCase();
-        return data.tags.filter((tag) => tag.toLowerCase().includes(lowered));
-    }, [data.tags, query]);
-
-    return (
-        <div className="mt-8 space-y-6 text-white">
-            <div className="rounded-3xl border border-white/10 bg-black/25 backdrop-blur-md p-4 md:p-5 space-y-4">
-                <div className="flex gap-2 items-center">
-                    <div className="flex-1 min-w-0">
-                        <UrlSearchInput
-                            placeholder="Search tags, accounts, or transactions..."
-                            debounceMs={250}
-                        />
-                    </div>
-                    <AccountFilterIcon
-                        accounts={data.accounts}
-                    />
-                </div>
-
-                <div className="space-y-2">
-                    <div className="inline-flex w-full justify-center gap-2 rounded-2xl border border-white/10 bg-white/5 p-1">
-                        {([['month', 'Monthly'], ['year', 'Yearly'], ['range', 'Range']] as const).map(([value, label]) => (
-                            <button
-                                key={value}
-                                type="button"
-                                onClick={() => setPeriod(value)}
-                                className={`rounded-xl px-4 py-2 text-sm font-medium transition whitespace-nowrap ${period === value
-                                    ? 'bg-sky-500 text-slate-950'
-                                    : 'text-white/65 hover:text-white hover:bg-white/10'
-                                    }`}
-                            >
-                                {label}
-                            </button>
-                        ))}
-                    </div>
-
-                    {period === 'range' && (
-                        <div className="grid grid-cols-2 gap-2">
-                            <DatePickerButton
-                                label="Start Date"
-                                value={startDate}
-                                inputRef={startInputRef}
-                                onClick={() => startInputRef.current?.showPicker?.() ?? startInputRef.current?.click()}
-                                onChange={(value) => setRangeDate('startDate', value)}
-                            />
-                            <DatePickerButton
-                                label="End Date"
-                                value={endDate}
-                                inputRef={endInputRef}
-                                onClick={() => endInputRef.current?.showPicker?.() ?? endInputRef.current?.click()}
-                                onChange={(value) => setRangeDate('endDate', value)}
-                            />
-                        </div>
-                    )}
-                </div>
-            </div>
-
-            <RingCard
-                title="Top tags"
-                slices={mainTagSlices}
-                emptyMessage="No tags match the current filters."
-            />
-
-            <TrendCard trend={data.trend} period={period} onZoom={() => setTrendZoomOpen(true)} />
-
-            <div className="rounded-3xl border border-white/10 bg-black/25 backdrop-blur-md p-5 space-y-4">
-                <div className="flex flex-wrap items-center justify-between gap-3">
-                    <div className="text-lg font-semibold text-white">Custom tag mix</div>
-
-                    {selectedFocusTags.length > 0 && (
-                        <button
-                            type="button"
-                            onClick={() => updateParams((params) => params.delete('focusTags'))}
-                            className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/8 px-3 py-1.5 text-xs text-white/70 hover:text-white hover:bg-white/12"
-                        >
-                            <XMarkIcon className="h-4 w-4" />
-                            Clear tag mix
-                        </button>
-                    )}
-                </div>
-
-                <div className="flex flex-wrap gap-2">
-                    {visibleTags.length === 0 ? (
-                        <div className="text-sm text-white/45">No tags available for this account set.</div>
-                    ) : (
-                        visibleTags.map((tag) => {
-                            const selected = selectedFocusTags.includes(tag);
-                            return (
-                                <button
-                                    key={tag}
-                                    type="button"
-                                    onClick={() => toggleFocusTag(tag)}
-                                    className={`inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-sm transition ${selected
-                                        ? 'border-sky-400/40 bg-sky-500/15 text-white'
-                                        : 'border-white/10 bg-white/5 text-white/65 hover:bg-white/10 hover:text-white'
-                                        }`}
-                                >
-                                    {selected && <CheckIcon className="h-4 w-4" />}
-                                    <span>{tag}</span>
-                                </button>
-                            );
-                        })
-                    )}
-                </div>
-
-                {selectedFocusTags.length > 0 && (
-                    <RingCard
-                        title="Selected tags"
-                        slices={focusTagSlices}
-                        emptyMessage="None of the selected tags produced spending in the current filters."
-                        compact
-                    />
-                )}
-            </div>
-
-            <div className="flex justify-center">
-                <button
-                    type="button"
-                    onClick={clearAllFilters}
-                    className="rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm text-white/70 hover:text-white hover:bg-white/10"
-                >
-                    Reset analytics filters
-                </button>
-            </div>
-
-            {trendZoomOpen && (
-                <TrendZoomModal trend={data.trend} period={period} onClose={() => setTrendZoomOpen(false)} />
-            )}
-        </div>
-    );
-}
-
-function DatePickerButton({
-    label,
-    value,
-    inputRef,
-    onChange,
-    onClick,
-}: {
-    label: string;
-    value: string;
-    inputRef: React.RefObject<HTMLInputElement | null>;
-    onChange: (value: string) => void;
-    onClick: () => void;
-}) {
-    const displayValue = value ? formatDateForButton(value) : 'Pick date';
-
-    return (
-        <div className="relative">
-            <button
-                type="button"
-                onClick={onClick}
-                aria-label={label}
-                className="flex w-full items-center justify-center gap-3 rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-white/80 hover:bg-white/10 transition"
-            >
-                <CalendarDaysIcon className="h-4 w-4 shrink-0 text-white/50" />
-                <span className="truncate text-white/75">{displayValue}</span>
-            </button>
-            <input
-                ref={inputRef}
-                type="date"
-                className="pointer-events-none absolute h-0 w-0 opacity-0"
-                value={value}
-                onChange={(e) => onChange(e.target.value)}
-            />
-        </div>
-    );
-}
-
-function TrendCard({
-    trend,
-    period,
-    onZoom,
-}: {
-    trend: AnalyticsTrendPoint[];
-    period: 'month' | 'year' | 'range';
-    onZoom: () => void;
-}) {
-    const values = trend.map((point) => Number(point.spent));
-    const max = Math.max(...values, 1);
-    const height = 380;
-    const width = Math.max(1200, trend.length * 82);
-    const padX = 76;
-    const padTop = 36;
-    const padBottom = 80;
-    const innerWidth = width - padX * 2;
-    const innerHeight = height - padTop - padBottom;
-    const step = trend.length > 1 ? innerWidth / (trend.length - 1) : 0;
-
-    const linePoints = trend.map((point, index) => {
-        const x = padX + index * step;
-        const y = padTop + innerHeight - (Number(point.spent) / max) * innerHeight;
-        return { x, y, label: point.label };
-    });
-
-    const linePath = linePoints
-        .map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x} ${point.y}`)
-        .join(' ');
-    const areaPath =
-        linePoints.length > 0
-            ? `${linePath} L ${linePoints[linePoints.length - 1].x} ${height - padBottom} L ${linePoints[0].x} ${height - padBottom} Z`
-            : '';
-
-    const tickCount = period === 'year' ? 6 : 8;
-    const tickStep = Math.max(1, Math.ceil(Math.max(linePoints.length, 1) / tickCount));
-
-    return (
-        <button
-            type="button"
-            onClick={onZoom}
-            className="w-full rounded-3xl border border-white/10 bg-black/25 backdrop-blur-md p-5 overflow-hidden text-left transition hover:bg-black/30"
-        >
-            <div className="flex items-center justify-between gap-4">
-                <div className="text-lg font-semibold text-white">Spending trend</div>
-            </div>
-
-            <div className="mt-4 overflow-hidden rounded-2xl border border-white/10 bg-slate-950/60">
-                <div className="overflow-x-auto no-scrollbar">
-                    <svg viewBox={`0 0 ${width} ${height}`} className="h-[320px] min-w-[1000px] w-full">
-                        <defs>
-                            <linearGradient id="trendFill" x1="0" y1="0" x2="0" y2="1">
-                                <stop offset="0%" stopColor="#38bdf8" stopOpacity="0.35" />
-                                <stop offset="100%" stopColor="#38bdf8" stopOpacity="0.02" />
-                            </linearGradient>
-                        </defs>
-
-                        {[0, 0.25, 0.5, 0.75, 1].map((ratio) => {
-                            const y = padTop + innerHeight - innerHeight * ratio;
-                            return (
-                                <g key={ratio}>
-                                    <line x1={padX} x2={width - padX} y1={y} y2={y} stroke="rgba(255,255,255,0.08)" strokeDasharray="5 6" />
-                                    <text x={16} y={y + 4} fill="rgba(255,255,255,0.35)" fontSize="18">
-                                        {formatAxisValue(max * ratio)}
-                                    </text>
-                                </g>
-                            );
-                        })}
-
-                        {areaPath && <path d={areaPath} fill="url(#trendFill)" />}
-                        {linePath && <path d={linePath} fill="none" stroke="#38bdf8" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" />}
-
-                        {linePoints.map((point) => (
-                            <circle key={`${point.label}-${point.x}`} cx={point.x} cy={point.y} r="6" fill="#e0f2fe" stroke="#0284c7" strokeWidth="4" />
-                        ))}
-
-                        {linePoints.map((point, index) => {
-                            if (index % tickStep !== 0 && index !== linePoints.length - 1) return null;
-                            return (
-                                <text key={`${point.label}-${index}`} x={point.x} y={height - 28} fill="rgba(255,255,255,0.45)" fontSize="16" textAnchor="middle">
-                                    {point.label}
-                                </text>
-                            );
-                        })}
-                    </svg>
-                </div>
-            </div>
-        </button>
-    );
-}
-
-function RingCard({
-    title,
-    slices,
-    emptyMessage,
-    compact = false,
-}: {
-    title: string;
-    slices: { label: string; value: number }[];
-    emptyMessage: string;
-    compact?: boolean;
-}) {
-    const total = slices.reduce((sum, slice) => sum + slice.value, 0);
-    const radius = compact ? 70 : 82;
-    const strokeWidth = compact ? 18 : 22;
-    const circumference = 2 * Math.PI * radius;
-    const segments = slices.reduce(
-        (acc, slice, index) => {
-            const portion = total > 0 ? slice.value / total : 0;
-            const dash = Math.max(portion * circumference, 0.01);
-            acc.push({
-                label: slice.label,
-                color: COLORS[index % COLORS.length],
-                dash,
-                offset: acc.length === 0 ? 0 : acc[acc.length - 1].offset + acc[acc.length - 1].dash,
-            });
-            return acc;
-        },
-        [] as Array<{ label: string; color: string; dash: number; offset: number }>,
-    );
-
-    return (
-        <div className="rounded-3xl border border-white/10 bg-black/25 backdrop-blur-md p-5 overflow-hidden">
-            <div className="text-lg font-semibold text-white">{title}</div>
-
-            {total > 0 ? (
-                <div className="mt-4 space-y-4">
-                    <div className="flex items-center justify-center">
-                        <svg viewBox="0 0 220 220" className={compact ? 'h-48 w-48' : 'h-56 w-56'}>
-                            <circle cx="110" cy="110" r={radius} fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth={strokeWidth} />
-                            {segments.map((segment) => (
-                                <circle
-                                    key={segment.label}
-                                    cx="110"
-                                    cy="110"
-                                    r={radius}
-                                    fill="none"
-                                    stroke={segment.color}
-                                    strokeWidth={strokeWidth}
-                                    strokeDasharray={`${segment.dash} ${circumference}`}
-                                    strokeDashoffset={-segment.offset}
-                                    transform="rotate(-90 110 110)"
-                                    strokeLinecap="butt"
-                                />
-                            ))}
-                            <circle cx="110" cy="110" r={radius - strokeWidth * 0.55} fill="#050816" opacity="0.96" />
-                            <text x="110" y="106" textAnchor="middle" fill="white" fontSize="18" fontWeight="700">
-                                {formatMKD(total)}
-                            </text>
-                            <text x="110" y="128" textAnchor="middle" fill="rgba(255,255,255,0.45)" fontSize="12">
-                                inclusive spend
-                            </text>
-                        </svg>
-                    </div>
-
-                    <div className="space-y-2">
-                        {slices.map((slice, index) => {
-                            const pct = total > 0 ? Math.round((slice.value / total) * 100) : 0;
-                            return (
-                                <div key={slice.label} className="flex items-center gap-3 rounded-2xl border border-white/8 bg-white/5 px-4 py-3 min-w-0">
-                                    <span className="h-3 w-3 rounded-full shrink-0" style={{ backgroundColor: COLORS[index % COLORS.length] }} />
-                                    <div className="min-w-0 flex-1">
-                                        <div className="truncate text-sm font-medium text-white">{slice.label}</div>
-                                        <div className="text-xs text-white/45">{pct}% of total</div>
-                                    </div>
-                                    <div className="text-sm font-semibold text-white whitespace-nowrap">{formatMKD(slice.value)}</div>
-                                </div>
-                            );
-                        })}
-                    </div>
-                </div>
-            ) : (
-                <div className="mt-4 rounded-2xl border border-dashed border-white/12 bg-white/5 px-4 py-8 text-center text-sm text-white/50">
-                    {emptyMessage}
-                </div>
-            )}
-        </div>
-    );
-}
-
-function TrendZoomModal({
-    trend,
-    period,
-    onClose,
-}: {
-    trend: AnalyticsTrendPoint[];
-    period: 'month' | 'year' | 'range';
-    onClose: () => void;
-}) {
-    return (
-        <div className="fixed inset-0 z-[70] flex items-center justify-center bg-black/70 px-4 py-6 backdrop-blur-sm">
-            <div className="relative w-full max-w-[96vw] rounded-3xl border border-white/10 bg-slate-950/95 shadow-2xl">
-                <div className="flex items-center justify-between gap-4 border-b border-white/10 px-4 py-3">
-                    <div className="text-lg font-semibold text-white">Spending trend</div>
-                    <button
-                        type="button"
-                        onClick={onClose}
-                        className="rounded-full border border-white/10 bg-white/5 p-2 text-white/70 hover:text-white hover:bg-white/10"
-                        aria-label="Close trend chart"
-                    >
-                        <XMarkIcon className="h-5 w-5" />
-                    </button>
-                </div>
-                <div className="max-h-[82vh] overflow-auto p-4">
-                    <div className="min-w-[1400px]">
-                        <TrendGraph trend={trend} period={period} zoomed />
-                    </div>
-                </div>
-            </div>
-        </div>
-    );
-}
-
-function TrendGraph({
-    trend,
-    period,
-    zoomed = false,
-}: {
-    trend: AnalyticsTrendPoint[];
-    period: 'month' | 'year' | 'range';
-    zoomed?: boolean;
-}) {
-    const values = trend.map((point) => Number(point.spent));
-    const max = Math.max(...values, 1);
-    const height = zoomed ? 560 : 380;
-    const width = Math.max(1200, trend.length * 82);
-    const padX = zoomed ? 88 : 76;
-    const padTop = zoomed ? 44 : 36;
-    const padBottom = zoomed ? 96 : 80;
-    const innerWidth = width - padX * 2;
-    const innerHeight = height - padTop - padBottom;
-    const step = trend.length > 1 ? innerWidth / (trend.length - 1) : 0;
-
-    const linePoints = trend.map((point, index) => {
-        const x = padX + index * step;
-        const y = padTop + innerHeight - (Number(point.spent) / max) * innerHeight;
-        return { x, y, label: point.label };
-    });
-
-    const linePath = linePoints
-        .map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x} ${point.y}`)
-        .join(' ');
-    const areaPath =
-        linePoints.length > 0
-            ? `${linePath} L ${linePoints[linePoints.length - 1].x} ${height - padBottom} L ${linePoints[0].x} ${height - padBottom} Z`
-            : '';
-
-    const tickCount = period === 'year' ? 6 : 8;
-    const tickStep = Math.max(1, Math.ceil(Math.max(linePoints.length, 1) / tickCount));
-
-    return (
-        <div className="rounded-3xl border border-white/10 bg-black/25 backdrop-blur-md p-5 overflow-hidden">
-            <div className="mb-4 flex items-center justify-between gap-4">
-                <div className="text-lg font-semibold text-white">Spending trend</div>
-            </div>
-
-            <div className="overflow-x-auto rounded-2xl border border-white/10 bg-slate-950/60">
-                <svg viewBox={`0 0 ${width} ${height}`} className="h-[520px] min-w-[1400px] w-full">
-                    <defs>
-                        <linearGradient id="trendFillZoom" x1="0" y1="0" x2="0" y2="1">
-                            <stop offset="0%" stopColor="#38bdf8" stopOpacity="0.35" />
-                            <stop offset="100%" stopColor="#38bdf8" stopOpacity="0.02" />
-                        </linearGradient>
-                    </defs>
-
-                    {[0, 0.25, 0.5, 0.75, 1].map((ratio) => {
-                        const y = padTop + innerHeight - innerHeight * ratio;
-                        return (
-                            <g key={ratio}>
-                                <line x1={padX} x2={width - padX} y1={y} y2={y} stroke="rgba(255,255,255,0.08)" strokeDasharray="5 6" />
-                                <text x={18} y={y + 5} fill="rgba(255,255,255,0.4)" fontSize="18">
-                                    {formatAxisValue(max * ratio)}
-                                </text>
-                            </g>
-                        );
-                    })}
-
-                    {areaPath && <path d={areaPath} fill="url(#trendFillZoom)" />}
-                    {linePath && <path d={linePath} fill="none" stroke="#38bdf8" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" />}
-
-                    {linePoints.map((point) => (
-                        <circle key={`${point.label}-${point.x}`} cx={point.x} cy={point.y} r="6" fill="#e0f2fe" stroke="#0284c7" strokeWidth="4" />
-                    ))}
-
-                    {linePoints.map((point, index) => {
-                        if (index % tickStep !== 0 && index !== linePoints.length - 1) return null;
-                        return (
-                            <text key={`${point.label}-${index}`} x={point.x} y={height - 32} fill="rgba(255,255,255,0.45)" fontSize="16" textAnchor="middle">
-                                {point.label}
-                            </text>
-                        );
-                    })}
-                </svg>
-            </div>
-        </div>
-    );
-}
-
-function toSlices(items: AnalyticsTagTotal[]) {
-    return items.map((item) => ({
-        label: item.tag_name,
-        value: Number(item.spent),
-    }));
-}
-
-function formatAxisValue(value: number) {
-    if (value <= 0) {
-        return '0';
-    }
-
-    if (value >= 1000) {
-        return `${Math.round(value / 1000)}k`;
-    }
-
-    return String(Math.round(value));
-}
-
-function toDateInputValue(date: Date) {
-    const year = date.getFullYear();
-    const month = String(date.getMonth() + 1).padStart(2, '0');
-    const day = String(date.getDate()).padStart(2, '0');
-    return `${year}-${month}-${day}`;
-}
-
-function formatDateForButton(value: string) {
-    const date = new Date(`${value}T00:00:00`);
-    if (Number.isNaN(date.getTime())) {
-        return value;
-    }
-
-    return new Intl.DateTimeFormat('en-US', {
-        month: 'short',
-        day: 'numeric',
-        year: 'numeric',
-    }).format(date);
-}
Index: p/(app)/analytics/page.tsx
===================================================================
--- app/(app)/analytics/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,63 +1,0 @@
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { poppins } from '@/app/ui/fonts';
-import { getAnalyticsData } from '@/app/lib/queries';
-import AnalyticsClient from './analytics-client';
-
-export default async function Page(props: {
-    searchParams?: Promise<{
-        query?: string;
-        accountId?: string;
-        period?: string;
-        startDate?: string;
-        endDate?: string;
-        focusTags?: string;
-    }>;
-}) {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login?callbackUrl=/analytics');
-    }
-
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        redirect('/login?callbackUrl=/analytics');
-    }
-
-    const searchParams = await props.searchParams;
-    const query = searchParams?.query || '';
-    const accountId = searchParams?.accountId ? Number(searchParams.accountId) : undefined;
-    const period = searchParams?.period === 'year' || searchParams?.period === 'range' ? searchParams.period : 'month';
-    const startDate = searchParams?.startDate || undefined;
-    const endDate = searchParams?.endDate || undefined;
-    const focusTags = searchParams?.focusTags ? searchParams.focusTags.split(',').filter(Boolean) : [];
-
-    const data = await getAnalyticsData({
-        userId,
-        query,
-        accountId: Number.isInteger(accountId) ? accountId : undefined,
-        period,
-        startDate,
-        endDate,
-        focusTags,
-    });
-
-    return (
-        <div className="w-full px-6 pt-10 pb-10">
-            <h1
-                className={`${poppins.className}
-          text-[40px]
-          leading-tight
-          tracking-tight
-          font-semibold
-          text-center
-          text-white
-        `}
-            >
-                Analytics
-            </h1>
-
-            <AnalyticsClient data={data} userId={userId} />
-        </div>
-    );
-}
Index: p/(app)/dashboard/accounts-section.tsx
===================================================================
--- app/(app)/dashboard/accounts-section.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,371 +1,0 @@
-'use client';
-
-import { useEffect, useMemo, useState } from 'react';
-import type { DashboardAccount } from '@/app/lib/queries';
-import { formatMKD } from '@/app/lib/utils';
-import { ArrowsUpDownIcon } from '@heroicons/react/24/outline';
-
-type Props = {
-    userId: number;
-    accounts: DashboardAccount[];
-};
-
-function storageKey(userId: number) {
-    return `fein:accountsOrder:v1:${userId}`;
-}
-
-function collapsedKey(userId: number) {
-    return `fein:accountsCollapsed:v1:${userId}`;
-}
-
-export default function AccountsSection({ userId, accounts }: Props) {
-    const [collapsed, setCollapsed] = useState(true);
-    const [editMode, setEditMode] = useState(false);
-
-    // order is stored as list of account ids
-    const [order, setOrder] = useState<number[] | null>(null);
-
-    // load order and collapsed state from localStorage
-    useEffect(() => {
-        try {
-            const raw = localStorage.getItem(storageKey(userId));
-            if (!raw) {
-                setOrder(accounts.map((a) => a.transaction_account_id));
-            } else {
-                const parsed = JSON.parse(raw) as number[];
-                setOrder(parsed);
-            }
-        } catch {
-            setOrder(accounts.map((a) => a.transaction_account_id));
-        }
-
-        try {
-            const savedCollapsed = localStorage.getItem(collapsedKey(userId));
-            if (savedCollapsed !== null) {
-                setCollapsed(savedCollapsed === 'true');
-            }
-            // else stays at the default (true)
-        } catch {
-            // ignore
-        }
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [userId]);
-
-    // keep order in sync if accounts change (new account added)
-    useEffect(() => {
-        if (!order) {
-            return;
-        }
-        const ids = accounts.map((a) => a.transaction_account_id);
-        const missing = ids.filter((id) => !order.includes(id));
-        if (missing.length === 0) {
-            return;
-        }
-
-        const next = [...order, ...missing];
-        setOrder(next);
-        localStorage.setItem(storageKey(userId), JSON.stringify(next));
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [accounts, order]);
-
-    const accountsById = useMemo(() => {
-        const m = new Map<number, DashboardAccount>();
-        for (const a of accounts) {
-            m.set(a.transaction_account_id, a);
-        }
-        return m;
-    }, [accounts]);
-
-    const orderedAccounts = useMemo(() => {
-        if (!order) {
-            return accounts;
-        }
-        const list: DashboardAccount[] = [];
-        for (const id of order) {
-            const acc = accountsById.get(id);
-            if (acc) {
-                list.push(acc);
-            }
-        }
-        // in case localStorage has old ids, append any not included
-        const appended = accounts.filter(
-            (a) => !list.some((x) => x.transaction_account_id === a.transaction_account_id),
-        );
-
-        return [...list, ...appended];
-    }, [accounts, accountsById, order]);
-
-    const count = orderedAccounts.length;
-    const hasAccounts = count > 0;
-    const canCollapse = count > 1;
-    const canReorder = count > 1;
-    const moreCount = Math.max(0, count - 1);
-
-    useEffect(() => {
-        // If 0 or 1 accounts, collapse/edit should not be possible
-        if (!canCollapse && collapsed) {
-            setCollapsed(false);
-            localStorage.setItem(collapsedKey(userId), 'false');
-        }
-        if (!canReorder && editMode) {
-            setEditMode(false);
-        }
-    }, [canCollapse, canReorder, collapsed, editMode, userId]);
-
-    function persist(nextOrder: number[]) {
-        setOrder(nextOrder);
-        localStorage.setItem(storageKey(userId), JSON.stringify(nextOrder));
-    }
-
-    // drag & drop
-    const [dragId, setDragId] = useState<number | null>(null);
-
-    function move(from: number, to: number) {
-        if (!order) {
-            return;
-        }
-        if (from === to) {
-            return;
-        }
-        const next = [...order];
-        const [item] = next.splice(from, 1);
-        next.splice(to, 0, item);
-        persist(next);
-    }
-
-    function moveUp(idx: number) {
-        if (!order) {
-            return;
-        }
-        if (idx <= 0) {
-            return;
-        }
-        move(idx, idx - 1);
-    }
-
-    function moveDown(idx: number) {
-        if (!order) {
-            return;
-        }
-        if (idx >= order.length - 1) {
-            return;
-        }
-        move(idx, idx + 1);
-    }
-
-    return (
-        <div className="mt-8">
-            {/* Header row */}
-            <div className="flex items-center justify-between">
-                <div className="text-white/90 text-xl font-semibold">Accounts</div>
-
-                <div className="flex items-center gap-3">
-                    {canCollapse && !collapsed && !editMode && (
-                        <button
-                            type="button"
-                            onClick={() => {
-                                setCollapsed(true);
-                                localStorage.setItem(collapsedKey(userId), 'true');
-                            }}
-                            className="text-white/60 hover:text-white/90 text-sm transition"
-                        >
-                            Collapse
-                        </button>
-                    )}
-
-                    {canReorder && (
-                        <button
-                            type="button"
-                            onClick={() => {
-                                setEditMode((v) => !v);
-                                setCollapsed(false); // editing implies expanded
-                                localStorage.setItem(collapsedKey(userId), 'false');
-                            }}
-                            className="text-white/60 hover:text-white/90 text-sm transition flex items-center"
-                            aria-label={editMode ? 'Done reordering' : 'Reorder accounts'}
-                            title={editMode ? 'Done' : 'Reorder'}
-                        >
-                            {editMode ? 'Done' : <ArrowsUpDownIcon className="h-5 w-5" />}
-                        </button>
-                    )}
-                </div>
-            </div>
-
-            {/* Collapsed stack */}
-            {canCollapse && collapsed ? (
-                <div className="mt-5 relative">
-                    {/* Ghost cards behind (blank, same style) */}
-                    <div
-                        aria-hidden
-                        className="
-                            absolute
-                            left-1/2
-                            top-10
-                            -translate-x-1/2
-                            w-[92%]
-                            h-[112px]
-                            rounded-2xl
-                            bg-blue-600/20
-                            border border-white/10
-                            backdrop-blur-md
-                            shadow-lg
-                        "
-                        style={{
-                            transform: 'translateY(10px) scale(0.96)',
-                            zIndex: 1,
-                            filter: 'saturate(0.95)',
-                        }}
-                    />
-
-                    {moreCount > 1 && (
-                        <div
-                            aria-hidden
-                            className="
-                                absolute
-                                left-1/2
-                                top-10
-                                -translate-x-1/2
-                                w-[92%]
-                                h-[112px]
-                                rounded-2xl
-                                bg-blue-700/20
-                                border border-white/10
-                                backdrop-blur-md
-                                shadow-md
-                            "
-                            style={{
-                                transform: 'translateY(45px) scale(0.82)',
-                                zIndex: 0,
-                                filter: 'saturate(0.95)',
-                            }}
-                        />
-                    )}
-
-                    {/* the actual top card */}
-                    <div className="relative z-10">
-                        <AccountCard acc={orderedAccounts[0]} />
-                    </div>
-
-                    {/* Spacer so section takes height */}
-                    <div style={{ height: 70 }} />
-
-                    <div className="flex justify-center items-center">
-                        {moreCount > 0 && (
-                            <button
-                                type="button"
-                                onClick={() => {
-                                    setCollapsed(false);
-                                    localStorage.setItem(collapsedKey(userId), 'false');
-                                }}
-                                className="text-white/60 hover:text-white/90 text-sm transition"
-                            >
-                                Expand {moreCount} more
-                            </button>
-                        )}
-                    </div>
-                </div>
-            ) : (
-                // Expanded list (reorderable in edit mode)
-                <div className="mt-5">
-                    {hasAccounts ? (
-                        <div className="space-y-5">
-                            {orderedAccounts.map((acc, idx) => (
-                                <div
-                                    key={acc.transaction_account_id}
-                                    draggable={editMode}
-                                    onDragStart={() => {
-                                        setDragId(acc.transaction_account_id);
-                                    }}
-                                    onDragOver={(e) => {
-                                        if (!editMode) {
-                                            return;
-                                        }
-                                        e.preventDefault();
-                                    }}
-                                    onDrop={() => {
-                                        if (!editMode) {
-                                            return;
-                                        }
-                                        if (!dragId || !order) {
-                                            return;
-                                        }
-                                        const from = order.indexOf(dragId);
-                                        const to = order.indexOf(acc.transaction_account_id);
-                                        if (from >= 0 && to >= 0) {
-                                            move(from, to);
-                                        }
-                                        setDragId(null);
-                                    }}
-                                    className={editMode ? 'cursor-grab active:cursor-grabbing' : ''}
-                                >
-                                    <AccountCard acc={acc} />
-
-                                    {editMode && order && (
-                                        <div className="mt-2 flex justify-end gap-2">
-                                            <button
-                                                type="button"
-                                                onClick={() => {
-                                                    moveUp(idx);
-                                                }}
-                                                className="text-xs text-white/60 hover:text-white/90 border border-white/10 rounded-lg px-3 py-1 bg-black/20"
-                                            >
-                                                Up
-                                            </button>
-                                            <button
-                                                type="button"
-                                                onClick={() => {
-                                                    moveDown(idx);
-                                                }}
-                                                className="text-xs text-white/60 hover:text-white/90 border border-white/10 rounded-lg px-3 py-1 bg-black/20"
-                                            >
-                                                Down
-                                            </button>
-                                        </div>
-                                    )}
-                                </div>
-                            ))}
-                        </div>
-                    ) : (
-                        <div className="text-white/60 text-sm">No accounts yet.</div>
-                    )}
-                </div>
-            )}
-        </div>
-    );
-}
-
-function AccountCard({
-    acc,
-    compact = false,
-}: {
-    acc: DashboardAccount;
-    compact?: boolean;
-}) {
-    return (
-        <div
-            className={`
-                relative
-                overflow-hidden
-                rounded-2xl
-                px-6
-                ${compact ? 'py-5' : 'py-6'}
-                bg-blue-600/25
-                border
-                border-white/10
-                backdrop-blur-md
-                shadow-lg
-            `}
-        >
-            <div className="pointer-events-none absolute inset-0 bg-gradient-to-br from-white/10 to-transparent" />
-
-            <div className="relative">
-                <div className="text-white text-2xl font-semibold">
-                    {acc.account_name ?? 'Account'}
-                </div>
-                <div className="mt-3 text-white text-2xl font-semibold">
-                    {formatMKD(acc.balance)}
-                </div>
-            </div>
-        </div>
-    );
-}
Index: p/(app)/dashboard/page.tsx
===================================================================
--- app/(app)/dashboard/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,153 +1,0 @@
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { poppins } from '@/app/ui/fonts';
-import { getDashboardData } from '@/app/lib/queries';
-import { formatMKD } from '@/app/lib/utils';
-import AccountsSection from './accounts-section';
-
-
-export default async function DashboardPage() {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login?callbackUrl=/dashboard');
-    }
-
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        redirect('/login?callbackUrl=/dashboard');
-    }
-
-    const data = await getDashboardData(userId);
-
-    const displayName = session.user.name ?? 'Account name';
-
-    return (
-        <div className="w-full px-6 pt-10 pb-10">
-            {/* Header name */}
-            <h1
-                className={`${poppins.className}
-                    text-[44px]
-                    leading-tight
-                    tracking-tight
-                    font-semibold
-                    text-white
-                `}
-            >
-                {displayName}
-            </h1>
-
-            {/* Total balance */}
-            <div className="mt-10">
-                <div className="text-white/80 text-xl font-semibold">Total Balance</div>
-                <div
-                    className={`${poppins.className}
-                        mt-3
-                        text-[40px]
-                        leading-tight
-                        tracking-tight
-                        font-semibold
-                        text-white
-                    `}
-                >
-                    {formatMKD(data.totalBalance)}
-                </div>
-            </div>
-
-            {/* Accounts (stacked cards like screenshot) */}
-            <AccountsSection userId={userId} accounts={data.accounts} />
-
-            {/* Quick analytics cards */}
-            <div className="mt-8 grid grid-cols-3 gap-3">
-                <div className="rounded-xl bg-purple-700/45 border border-white/10 backdrop-blur-md px-3 py-4">
-                    <div className="text-white text-sm font-semibold leading-tight">
-                        Daily budget
-                        <br />
-                        until end of
-                        <br />
-                        month
-                    </div>
-                    <div className="mt-4 text-white text-lg font-semibold">
-                        {formatMKD(data.dailyBudgetUntilEndOfMonth)}
-                    </div>
-                </div>
-
-                <div className="rounded-xl bg-purple-700/45 border border-white/10 backdrop-blur-md px-3 py-4">
-                    <div className="text-white text-sm font-semibold leading-tight">
-                        Three day
-                        <br />
-                        spending
-                        <br />
-                        average
-                    </div>
-                    <div className="mt-4 text-white text-lg font-semibold">
-                        {formatMKD(data.threeDaySpendingAvg)}
-                    </div>
-                </div>
-
-                <div className="rounded-xl bg-purple-700/45 border border-white/10 backdrop-blur-md px-3 py-4">
-                    <div className="text-white text-sm font-semibold leading-tight">
-                        Daily
-                        <br />
-                        spending
-                        <br />
-                        average
-                    </div>
-                    <div className="mt-4 text-white text-lg font-semibold">
-                        {formatMKD(data.dailySpendingAvgMonthToDate)}
-                    </div>
-                </div>
-            </div>
-
-            {/* Transaction history */}
-            <div className="mt-10">
-                <div className="text-white text-2xl font-semibold">Transaction History</div>
-
-                <div className="mt-4 space-y-4">
-                    {data.recentTransactions.length === 0 ? (
-                        <div className="text-white/60 text-sm">
-                            No transactions yet.
-                        </div>
-                    ) : (
-                        data.recentTransactions.map((tx) => {
-                            const net = Number(tx.net_amount);
-                            const isNegative = net < 0;
-
-                            return (
-                                <div
-                                    key={tx.transaction_id}
-                                    className="
-                                        rounded-2xl
-                                        px-5
-                                        py-4
-                                        bg-black/30
-                                        border border-white/10
-                                        backdrop-blur-md
-                                        flex
-                                        items-center
-                                        justify-between
-                                    "
-                                >
-                                    <div>
-                                        <div className="text-white text-lg font-semibold">
-                                            {tx.transaction_name ?? 'Transaction'}
-                                        </div>
-                                        <div className="text-white/50 text-sm">
-                                            {tx.primary_tag ?? ''}
-                                        </div>
-                                    </div>
-
-                                    <div
-                                        className={`text-xl font-semibold ${isNegative ? 'text-amber-400' : 'text-emerald-300'
-                                            }`}
-                                    >
-                                        {formatMKD(net)}
-                                    </div>
-                                </div>
-                            );
-                        })
-                    )}
-                </div>
-            </div>
-        </div>
-    );
-}
Index: p/(app)/history/account-filter.tsx
===================================================================
--- app/(app)/history/account-filter.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,10 +1,0 @@
-import AccountFilterIcon from '@/app/ui/account-filter-icon';
-import type { TransactionAccountLite } from '@/app/lib/queries';
-
-export default function AccountFilter({
-    accounts,
-}: {
-    accounts: TransactionAccountLite[];
-}) {
-    return <AccountFilterIcon accounts={accounts} resetPageOnChange />;
-}
Index: p/(app)/history/page.tsx
===================================================================
--- app/(app)/history/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,91 +1,0 @@
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { Suspense } from 'react';
-import { poppins } from '@/app/ui/fonts';
-import {
-    getHistoryTransactions,
-    getHistoryTransactionPages,
-    getUserTransactionAccounts,
-    getUserTagsForHistory,
-} from '@/app/lib/queries';
-import Search from './search';
-import AccountFilter from './account-filter';
-import TagFilter from './tag-filter';
-import TransactionList from './transaction-list';
-import Pagination from './pagination';
-
-export default async function HistoryPage(props: {
-    searchParams?: Promise<{
-        query?: string;
-        accountId?: string;
-        tags?: string;
-        page?: string;
-    }>;
-}) {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login?callbackUrl=/history');
-    }
-
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        redirect('/login?callbackUrl=/history');
-    }
-
-    const searchParams = await props.searchParams;
-    const query = searchParams?.query || '';
-    const accountId = searchParams?.accountId
-        ? Number(searchParams.accountId)
-        : undefined;
-    const selectedTags = searchParams?.tags
-        ? searchParams.tags.split(',').filter(Boolean)
-        : [];
-    const currentPage = Number(searchParams?.page) || 1;
-
-    const [transactions, totalPages, accounts, allTags] = await Promise.all([
-        getHistoryTransactions({ userId, accountId, query, tags: selectedTags, page: currentPage }),
-        getHistoryTransactionPages({ userId, accountId, query, tags: selectedTags }),
-        getUserTransactionAccounts(userId),
-        getUserTagsForHistory(userId),
-    ]);
-
-    return (
-        <div className="w-full px-6 pt-10 pb-10">
-            <h1
-                className={`${poppins.className}
-                    text-[40px]
-                    leading-tight
-                    tracking-tight
-                    font-semibold
-                    text-center
-                    text-white
-                `}
-            >
-                History
-            </h1>
-
-            <div className="mt-8 flex flex-col gap-3">
-                <div className="flex gap-2 items-center">
-                    <div className="flex-1 min-w-0">
-                        <Suspense fallback={null}>
-                            <Search placeholder="Name, tag, or account…" />
-                        </Suspense>
-                    </div>
-                    <Suspense fallback={null}>
-                        <AccountFilter accounts={accounts} />
-                    </Suspense>
-                </div>
-
-                <Suspense fallback={null}>
-                    <TagFilter tags={allTags} />
-                </Suspense>
-            </div>
-
-            <TransactionList transactions={transactions} />
-
-            <Suspense fallback={null}>
-                <Pagination totalPages={totalPages} />
-            </Suspense>
-        </div>
-    );
-}
Index: p/(app)/history/pagination.tsx
===================================================================
--- app/(app)/history/pagination.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,122 +1,0 @@
-'use client';
-
-import { usePathname, useSearchParams } from 'next/navigation';
-import Link from 'next/link';
-import clsx from 'clsx';
-import { generatePagination } from '@/app/lib/utils';
-import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
-
-export default function Pagination({ totalPages }: { totalPages: number }) {
-    const pathname = usePathname();
-    const searchParams = useSearchParams();
-    const currentPage = Number(searchParams.get('page')) || 1;
-
-    const allPages = generatePagination(currentPage, totalPages);
-
-    function createPageURL(pageNumber: number | string) {
-        const params = new URLSearchParams(searchParams);
-        params.set('page', pageNumber.toString());
-        return `${pathname}?${params.toString()}`;
-    }
-
-    if (totalPages <= 1) return null;
-
-    return (
-        <div className="mt-6 flex items-center justify-center gap-1">
-            <PaginationArrow
-                direction="left"
-                href={createPageURL(currentPage - 1)}
-                isDisabled={currentPage <= 1}
-            />
-
-            {allPages.map((page, index) => {
-                let position: 'first' | 'last' | 'single' | 'middle' | undefined;
-
-                if (index === 0) position = 'first';
-                if (index === allPages.length - 1) position = 'last';
-                if (allPages.length === 1) position = 'single';
-                if (page === '...') position = 'middle';
-
-                return (
-                    <PaginationNumber
-                        key={`${page}-${index}`}
-                        href={createPageURL(page)}
-                        page={page}
-                        position={position}
-                        isActive={currentPage === page}
-                    />
-                );
-            })}
-
-            <PaginationArrow
-                direction="right"
-                href={createPageURL(currentPage + 1)}
-                isDisabled={currentPage >= totalPages}
-            />
-        </div>
-    );
-}
-
-function PaginationNumber({
-    page,
-    href,
-    isActive,
-    position,
-}: {
-    page: number | string;
-    href: string;
-    position?: 'first' | 'last' | 'middle' | 'single';
-    isActive: boolean;
-}) {
-    const className = clsx(
-        'flex h-9 w-9 items-center justify-center text-sm rounded-lg transition',
-        {
-            'rounded-l-xl': position === 'first' || position === 'single',
-            'rounded-r-xl': position === 'last' || position === 'single',
-            'bg-blue-600 text-white': isActive,
-            'text-white/60 hover:text-white hover:bg-white/10': !isActive && position !== 'middle',
-            'text-white/40 pointer-events-none': position === 'middle',
-        },
-    );
-
-    return isActive || position === 'middle' ? (
-        <div className={className}>{page}</div>
-    ) : (
-        <Link href={href} className={className}>
-            {page}
-        </Link>
-    );
-}
-
-function PaginationArrow({
-    href,
-    direction,
-    isDisabled,
-}: {
-    href: string;
-    direction: 'left' | 'right';
-    isDisabled?: boolean;
-}) {
-    const className = clsx(
-        'flex h-9 w-9 items-center justify-center rounded-lg transition',
-        {
-            'pointer-events-none text-white/20': isDisabled,
-            'text-white/60 hover:text-white hover:bg-white/10': !isDisabled,
-        },
-    );
-
-    const icon =
-        direction === 'left' ? (
-            <ChevronLeftIcon className="h-4 w-4" />
-        ) : (
-            <ChevronRightIcon className="h-4 w-4" />
-        );
-
-    return isDisabled ? (
-        <div className={className}>{icon}</div>
-    ) : (
-        <Link href={href} className={className}>
-            {icon}
-        </Link>
-    );
-}
Index: p/(app)/history/search.tsx
===================================================================
--- app/(app)/history/search.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,5 +1,0 @@
-import UrlSearchInput from '@/app/ui/url-search-input';
-
-export default function Search({ placeholder }: { placeholder: string }) {
-    return <UrlSearchInput placeholder={placeholder} resetPageOnChange />;
-}
Index: p/(app)/history/tag-filter.tsx
===================================================================
--- app/(app)/history/tag-filter.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,109 +1,0 @@
-'use client';
-
-import { useSearchParams, usePathname, useRouter } from 'next/navigation';
-import { useRef, useCallback } from 'react';
-
-export default function TagFilter({ tags }: { tags: string[] }) {
-    const searchParams = useSearchParams();
-    const pathname = usePathname();
-    const { replace } = useRouter();
-
-    // Read selected tags from URL (?tags=food,transport)
-    const selectedRaw = searchParams.get('tags') ?? '';
-    const selected = selectedRaw ? selectedRaw.split(',').filter(Boolean) : [];
-
-    function toggle(tag: string) {
-        const params = new URLSearchParams(searchParams);
-        params.set('page', '1');
-
-        let next: string[];
-        if (selected.includes(tag)) {
-            next = selected.filter((t) => t !== tag);
-        } else {
-            next = [...selected, tag];
-        }
-
-        if (next.length > 0) {
-            params.set('tags', next.join(','));
-        } else {
-            params.delete('tags');
-        }
-
-        replace(`${pathname}?${params.toString()}`);
-    }
-
-    // ── Drag-to-scroll (mouse + touch) ──
-    const scrollRef = useRef<HTMLDivElement>(null);
-    const isDragging = useRef(false);
-    const startX = useRef(0);
-    const scrollLeft = useRef(0);
-    const dragDistance = useRef(0);
-
-    // 8px threshold: anything less is a tap, more is a drag
-    const DRAG_THRESHOLD = 8;
-
-    const onPointerDown = useCallback((e: React.PointerEvent) => {
-        const el = scrollRef.current;
-        if (!el) return;
-        isDragging.current = true;
-        dragDistance.current = 0;
-        startX.current = e.clientX;
-        scrollLeft.current = el.scrollLeft;
-    }, []);
-
-    const onPointerMove = useCallback((e: React.PointerEvent) => {
-        if (!isDragging.current || !scrollRef.current) return;
-        const dx = e.clientX - startX.current;
-        dragDistance.current = Math.abs(dx);
-        scrollRef.current.scrollLeft = scrollLeft.current - dx;
-    }, []);
-
-    const onPointerUp = useCallback(() => {
-        isDragging.current = false;
-    }, []);
-
-    // Suppress click only when the pointer moved beyond the threshold
-    const onClickCapture = useCallback((e: React.MouseEvent) => {
-        if (dragDistance.current >= DRAG_THRESHOLD) {
-            e.stopPropagation();
-            e.preventDefault();
-        }
-    }, []);
-
-    if (tags.length === 0) return null;
-
-    return (
-        <div
-            ref={scrollRef}
-            className="overflow-x-auto no-scrollbar -mx-6 px-6 cursor-grab active:cursor-grabbing select-none touch-pan-x"
-            onPointerDown={onPointerDown}
-            onPointerMove={onPointerMove}
-            onPointerUp={onPointerUp}
-            onPointerCancel={onPointerUp}
-            onClickCapture={onClickCapture}
-        >
-            <div className="flex gap-2 w-max">
-                {tags.map((tag) => {
-                    const isActive = selected.includes(tag);
-                    return (
-                        <button
-                            key={tag}
-                            type="button"
-                            onClick={() => toggle(tag)}
-                            className={`
-                                whitespace-nowrap rounded-full px-4 py-1.5 text-sm font-medium
-                                border transition-all shrink-0
-                                ${isActive
-                                    ? 'bg-blue-600 border-blue-500 text-white'
-                                    : 'bg-white/10 border-white/10 text-white/60 hover:bg-white/15 hover:text-white/80'
-                                }
-                            `}
-                        >
-                            {tag}
-                        </button>
-                    );
-                })}
-            </div>
-        </div>
-    );
-}
Index: p/(app)/history/transaction-list.tsx
===================================================================
--- app/(app)/history/transaction-list.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,83 +1,0 @@
-import { formatMKD, formatDateToLocal } from '@/app/lib/utils';
-import type { HistoryTransaction } from '@/app/lib/queries';
-
-export default function TransactionList({
-    transactions,
-}: {
-    transactions: HistoryTransaction[];
-}) {
-    if (transactions.length === 0) {
-        return (
-            <div className="mt-6 text-center text-white/50 text-sm py-10">
-                No transactions found.
-            </div>
-        );
-    }
-
-    return (
-        <div className="mt-4 space-y-3">
-            {transactions.map((tx) => {
-                const net = Number(tx.net_amount);
-                const isNegative = net < 0;
-
-                // postgres.js may return tags as a parsed array or as a PG
-                // array literal string like "{food,transport}". Normalise to
-                // a plain JS string[] so the pills always render.
-                const rawTags: string[] = Array.isArray(tx.tags)
-                    ? tx.tags.filter(Boolean)
-                    : typeof tx.tags === 'string' && (tx.tags as string).length > 2
-                      ? (tx.tags as string)
-                            .replace(/^\{|\}$/g, '')
-                            .split(',')
-                            .map((s) => s.trim())
-                            .filter(Boolean)
-                      : [];
-
-                // Separate note tags (__note:…) from regular tags
-                const tags = rawTags.filter((t) => !t.startsWith('__note:'));
-                const notes = rawTags
-                    .filter((t) => t.startsWith('__note:'))
-                    .map((t) => t.slice('__note:'.length));
-
-                return (
-                    <div
-                        key={tx.transaction_id}
-                        className="rounded-2xl px-5 py-4 bg-black/30 border border-white/10 backdrop-blur-md flex items-center justify-between"
-                    >
-                        <div className="min-w-0 flex-1 mr-3">
-                            <div className="text-white text-lg font-semibold truncate">
-                                {tx.transaction_name ?? 'Transaction'}
-                            </div>
-                            {tags.length > 0 && (
-                                <div className="mt-1.5 flex flex-wrap gap-1.5">
-                                    {tags.map((tag) => (
-                                        <span
-                                            key={tag}
-                                            className="inline-block rounded-full bg-white/15 border border-white/10 px-2.5 py-0.5 text-xs text-white/70"
-                                        >
-                                            {tag}
-                                        </span>
-                                    ))}
-                                </div>
-                            )}
-                            {notes.length > 0 && (
-                                <div className="mt-1 text-xs text-white/40 italic truncate">
-                                    {notes[0]}
-                                </div>
-                            )}
-                            <div className="mt-1 text-xs text-white/40">
-                                {formatDateToLocal(tx.date)}
-                            </div>
-                        </div>
-                        <div
-                            className={`text-xl font-semibold whitespace-nowrap ${isNegative ? 'text-amber-400' : 'text-emerald-300'
-                                }`}
-                        >
-                            {formatMKD(net)}
-                        </div>
-                    </div>
-                );
-            })}
-        </div>
-    );
-}
Index: p/(app)/layout.tsx
===================================================================
--- app/(app)/layout.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,31 +1,0 @@
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import BottomNav from '@/app/ui/bottom-nav';
-
-export default async function AppLayout({
-    children,
-}: {
-    children: React.ReactNode;
-}) {
-    const session = await auth();
-
-    if (!session) {
-        redirect('/login?callbackUrl=/dashboard');
-    }
-
-    return (
-        <div className="relative h-full overflow-hidden">
-            {/* Scrollable content inside phone shell */}
-            <main className="h-full overflow-y-auto no-scrollbar pb-[120px]">
-                {children}
-            </main>
-
-            {/* Bottom nav FLOATS INSIDE the phone shell */}
-            <div className="absolute inset-x-0 bottom-0 z-50 flex justify-center pb-4 pointer-events-none">
-                <div className="w-full pointer-events-auto">
-                    <BottomNav />
-                </div>
-            </div>
-        </div>
-    );
-}
Index: p/(app)/profile/actions.ts
===================================================================
--- app/(app)/profile/actions.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,96 +1,0 @@
-'use server';
-
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { sql } from '@/app/lib/db';
-import bcrypt from 'bcrypt';
-
-type ActionResult = string | undefined; // string = error message, undefined = success
-
-export async function updateProfile(
-    _prevState: ActionResult,
-    formData: FormData
-): Promise<ActionResult> {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login');
-    }
-
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        return 'Invalid session. Please log in again.';
-    }
-    const name = String(formData.get('name') ?? '').trim();
-    const email = String(formData.get('email') ?? '').trim().toLowerCase();
-
-    if (!name) {
-        return 'Name is required.';
-    }
-    if (!email || !email.includes('@')) {
-        return 'Please enter a valid email.';
-    }
-
-    // Email already exists check
-    const existing = await sql`
-        SELECT user_id FROM "user"
-        WHERE email = ${email} AND user_id != ${userId}
-    `;
-    if (existing.length > 0) {
-        return 'Email already exists.';
-    }
-
-    await sql`
-        UPDATE "user"
-        SET user_name = ${name},
-            email = ${email}
-        WHERE user_id = ${userId}
-    `;
-
-    redirect('/profile');
-}
-
-export async function updatePassword(
-    _prevState: ActionResult,
-    formData: FormData
-): Promise<ActionResult> {
-    const session = await auth();
-    if (!session?.user?.id) {
-        redirect('/login');
-    }
-
-    const userId = Number(session.user.id);
-    if (!Number.isInteger(userId)) {
-        return 'Invalid session. Please log in again.';
-    }
-    const currentPassword = String(formData.get('currentPassword') ?? '');
-    const newPassword = String(formData.get('newPassword') ?? '');
-
-    if (newPassword.length < 6) {
-        return 'New password must be at least 6 characters.';
-    }
-
-    const users = await sql`
-        SELECT password
-        FROM "user"
-        WHERE user_id = ${userId}
-    `;
-    const user = users[0];
-    if (!user) {
-        return 'User not found. Please log in again.';
-    }
-
-    const match = await bcrypt.compare(currentPassword, user.password);
-    if (!match) {
-        return 'Current password is incorrect.';
-    }
-
-    const hashed = await bcrypt.hash(newPassword, 10);
-
-    await sql`
-        UPDATE "user"
-        SET password = ${hashed}
-        WHERE user_id = ${userId}
-    `;
-
-    redirect('/profile');
-}
Index: p/(app)/profile/edit/page.tsx
===================================================================
--- app/(app)/profile/edit/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,56 +1,0 @@
-import { auth } from '@/auth';
-import { redirect } from 'next/navigation';
-import { poppins } from '@/app/ui/fonts';
-import { ProfileUpdateForm, PasswordUpdateForm } from '../profile-forms';
-import Link from 'next/link';
-
-
-export default async function EditProfilePage() {
-    const session = await auth();
-    if (!session?.user) {
-        redirect('/login');
-    }
-
-    return (
-        <div className="w-full px-6 pt-10 space-y-10 pb-10">
-
-            {/* Back */}
-            <div className="max-w-md mx-auto">
-                <Link
-                    href="/profile"
-                    className="inline-flex items-center text-white/60 hover:text-white/80 transition"
-                >
-                    <span className={`${poppins.className} text-sm`}>← Back</span>
-                </Link>
-            </div>
-
-            <h1
-                className={`${poppins.className}
-                    text-[40px]
-                    leading-tight
-                    tracking-tight
-                    font-semibold
-                    text-center
-                    text-white
-                `}
-            >
-                Edit profile
-            </h1>
-
-            <div className="max-w-md mx-auto space-y-8 pb-10">
-                {/* Account Info */}
-                <section className="rounded-3xl bg-white/5 backdrop-blur-md border border-white/10 p-6 space-y-5">
-                    <ProfileUpdateForm
-                        defaultName={session.user.name ?? ''}
-                        defaultEmail={session.user.email ?? ''}
-                    />
-                </section>
-
-                {/* Security */}
-                <section className="rounded-3xl bg-white/5 backdrop-blur-md border border-white/10 p-6 space-y-5">
-                    <PasswordUpdateForm />
-                </section>
-            </div>
-        </div>
-    );
-}
Index: p/(app)/profile/page.tsx
===================================================================
--- app/(app)/profile/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,119 +1,0 @@
-import Link from 'next/link';
-import { auth, signOut } from '@/auth';
-import { redirect } from 'next/navigation';
-import { ChevronRightIcon } from '@heroicons/react/24/outline';
-import { poppins } from '@/app/ui/fonts';
-
-export default async function ProfilePage() {
-    const session = await auth();
-    if (!session?.user) redirect('/login');
-
-    const name = session.user.name ?? 'Account name';
-    const email = session.user.email ?? 'account email';
-
-    return (
-        <div className="w-full px-6 pt-6 pb-10">
-            {/* Top title */}
-            <h1
-                className={`${poppins.className}
-                    text-[40px]
-                    font-semibold
-                    text-center
-                    text-white/90
-                    mt-2
-                `}
-            >
-                Profile
-            </h1>
-
-            {/* Center identity */}
-            <div className="mt-24 text-center">
-                <div
-                    className={`${poppins.className}
-                        text-[52px]
-                        leading-[1.05]
-                        font-semibold
-                        text-white
-                        tracking-tight
-                    `}
-                >
-                    {name}
-                </div>
-
-                <div className="mt-6 text-white/45 text-lg">
-                    {email}
-                </div>
-            </div>
-
-            {/* Action list */}
-            <div className="mt-24 space-y-4 max-w-md mx-auto">
-                <Link
-                    href="/profile/edit"
-                    className="
-                        flex items-center justify-between
-                        h-14
-                        rounded-2xl
-                        border border-white/35
-                        bg-white/5
-                        px-5
-                        text-white/55
-                        backdrop-blur-md
-                        transition
-                        hover:bg-white/10
-                    "
-                >
-                    <span className={`${poppins.className} text-base`}>Edit Profile</span>
-                    <ChevronRightIcon className="h-5 w-5 text-white/35" />
-                </Link>
-
-                <Link
-                    href="/profile/settings"
-                    className="
-                        flex items-center justify-between
-                        h-14
-                        rounded-2xl
-                        border border-white/35
-                        bg-white/5
-                        px-5
-                        text-white/55
-                        backdrop-blur-md
-                        transition
-                        hover:bg-white/10
-                    "
-                >
-                    <span className={`${poppins.className} text-base`}>Settings</span>
-                    <ChevronRightIcon className="h-5 w-5 text-white/35" />
-                </Link>
-
-                <form
-                    action={async () => {
-                        'use server';
-                        await signOut({ redirectTo: '/login' });
-                    }}
-                >
-                    <button
-                        type="submit"
-                        className="
-                            w-full
-                            flex items-center justify-between
-                            h-14
-                            rounded-2xl
-                            border border-white/35
-                            bg-white/5
-                            px-5
-                            backdrop-blur-md
-                            transition
-                            hover:bg-white/10
-                        "
-                    >
-                        <span className={`${poppins.className} text-base text-red-300`}>
-                            Sign Out
-                        </span>
-                        {/* no chevron in the screenshot, but if you want it remove the next line */}
-                        <span className="w-5" />
-                    </button>
-                </form>
-            </div>
-        </div>
-    );
-}
Index: p/(app)/profile/profile-forms.tsx
===================================================================
--- app/(app)/profile/profile-forms.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,98 +1,0 @@
-'use client';
-
-import React from 'react';
-import { updateProfile, updatePassword } from './actions';
-
-function ErrorLine({ error }: { error?: string }) {
-    if (!error) {
-        return null;
-    }
-    return <p className="text-red-400 text-sm">{error}</p>;
-}
-
-export function ProfileUpdateForm({
-    defaultName,
-    defaultEmail,
-}: {
-    defaultName: string;
-    defaultEmail: string;
-}) {
-    const [error, action, pending] = React.useActionState<string | undefined, FormData>(
-        updateProfile,
-        undefined
-    );
-
-    return (
-        <form action={action} className="space-y-4">
-            <div className="space-y-2">
-                <label className="text-white/70 text-sm">Name</label>
-                <input
-                    name="name"
-                    defaultValue={defaultName}
-                    required
-                    className="w-full rounded-xl bg-white/10 border border-white/10 px-4 py-3 text-white focus:ring-2 focus:ring-blue-500 outline-none"
-                />
-            </div>
-
-            <div className="space-y-2">
-                <label className="text-white/70 text-sm">Email</label>
-                <input
-                    name="email"
-                    defaultValue={defaultEmail}
-                    required
-                    className="w-full rounded-xl bg-white/10 border border-white/10 px-4 py-3 text-white focus:ring-2 focus:ring-blue-500 outline-none"
-                />
-            </div>
-
-            <ErrorLine error={error} />
-
-            <button
-                disabled={pending}
-                className="w-full bg-blue-600 hover:bg-blue-500 rounded-xl py-3 text-white font-medium transition disabled:opacity-50 disabled:cursor-not-allowed"
-            >
-                {pending ? 'Saving…' : 'Save Changes'}
-            </button>
-        </form>
-    );
-}
-
-export function PasswordUpdateForm() {
-    const [error, action, pending] = React.useActionState<string | undefined, FormData>(
-        updatePassword,
-        undefined
-    );
-
-    return (
-        <form action={action} className="space-y-4">
-            <div className="space-y-2">
-                <label className="text-white/70 text-sm">Current Password</label>
-                <input
-                    type="password"
-                    name="currentPassword"
-                    required
-                    className="w-full rounded-xl bg-white/10 border border-white/10 px-4 py-3 text-white focus:ring-2 focus:ring-blue-500 outline-none"
-                />
-            </div>
-
-            <div className="space-y-2">
-                <label className="text-white/70 text-sm">New Password</label>
-                <input
-                    type="password"
-                    name="newPassword"
-                    required
-                    minLength={6}
-                    className="w-full rounded-xl bg-white/10 border border-white/10 px-4 py-3 text-white focus:ring-2 focus:ring-blue-500 outline-none"
-                />
-            </div>
-
-            <ErrorLine error={error} />
-
-            <button
-                disabled={pending}
-                className="w-full bg-blue-600 hover:bg-blue-500 rounded-xl py-3 text-white font-medium transition disabled:opacity-50 disabled:cursor-not-allowed"
-            >
-                {pending ? 'Updating…' : 'Update Password'}
-            </button>
-        </form>
-    );
-}
Index: p/(app)/profile/settings/page.tsx
===================================================================
--- app/(app)/profile/settings/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,75 +1,0 @@
-import Link from 'next/link';
-import { poppins } from '@/app/ui/fonts';
-
-export default function ProfileSettingsPage() {
-    return (
-        <div className="w-full px-6 pt-6 pb-10">
-            {/* Back */}
-            <div className="max-w-md mx-auto">
-                <Link
-                    href="/profile"
-                    className="inline-flex items-center text-white/60 hover:text-white/80 transition"
-                >
-                    <span className={`${poppins.className} text-sm`}>← Back</span>
-                </Link>
-            </div>
-
-            {/* Title */}
-            <h1
-                className={`${poppins.className}
-                    text-[40px]
-                    leading-tight
-                    tracking-tight
-                    font-semibold
-                    text-center
-                    text-white
-                    mt-6
-                `}
-            >
-                Settings
-            </h1>
-
-            <div className="mt-10 max-w-md mx-auto space-y-4">
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-
-                <div className="rounded-2xl border border-white/35 bg-white/5 backdrop-blur-md px-5 py-4 text-white/70">
-                    (coming soon)
-                </div>
-            </div>
-        </div>
-    );
-}
Index: p/(auth)/actions.ts
===================================================================
--- app/(auth)/actions.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,94 +1,0 @@
-'use server'
-
-import { z } from 'zod';
-import { sql } from '@/app/lib/db';
-import { signIn } from '@/auth';
-import bcrypt from "bcryptjs";
-import { AuthError } from 'next-auth';
-
-export async function authenticate(
-    prevState: string | undefined,
-    formData: FormData,
-) {
-    try {
-        const redirectTo =
-            (formData.get('redirectTo') as string)?.startsWith('/')
-                ? (formData.get('redirectTo') as string)
-                : '/dashboard';
-
-        await signIn('credentials', {
-            ...Object.fromEntries(formData),
-            redirectTo,
-        });
-    } catch (error) {
-        if (error instanceof AuthError) {
-            switch (error.type) {
-                case 'CredentialsSignin':
-                    return 'Invalid email or password.';
-                default:
-                    return 'Something went wrong. Please try again.';
-            }
-        }
-        throw error;
-    }
-}
-
-export async function register(
-    prevState: string | undefined,
-    formData: FormData,
-) {
-    const schema = z.object({
-        user_name: z.string().min(1),
-        email: z.string().email(),
-        password: z.string().min(6),
-        redirectTo: z.string().optional(),
-    });
-
-    const parsed = schema.safeParse({
-        user_name: formData.get('user_name'),
-        email: formData.get('email'),
-        password: formData.get('password'),
-        redirectTo: formData.get('redirectTo'),
-    });
-
-    if (!parsed.success) {
-        return 'Invalid form data.';
-    }
-
-    const { user_name, email, password, redirectTo } = parsed.data;
-
-    // sanitize redirect
-    const safeRedirect =
-        redirectTo?.startsWith('/') ? redirectTo : '/dashboard';
-
-    const existing =
-        await sql`SELECT user_id FROM "user" WHERE email=${email}`;
-
-    if (existing.length > 0) {
-        return 'User already exists.';
-    }
-
-    const hashed = await bcrypt.hash(password, 10);
-
-    try {
-        await sql`
-            INSERT INTO "user" (user_name, email, password)
-            VALUES (${user_name}, ${email}, ${hashed})
-        `;
-    } catch {
-        return 'Failed to create user.';
-    }
-
-    try {
-        await signIn('credentials', {
-            email,
-            password,
-            redirectTo: safeRedirect,
-        });
-    } catch (error) {
-        if (error instanceof AuthError) {
-            return 'Account created, but auto-login failed. Please log in.';
-        }
-        throw error;
-    }
-}
Index: p/(auth)/layout.tsx
===================================================================
--- app/(auth)/layout.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,17 +1,0 @@
-export default function AuthLayout({
-    children,
-}: {
-    children: React.ReactNode;
-}) {
-    return (
-        <div
-            className="
-        flex-1
-        flex
-        flex-col
-      "
-        >
-            {children}
-        </div>
-    );
-}
Index: p/(auth)/login/page.tsx
===================================================================
--- app/(auth)/login/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,46 +1,0 @@
-import LoginForm from '@/app/ui/login-form';
-import { Suspense } from 'react';
-import { Metadata } from 'next';
-import { poppins } from '@/app/ui/fonts';
-
-export const metadata: Metadata = {
-    title: 'Login',
-};
-
-export default function LoginPage() {
-    return (
-        <>
-            <main
-                className="
-                    flex-1
-                    flex
-                    flex-col
-                    items-center
-                    justify-center 
-                    md:justify-center
-                    px-4
-                    mt-[-80]
-                "
-            >
-                <h1
-                    className={`${poppins.className} 
-                        text-[40px] 
-                        leading-tight
-                        tracking-tight
-                        font-semibold 
-                        text-center 
-                        text-white 
-                        antialiased
-                    `}
-                >
-                    Welcome to<br />
-                    FEiN
-                </h1>
-
-                <Suspense>
-                    <LoginForm />
-                </Suspense>
-            </main>
-        </>
-    );
-}
Index: p/(auth)/register/page.tsx
===================================================================
--- app/(auth)/register/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,43 +1,0 @@
-import RegisterForm from '@/app/ui/register-form';
-import { Suspense } from 'react';
-import { Metadata } from 'next';
-import { poppins } from '@/app/ui/fonts';
-
-export const metadata: Metadata = {
-    title: 'Register',
-};
-
-export default function RegisterPage() {
-    return (
-        <main
-            className="
-                flex-1
-                flex
-                flex-col
-                items-center
-                justify-center
-                px-4
-                mt-[-80px]
-            "
-        >
-            <h1
-                className={`${poppins.className}
-                    text-[40px]
-                    leading-tight
-                    tracking-tight
-                    font-semibold
-                    text-center
-                    text-white
-                    antialiased
-                `}
-            >
-                Create an<br />
-                account
-            </h1>
-
-            <Suspense>
-                <RegisterForm />
-            </Suspense>
-        </main>
-    );
-}
Index: p/layout.tsx
===================================================================
--- app/layout.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,50 +1,0 @@
-import '@/app/ui/global.css';
-import { poppins } from '@/app/ui/fonts';
-import { Metadata } from 'next';
-import GlobalNavigationIndicator from '@/app/ui/global-navigation-indicator';
-
-export const metadata: Metadata = {
-  title: {
-    template: '%s | FEiN',
-    default: 'FEiN',
-  },
-  description: 'Mobile-first web-application for personal finance tracking',
-};
-
-export default function RootLayout({
-  children,
-}: {
-  children: React.ReactNode;
-}) {
-  return (
-    <html lang="en">
-      {/* lock page scroll; the app will scroll inside the phone shell */}
-      <body className={`${poppins.className} antialiased bg-black overflow-hidden`}>
-        {/* Outer background wrapper */}
-        <div className="min-h-screen w-full xs:bg-fein  md:bg-black flex items-center justify-center">
-          {/* Phone shell */}
-          <div
-            className="
-              relative
-              w-full
-              h-screen
-              md:h-[800px]
-              md:max-h-[90vh]
-              md:w-[390px]
-              shadow-xl
-              md:rounded-2xl
-              overflow-hidden
-              flex 
-              flex-col
-              bg-fein
-            "
-          >
-            {children}
-          </div>
-        </div>
-
-        <GlobalNavigationIndicator />
-      </body>
-    </html>
-  );
-}
Index: p/lib/db.ts
===================================================================
--- app/lib/db.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,16 +1,0 @@
-import postgres from 'postgres';
-
-declare global {
-    // eslint-disable-next-line no-var
-    var __fein_sql: ReturnType<typeof postgres> | undefined;
-}
-
-export const sql =
-    global.__fein_sql ??
-    postgres(process.env.POSTGRES_URL!, {
-        ssl: 'require',
-    });
-
-if (process.env.NODE_ENV !== 'production') {
-    global.__fein_sql = sql;
-}
Index: p/lib/definitions.ts
===================================================================
--- app/lib/definitions.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,61 +1,0 @@
-// This file contains type definitions for the data.
-// It describes the shape of the data, and what data type each property should accept.
-
-export type User = {
-  user_id: number;
-  user_name: string;
-  email: string;
-  password: string; // hashed
-};
-
-export type TransactionAccount = {
-  transaction_account_id: number;
-  account_name: string | null;
-  balance: string; // DECIMAL comes back as string with `postgres` driver
-  user_id: number | null;
-};
-
-export type Transaction = {
-  transaction_id: number;
-  transaction_name: string | null;
-  amount: string; // DECIMAL -> string
-  net_amount: string | null; // DECIMAL -> string
-  date: string; // TIMESTAMPTZ -> ISO string
-};
-
-export type Tag = {
-  tag_id: number;
-  tag_name: string;
-};
-
-export type TagAssignedToTransaction = {
-  tag_assigned_to_transaction_id: number;
-  transaction_id: number;
-  tag_id: number;
-};
-
-export type TransactionBreakdown = {
-  transaction_breakdown_id: number;
-  transaction_id: number | null;
-  transaction_account_id: number | null;
-  spent_amount: string | null; // DECIMAL -> string
-  earned_amount: string | null; // DECIMAL -> string
-};
-
-/**
- * Useful “joined/view” shapes (not tables).
- * These make UI and API code nicer.
- */
-
-export type TransactionWithTags = Transaction & {
-  tags: Tag[];
-};
-
-export type TransactionAccountWithBreakdowns = TransactionAccount & {
-  breakdowns: TransactionBreakdown[];
-};
-
-export type TransactionBreakdownResolved = TransactionBreakdown & {
-  transaction?: Transaction;
-  transaction_account?: TransactionAccount;
-};
Index: p/lib/queries.ts
===================================================================
--- app/lib/queries.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,586 +1,0 @@
-import { sql } from './db';
-
-export type DashboardAccount = {
-    transaction_account_id: number;
-    account_name: string | null;
-    balance: string; // DECIMAL comes as string
-};
-
-export type DashboardTransaction = {
-    transaction_id: number;
-    transaction_name: string | null;
-    date: string; // timestamptz as ISO-ish string
-    net_amount: string; // signed: earned - spent
-    primary_tag: string | null;
-};
-
-export type DashboardData = {
-    totalBalance: string; // DECIMAL -> string
-    accounts: DashboardAccount[];
-
-    // Quick analytics cards
-    dailyBudgetUntilEndOfMonth: string; // DECIMAL -> string
-    threeDaySpendingAvg: string; // DECIMAL -> string (spend only, positive)
-    dailySpendingAvgMonthToDate: string; // DECIMAL -> string (spend only, positive)
-
-    recentTransactions: DashboardTransaction[];
-};
-
-export type TransactionAccountLite = {
-    transaction_account_id: number;
-    account_name: string | null;
-};
-
-export type AnalyticsPeriod = 'month' | 'year' | 'range';
-
-export type AnalyticsTagTotal = {
-    tag_name: string;
-    spent: string;
-};
-
-export type AnalyticsTrendPoint = {
-    bucket_key: string;
-    label: string;
-    spent: string;
-};
-
-export type AnalyticsData = {
-    accounts: TransactionAccountLite[];
-    tags: string[];
-    totalSpent: string;
-    tagTotals: AnalyticsTagTotal[];
-    focusTagTotals: AnalyticsTagTotal[];
-    trend: AnalyticsTrendPoint[];
-};
-
-export type HistoryTransaction = {
-    transaction_id: number;
-    transaction_name: string | null;
-    date: string; // ISO from PG
-    net_amount: string; // numeric comes as string via postgres.js
-    tags: string[]; // aggregated
-};
-
-function startOfMonth(d: Date) {
-    return new Date(d.getFullYear(), d.getMonth(), 1);
-}
-function endOfMonth(d: Date) {
-    return new Date(d.getFullYear(), d.getMonth() + 1, 0, 23, 59, 59, 999);
-}
-
-function startOfYear(d: Date) {
-    return new Date(d.getFullYear(), 0, 1);
-}
-
-function endOfYear(d: Date) {
-    return new Date(d.getFullYear(), 11, 31, 23, 59, 59, 999);
-}
-
-function parseDateInput(dateStr: string | undefined, fallback: Date) {
-    if (!dateStr) return fallback;
-    const parsed = new Date(`${dateStr}T00:00:00`);
-    return Number.isNaN(parsed.getTime()) ? fallback : parsed;
-}
-
-function bucketKeyForDate(date: Date, granularity: 'day' | 'month') {
-    const year = date.getFullYear();
-    const month = String(date.getMonth() + 1).padStart(2, '0');
-    if (granularity === 'month') {
-        return `${year}-${month}`;
-    }
-    const day = String(date.getDate()).padStart(2, '0');
-    return `${year}-${month}-${day}`;
-}
-
-function trendLabelForDate(date: Date, granularity: 'day' | 'month') {
-    if (granularity === 'month') {
-        return new Intl.DateTimeFormat('en-US', { month: 'short' }).format(date);
-    }
-
-    return String(date.getDate());
-}
-
-function buildTrendSeries(params: {
-    start: Date;
-    end: Date;
-    granularity: 'day' | 'month';
-    rows: { bucket_key: string; spent: string }[];
-}) {
-    const { start, end, granularity, rows } = params;
-    const lookup = new Map(rows.map((row) => [row.bucket_key, row.spent]));
-    const points: AnalyticsTrendPoint[] = [];
-
-    const cursor = new Date(start);
-    while (cursor <= end) {
-        const key = bucketKeyForDate(cursor, granularity);
-        points.push({
-            bucket_key: key,
-            label: trendLabelForDate(cursor, granularity),
-            spent: lookup.get(key) ?? '0.00',
-        });
-
-        if (granularity === 'month') {
-            cursor.setMonth(cursor.getMonth() + 1, 1);
-        } else {
-            cursor.setDate(cursor.getDate() + 1);
-        }
-    }
-
-    return points;
-}
-
-export async function getAnalyticsData(params: {
-    userId: number;
-    query?: string;
-    accountId?: number;
-    period?: AnalyticsPeriod;
-    startDate?: string;
-    endDate?: string;
-    focusTags?: string[];
-}): Promise<AnalyticsData> {
-    const now = new Date();
-    const period = params.period ?? 'month';
-    const defaultMonthStart = startOfMonth(now);
-    const defaultMonthEnd = endOfMonth(now);
-    const defaultYearStart = startOfYear(now);
-    const defaultYearEnd = endOfYear(now);
-
-    const start =
-        period === 'year'
-            ? defaultYearStart
-            : period === 'range'
-                ? parseDateInput(params.startDate, defaultMonthStart)
-                : defaultMonthStart;
-    const end =
-        period === 'year'
-            ? defaultYearEnd
-            : period === 'range'
-                ? parseDateInput(params.endDate, defaultMonthEnd)
-                : defaultMonthEnd;
-
-    const startBoundary = new Date(start);
-    startBoundary.setHours(0, 0, 0, 0);
-    const endBoundary = new Date(end);
-    endBoundary.setHours(23, 59, 59, 999);
-
-    const granularity: 'day' | 'month' = period === 'year' ? 'month' : 'day';
-    const searchPattern = params.query ? `%${params.query}%` : null;
-    const accountId = params.accountId ?? null;
-    const focusTags = params.focusTags && params.focusTags.length > 0 ? params.focusTags : null;
-    const focusTagCount = focusTags ? focusTags.length : 0;
-    const dateFormat = granularity === 'month' ? 'YYYY-MM' : 'YYYY-MM-DD';
-
-    const [accounts, tags, totalSpentRow, tagTotals, focusTagTotals, trendRows] = await Promise.all([
-        getUserTransactionAccounts(params.userId),
-        getUserTagsForHistory(params.userId),
-        sql<{ spent: string | null }[]>`
-            SELECT COALESCE(SUM(tb.spent_amount), 0)::numeric(12,2) AS spent
-            FROM transaction_breakdown tb
-            JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-            JOIN transaction t ON t.transaction_id = tb.transaction_id
-            WHERE ta.user_id = ${params.userId}
-                AND (${accountId}::int IS NULL OR tb.transaction_account_id = ${accountId})
-                AND t.date >= ${startBoundary.toISOString()}
-                AND t.date <= ${endBoundary.toISOString()}
-                AND (
-                    ${searchPattern}::text IS NULL
-                    OR t.transaction_name ILIKE ${searchPattern}
-                    OR ta.account_name ILIKE ${searchPattern}
-                    OR EXISTS (
-                        SELECT 1
-                        FROM tag_assigned_to_transaction tat2
-                        JOIN tag tg2 ON tg2.tag_id = tat2.tag_id
-                        WHERE tat2.transaction_id = t.transaction_id
-                            AND tg2.tag_name ILIKE ${searchPattern}
-                    )
-                )
-        `,
-        sql<AnalyticsTagTotal[]>`
-            SELECT
-                tg.tag_name,
-                COALESCE(SUM(COALESCE(tb.spent_amount, 0)), 0)::numeric(12,2)::text AS spent
-            FROM transaction t
-            JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-            JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-            JOIN tag_assigned_to_transaction tat ON tat.transaction_id = t.transaction_id
-            JOIN tag tg ON tg.tag_id = tat.tag_id
-            WHERE ta.user_id = ${params.userId}
-                AND (${accountId}::int IS NULL OR tb.transaction_account_id = ${accountId})
-                AND t.date >= ${startBoundary.toISOString()}
-                AND t.date <= ${endBoundary.toISOString()}
-                AND tg.tag_name NOT LIKE '__note:%'
-                AND (
-                    ${searchPattern}::text IS NULL
-                    OR t.transaction_name ILIKE ${searchPattern}
-                    OR ta.account_name ILIKE ${searchPattern}
-                    OR tg.tag_name ILIKE ${searchPattern}
-                    OR EXISTS (
-                        SELECT 1
-                        FROM tag_assigned_to_transaction tat2
-                        JOIN tag tg2 ON tg2.tag_id = tat2.tag_id
-                        WHERE tat2.transaction_id = t.transaction_id
-                            AND tg2.tag_name ILIKE ${searchPattern}
-                    )
-                )
-            GROUP BY tg.tag_name
-            ORDER BY COALESCE(SUM(COALESCE(tb.spent_amount, 0)), 0) DESC, tg.tag_name ASC
-            LIMIT 12
-        `,
-        focusTagCount > 0
-            ? sql<AnalyticsTagTotal[]>`
-                SELECT
-                    tg.tag_name,
-                    COALESCE(SUM(COALESCE(tb.spent_amount, 0)), 0)::numeric(12,2)::text AS spent
-                FROM transaction t
-                JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-                JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-                JOIN tag_assigned_to_transaction tat ON tat.transaction_id = t.transaction_id
-                JOIN tag tg ON tg.tag_id = tat.tag_id
-                WHERE ta.user_id = ${params.userId}
-                    AND (${accountId}::int IS NULL OR tb.transaction_account_id = ${accountId})
-                    AND t.date >= ${startBoundary.toISOString()}
-                    AND t.date <= ${endBoundary.toISOString()}
-                    AND tg.tag_name NOT LIKE '__note:%'
-                    AND tg.tag_name = ANY(${focusTags ?? []}::text[])
-                    AND (
-                        ${searchPattern}::text IS NULL
-                        OR t.transaction_name ILIKE ${searchPattern}
-                        OR ta.account_name ILIKE ${searchPattern}
-                        OR tg.tag_name ILIKE ${searchPattern}
-                        OR EXISTS (
-                            SELECT 1
-                            FROM tag_assigned_to_transaction tat2
-                            JOIN tag tg2 ON tg2.tag_id = tat2.tag_id
-                            WHERE tat2.transaction_id = t.transaction_id
-                                AND tg2.tag_name ILIKE ${searchPattern}
-                        )
-                    )
-                GROUP BY tg.tag_name
-                ORDER BY COALESCE(SUM(COALESCE(tb.spent_amount, 0)), 0) DESC, tg.tag_name ASC
-            `
-            : Promise.resolve([] as AnalyticsTagTotal[]),
-        sql<{ bucket_key: string; spent: string }[]>`
-            SELECT
-                TO_CHAR(DATE_TRUNC(${granularity}, t.date), ${dateFormat}) AS bucket_key,
-                COALESCE(SUM(COALESCE(tb.spent_amount, 0)), 0)::numeric(12,2)::text AS spent
-            FROM transaction t
-            JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-            JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-            WHERE ta.user_id = ${params.userId}
-                AND (${accountId}::int IS NULL OR tb.transaction_account_id = ${accountId})
-                AND t.date >= ${startBoundary.toISOString()}
-                AND t.date <= ${endBoundary.toISOString()}
-                AND (
-                    ${searchPattern}::text IS NULL
-                    OR t.transaction_name ILIKE ${searchPattern}
-                    OR ta.account_name ILIKE ${searchPattern}
-                    OR EXISTS (
-                        SELECT 1
-                        FROM tag_assigned_to_transaction tat2
-                        JOIN tag tg2 ON tg2.tag_id = tat2.tag_id
-                        WHERE tat2.transaction_id = t.transaction_id
-                            AND tg2.tag_name ILIKE ${searchPattern}
-                    )
-                )
-            GROUP BY 1
-            ORDER BY 1 ASC
-        `,
-    ]);
-
-    const trend = buildTrendSeries({
-        start: startBoundary,
-        end: endBoundary,
-        granularity,
-        rows: trendRows,
-    });
-
-    return {
-        accounts,
-        tags,
-        totalSpent: totalSpentRow[0]?.spent ?? '0.00',
-        tagTotals,
-        focusTagTotals,
-        trend,
-    };
-}
-
-export async function getDashboardData(userId: number): Promise<DashboardData> {
-    const now = new Date();
-    const som = startOfMonth(now);
-    const eom = endOfMonth(now);
-
-    // Days remaining including today (budget "until end of month")
-    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
-    const lastDayStart = new Date(eom.getFullYear(), eom.getMonth(), eom.getDate());
-    const daysLeft =
-        Math.max(
-            1,
-            Math.round((lastDayStart.getTime() - todayStart.getTime()) / (1000 * 60 * 60 * 24)) + 1,
-        );
-
-    // Days passed including today (month-to-date average)
-    const daysPassed = Math.max(1, now.getDate());
-
-    // Accounts + total balance
-    const accounts = await sql<DashboardAccount[]>`
-        SELECT
-        transaction_account_id,
-        account_name,
-        balance
-        FROM transaction_account
-        WHERE user_id = ${userId}
-        ORDER BY transaction_account_id ASC
-    `;
-
-    const totalBalanceRow = await sql<{ total: string | null }[]>`
-        SELECT COALESCE(SUM(balance), 0)::numeric(12,2) AS total
-        FROM transaction_account
-        WHERE user_id = ${userId}
-    `;
-    const totalBalance = totalBalanceRow[0]?.total ?? '0.00';
-
-    // Month spend total (spent_amount only) scoped to user via accounts
-    const monthSpendRow = await sql<{ spent: string | null }[]>`
-        SELECT COALESCE(SUM(tb.spent_amount), 0)::numeric(12,2) AS spent
-        FROM transaction_breakdown tb
-        JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-        JOIN transaction t ON t.transaction_id = tb.transaction_id
-        WHERE ta.user_id = ${userId}
-        AND t.date >= ${som.toISOString()}
-        AND t.date <= ${eom.toISOString()}
-    `;
-    const monthSpent = monthSpendRow[0]?.spent ?? '0.00';
-
-    // Last 3 calendar days spend (including today)
-    const threeDaysAgoStart = new Date(todayStart);
-    threeDaysAgoStart.setDate(threeDaysAgoStart.getDate() - 2); // today + previous 2 days
-    const threeDaySpendRow = await sql<{ spent: string | null }[]>`
-    SELECT COALESCE(SUM(tb.spent_amount), 0)::numeric(12,2) AS spent
-    FROM transaction_breakdown tb
-    JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-    JOIN transaction t ON t.transaction_id = tb.transaction_id
-    WHERE ta.user_id = ${userId}
-      AND t.date >= ${threeDaysAgoStart.toISOString()}
-      AND t.date <= ${now.toISOString()}
-  `;
-    const threeDaySpent = threeDaySpendRow[0]?.spent ?? '0.00';
-
-    // Compute quick cards in JS (still DECIMAL-safe enough for display)
-    const totalBalanceNum = Number(totalBalance);
-    const monthSpentNum = Number(monthSpent);
-    const threeDaySpentNum = Number(threeDaySpent);
-
-    const dailyBudgetUntilEndOfMonth = (totalBalanceNum / daysLeft).toFixed(2);
-    const threeDaySpendingAvg = (threeDaySpentNum / 3).toFixed(2);
-    const dailySpendingAvgMonthToDate = (monthSpentNum / daysPassed).toFixed(2);
-
-    // Recent transactions (scoped via breakdown -> account user)
-    // net_amount = SUM(earned) - SUM(spent) for that user’s breakdown rows
-    // primary_tag = first tag_name (alphabetical) if exists
-    const recentTransactions = await sql<DashboardTransaction[]>`
-        WITH tx AS (
-        SELECT
-            t.transaction_id,
-            t.transaction_name,
-            t.date,
-            (COALESCE(SUM(tb.earned_amount), 0) - COALESCE(SUM(tb.spent_amount), 0))::numeric(12,2) AS net_amount
-        FROM transaction t
-        JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-        JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-        WHERE ta.user_id = ${userId}
-        GROUP BY t.transaction_id, t.transaction_name, t.date
-        ORDER BY t.date DESC
-        LIMIT 6
-        ),
-        tag_one AS (
-        SELECT
-            tat.transaction_id,
-            MIN(tag.tag_name) AS primary_tag
-        FROM tag_assigned_to_transaction tat
-        JOIN tag ON tag.tag_id = tat.tag_id
-        WHERE tag.tag_name NOT LIKE '__note:%'
-        GROUP BY tat.transaction_id
-        )
-        SELECT
-        tx.transaction_id,
-        tx.transaction_name,
-        tx.date,
-        tx.net_amount::text AS net_amount,
-        tag_one.primary_tag
-        FROM tx
-        LEFT JOIN tag_one ON tag_one.transaction_id = tx.transaction_id
-        ORDER BY tx.date DESC
-    `;
-
-    return {
-        totalBalance,
-        accounts,
-        dailyBudgetUntilEndOfMonth,
-        threeDaySpendingAvg,
-        dailySpendingAvgMonthToDate,
-        recentTransactions,
-    };
-}
-
-export async function getUserTransactionAccounts(userId: number) {
-    const rows = await sql<TransactionAccountLite[]>`
-        SELECT
-            ta.transaction_account_id,
-            ta.account_name
-        FROM transaction_account ta
-        WHERE ta.user_id = ${userId}
-        ORDER BY ta.transaction_account_id ASC
-    `;
-    return rows;
-}
-
-export async function getUserTagsForHistory(userId: number) {
-    // Only tags that appear in user's transactions (through breakdown -> account -> user)
-    const rows = await sql<{ tag_name: string }[]>`
-        SELECT DISTINCT tg.tag_name
-        FROM tag tg
-        JOIN tag_assigned_to_transaction tat ON tat.tag_id = tg.tag_id
-        JOIN transaction t ON t.transaction_id = tat.transaction_id
-        JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-        JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-        WHERE ta.user_id = ${userId}
-          AND tg.tag_name NOT LIKE '__note:%'
-        ORDER BY tg.tag_name ASC
-    `;
-    return rows.map((r) => r.tag_name);
-}
-
-export async function getAllTags() {
-    const rows = await sql<{ tag_id: number; tag_name: string }[]>`
-        SELECT tag_id, tag_name
-        FROM tag
-        WHERE tag_name NOT LIKE '__note:%'
-        ORDER BY tag_name ASC
-    `;
-    return rows;
-}
-
-export const HISTORY_ITEMS_PER_PAGE = 10;
-
-export async function getHistoryTransactions(params: {
-    userId: number;
-    accountId?: number;
-    query?: string; // searches transaction_name, tag_name, account_name
-    tags?: string[]; // intersection: transaction must have ALL of these tags
-    page?: number;
-}) {
-    const { userId, accountId, query, tags, page = 1 } = params;
-    const offset = (page - 1) * HISTORY_ITEMS_PER_PAGE;
-    const searchPattern = query ? `%${query}%` : null;
-    const tagFilter = tags && tags.length > 0 ? tags : null;
-    const tagCount = tagFilter ? tagFilter.length : 0;
-
-    const rows = await sql<HistoryTransaction[]>`
-        WITH filtered_tx AS (
-            SELECT
-                t.transaction_id,
-                t.transaction_name,
-                t.date,
-                (
-                    COALESCE(SUM(COALESCE(tb.earned_amount, 0)), 0)
-                    -
-                    COALESCE(SUM(COALESCE(tb.spent_amount, 0)), 0)
-                )::text AS net_amount
-            FROM transaction t
-            JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-            JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-            WHERE ta.user_id = ${userId}
-                AND (${accountId ?? null}::int IS NULL OR tb.transaction_account_id = ${accountId ?? null})
-                AND (
-                    ${searchPattern}::text IS NULL
-                    OR t.transaction_name ILIKE ${searchPattern}
-                    OR ta.account_name ILIKE ${searchPattern}
-                    OR EXISTS (
-                        SELECT 1
-                        FROM tag_assigned_to_transaction tat2
-                        JOIN tag tg2 ON tg2.tag_id = tat2.tag_id
-                        WHERE tat2.transaction_id = t.transaction_id
-                            AND tg2.tag_name ILIKE ${searchPattern}
-                    )
-                )
-                AND (
-                    ${tagCount}::int = 0
-                    OR (
-                        SELECT COUNT(DISTINCT tg_f.tag_name)
-                        FROM tag_assigned_to_transaction tat_f
-                        JOIN tag tg_f ON tg_f.tag_id = tat_f.tag_id
-                        WHERE tat_f.transaction_id = t.transaction_id
-                            AND tg_f.tag_name = ANY(${tagFilter ?? []}::text[])
-                    ) = ${tagCount}
-                )
-            GROUP BY t.transaction_id
-            ORDER BY t.date DESC
-            LIMIT ${HISTORY_ITEMS_PER_PAGE}
-            OFFSET ${offset}
-        )
-        SELECT
-            ft.transaction_id,
-            ft.transaction_name,
-            ft.date::text AS date,
-            ft.net_amount,
-            COALESCE(
-                ARRAY_REMOVE(ARRAY_AGG(DISTINCT tg.tag_name), NULL),
-                ARRAY[]::text[]
-            ) AS tags
-        FROM filtered_tx ft
-        LEFT JOIN tag_assigned_to_transaction tat ON tat.transaction_id = ft.transaction_id
-        LEFT JOIN tag tg ON tg.tag_id = tat.tag_id
-        GROUP BY ft.transaction_id, ft.transaction_name, ft.date, ft.net_amount
-        ORDER BY ft.date DESC
-    `;
-
-    return rows;
-}
-
-export async function getHistoryTransactionPages(params: {
-    userId: number;
-    accountId?: number;
-    query?: string;
-    tags?: string[];
-}) {
-    const { userId, accountId, query, tags } = params;
-    const searchPattern = query ? `%${query}%` : null;
-    const tagFilter = tags && tags.length > 0 ? tags : null;
-    const tagCount = tagFilter ? tagFilter.length : 0;
-
-    const countResult = await sql<{ count: string }[]>`
-        SELECT COUNT(DISTINCT t.transaction_id)::text AS count
-        FROM transaction t
-        JOIN transaction_breakdown tb ON tb.transaction_id = t.transaction_id
-        JOIN transaction_account ta ON ta.transaction_account_id = tb.transaction_account_id
-        LEFT JOIN tag_assigned_to_transaction tat ON tat.transaction_id = t.transaction_id
-        LEFT JOIN tag tg ON tg.tag_id = tat.tag_id
-        WHERE ta.user_id = ${userId}
-            AND (${accountId ?? null}::int IS NULL OR tb.transaction_account_id = ${accountId ?? null})
-            AND (
-                ${searchPattern}::text IS NULL
-                OR t.transaction_name ILIKE ${searchPattern}
-                OR ta.account_name ILIKE ${searchPattern}
-                OR EXISTS (
-                    SELECT 1
-                    FROM tag_assigned_to_transaction tat2
-                    JOIN tag tg2 ON tg2.tag_id = tat2.tag_id
-                    WHERE tat2.transaction_id = t.transaction_id
-                        AND tg2.tag_name ILIKE ${searchPattern}
-                )
-            )
-            AND (
-                ${tagCount}::int = 0
-                OR (
-                    SELECT COUNT(DISTINCT tg_f.tag_name)
-                    FROM tag_assigned_to_transaction tat_f
-                    JOIN tag tg_f ON tg_f.tag_id = tat_f.tag_id
-                    WHERE tat_f.transaction_id = t.transaction_id
-                        AND tg_f.tag_name = ANY(${tagFilter ?? []}::text[])
-                ) = ${tagCount}
-            )
-    `;
-
-    const totalCount = Number(countResult[0]?.count ?? '0');
-    return Math.ceil(totalCount / HISTORY_ITEMS_PER_PAGE);
-}
Index: p/lib/utils.ts
===================================================================
--- app/lib/utils.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,62 +1,0 @@
-export function formatMKD(value: string | number) {
-  let n = typeof value === 'number' ? value : Number(value);
-
-  // Normalize -0 to 0
-  if (Object.is(n, -0) || Math.abs(n) < 0.005) {
-    n = 0;
-  }
-
-  const formatted = new Intl.NumberFormat('en-US', {
-    maximumFractionDigits: 0,
-  }).format(Math.abs(n));
-
-  return n < 0 ? `MKD -${formatted}` : `MKD ${formatted}`;
-}
-
-export const formatDateToLocal = (
-  dateStr: string,
-  locale: string = 'en-US',
-) => {
-  const date = new Date(dateStr);
-  const options: Intl.DateTimeFormatOptions = {
-    day: 'numeric',
-    month: 'short',
-    year: 'numeric',
-  };
-  const formatter = new Intl.DateTimeFormat(locale, options);
-  return formatter.format(date);
-};
-
-
-export const generatePagination = (currentPage: number, totalPages: number) => {
-  // If the total number of pages is 7 or less,
-  // display all pages without any ellipsis.
-  if (totalPages <= 7) {
-    return Array.from({ length: totalPages }, (_, i) => i + 1);
-  }
-
-  // If the current page is among the first 3 pages,
-  // show the first 3, an ellipsis, and the last 2 pages.
-  if (currentPage <= 3) {
-    return [1, 2, 3, '...', totalPages - 1, totalPages];
-  }
-
-  // If the current page is among the last 3 pages,
-  // show the first 2, an ellipsis, and the last 3 pages.
-  if (currentPage >= totalPages - 2) {
-    return [1, 2, '...', totalPages - 2, totalPages - 1, totalPages];
-  }
-
-  // If the current page is somewhere in the middle,
-  // show the first page, an ellipsis, the current page and its neighbors,
-  // another ellipsis, and the last page.
-  return [
-    1,
-    '...',
-    currentPage - 1,
-    currentPage,
-    currentPage + 1,
-    '...',
-    totalPages,
-  ];
-};
Index: p/page.tsx
===================================================================
--- app/page.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,51 +1,0 @@
-import Link from 'next/link';
-import { poppins } from '@/app/ui/fonts';
-
-export default function Page() {
-  return (
-    <>
-      <main
-        className="
-                    flex-1
-                    flex
-                    flex-col
-                    items-center
-                    justify-center 
-                    md:justify-center
-                    px-4
-                    mt-[-80]
-                "
-      >
-        <h1
-          className={`${poppins.className} 
-                        text-[40px] 
-                        leading-tight
-                        tracking-tight
-                        font-semibold 
-                        text-center
-                        mb-10 
-                        text-white 
-                        antialiased
-                    `}
-        >
-          Welcome to<br />
-          FEiN
-        </h1>
-
-        <Link
-          href="/login"
-          className="flex items-center gap-5 rounded-lg bg-blue-500 px-6 py-3 mb-10 text-sm font-medium text-white transition-colors hover:bg-blue-400 md:text-base"
-        >
-          <span>Log in</span>
-        </Link>
-        <Link
-          href="/register"
-          className="flex items-center gap-5 rounded-lg bg-blue-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-blue-400 md:text-base"
-        >
-          <span>Register</span>
-        </Link>
-
-      </main>
-    </>
-  );
-}
Index: p/ui/account-filter-icon.tsx
===================================================================
--- app/ui/account-filter-icon.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,125 +1,0 @@
-'use client';
-
-import { useState, useRef, useEffect } from 'react';
-import { useSearchParams, usePathname, useRouter } from 'next/navigation';
-import { WalletIcon, CheckIcon } from '@heroicons/react/24/outline';
-import type { TransactionAccountLite } from '@/app/lib/queries';
-
-const NAVIGATION_START_EVENT = 'fein:navigation-start';
-
-export default function AccountFilterIcon({
-    accounts,
-    accountParam = 'accountId',
-    resetPageOnChange = false,
-    onNavigateStart,
-}: {
-    accounts: TransactionAccountLite[];
-    accountParam?: string;
-    resetPageOnChange?: boolean;
-    onNavigateStart?: () => void;
-}) {
-    const searchParams = useSearchParams();
-    const pathname = usePathname();
-    const { replace } = useRouter();
-    const [open, setOpen] = useState(false);
-    const ref = useRef<HTMLDivElement>(null);
-
-    const currentId = searchParams.get(accountParam) ?? '';
-    const hasFilter = currentId !== '';
-
-    useEffect(() => {
-        function onClickOutside(e: MouseEvent) {
-            if (ref.current && !ref.current.contains(e.target as Node)) {
-                setOpen(false);
-            }
-        }
-        if (open) {
-            document.addEventListener('mousedown', onClickOutside);
-            return () => document.removeEventListener('mousedown', onClickOutside);
-        }
-    }, [open]);
-
-    function select(value: string) {
-        const params = new URLSearchParams(searchParams);
-
-        if (resetPageOnChange) {
-            params.set('page', '1');
-        }
-
-        if (value) {
-            params.set(accountParam, value);
-        } else {
-            params.delete(accountParam);
-        }
-
-        const nextQuery = params.toString();
-        window.dispatchEvent(new Event(NAVIGATION_START_EVENT));
-        onNavigateStart?.();
-        replace(nextQuery ? `${pathname}?${nextQuery}` : pathname, { scroll: false });
-        setOpen(false);
-    }
-
-    return (
-        <div ref={ref} className="relative">
-            <button
-                type="button"
-                onClick={() => setOpen((v) => !v)}
-                className={`
-                    flex items-center justify-center h-12 w-12 rounded-xl border transition
-                    ${hasFilter
-                        ? 'bg-blue-600 border-blue-500 text-white'
-                        : 'bg-white/15 border-white/15 text-white/60 hover:text-white hover:bg-white/20'
-                    }
-                `}
-                title="Filter by account"
-            >
-                <WalletIcon className="h-5 w-5" />
-            </button>
-
-            {open && (
-                <div className="absolute right-0 top-14 z-50 w-56 rounded-xl bg-gray-900/95 border border-white/15 backdrop-blur-lg shadow-2xl py-1 overflow-hidden">
-                    <DropdownItem
-                        label="All Accounts"
-                        isSelected={currentId === ''}
-                        onClick={() => select('')}
-                    />
-                    {accounts.map((acc) => {
-                        const id = String(acc.transaction_account_id);
-                        return (
-                            <DropdownItem
-                                key={id}
-                                label={acc.account_name ?? `Account #${acc.transaction_account_id}`}
-                                isSelected={currentId === id}
-                                onClick={() => select(id)}
-                            />
-                        );
-                    })}
-                </div>
-            )}
-        </div>
-    );
-}
-
-function DropdownItem({
-    label,
-    isSelected,
-    onClick,
-}: {
-    label: string;
-    isSelected: boolean;
-    onClick: () => void;
-}) {
-    return (
-        <button
-            type="button"
-            onClick={onClick}
-            className={`
-                w-full flex items-center gap-2 px-4 py-2.5 text-sm text-left transition
-                ${isSelected ? 'text-white bg-white/10' : 'text-white/70 hover:bg-white/5 hover:text-white'}
-            `}
-        >
-            {isSelected && <CheckIcon className="h-4 w-4 shrink-0 text-blue-400" />}
-            <span className={isSelected ? '' : 'pl-6'}>{label}</span>
-        </button>
-    );
-}
Index: p/ui/bottom-nav.tsx
===================================================================
--- app/ui/bottom-nav.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,109 +1,0 @@
-'use client';
-
-import Link from 'next/link';
-import { usePathname } from 'next/navigation';
-import {
-    HomeIcon,
-    ClockIcon,
-    ChartBarIcon,
-    UserIcon,
-    PlusIcon,
-} from '@heroicons/react/24/outline';
-
-const TABS = [
-    { href: '/dashboard', icon: HomeIcon },
-    { href: '/history', icon: ClockIcon },
-    { href: '/analytics', icon: ChartBarIcon },
-    { href: '/profile', icon: UserIcon },
-];
-
-export default function BottomNav() {
-    const pathname = usePathname();
-
-    const isAddPage = pathname.startsWith('/add');
-
-    return (
-        <div className="relative">
-            {/* Floating bar */}
-            <nav
-                className="
-                    pointer-events-auto
-                    pb-safe
-                    mx-4
-                    mb-0
-                    h-14
-                    rounded-2xl
-                    bg-black/40
-                    backdrop-blur-md
-                    shadow-lg
-                    border
-                    border-white/10
-                    flex
-                    items-center
-                    justify-center
-                    px-6
-                    gap-11
-                "
-            >
-                {/* Left tabs */}
-                <div className="flex gap-11">
-                    {TABS.slice(0, 2).map(({ href, icon: Icon }) => {
-                        const active = pathname.startsWith(href);
-                        return (
-                            <Link key={href} href={href}>
-                                <Icon
-                                    className={`h-6 w-6 ${active ? 'text-blue-500' : 'text-white/60'
-                                        }`}
-                                />
-                            </Link>
-                        );
-                    })}
-                </div>
-
-                {/* Spacer for center button */}
-                <div className="w-12" />
-
-                {/* Right tabs */}
-                <div className="flex gap-11">
-                    {TABS.slice(2).map(({ href, icon: Icon }) => {
-                        const active = pathname.startsWith(href);
-                        return (
-                            <Link key={href} href={href}>
-                                <Icon
-                                    className={`h-6 w-6 ${active ? 'text-blue-500' : 'text-white/60'
-                                        }`}
-                                />
-                            </Link>
-                        );
-                    })}
-                </div>
-            </nav>
-
-            {/* Center plus button */}
-            <Link
-                href="/add"
-                className="
-                    absolute
-                    left-1/2
-                    -top-6
-                    -translate-x-1/2
-                    h-14
-                    w-14
-                    rounded-full
-                    flex
-                    items-center
-                    justify-center
-                    shadow-xl
-                    border
-                    border-white/20
-                    backdrop-blur-md
-                "
-                style={{
-                    backgroundColor: isAddPage ? '#9CA3AF' : '#3B82F6',
-                }}
-            >
-                <PlusIcon className="h-7 w-7 text-white" />
-            </Link>
-        </div>
-    );
-}
Index: p/ui/button.tsx
===================================================================
--- app/ui/button.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,19 +1,0 @@
-import clsx from 'clsx';
-
-interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
-  children: React.ReactNode;
-}
-
-export function Button({ children, className, ...rest }: ButtonProps) {
-  return (
-    <button
-      {...rest}
-      className={clsx(
-        'flex h-10 items-center rounded-lg bg-blue-500 px-4 text-sm font-medium text-white transition-colors hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:bg-blue-600 aria-disabled:cursor-not-allowed aria-disabled:opacity-50',
-        className,
-      )}
-    >
-      {children}
-    </button>
-  );
-}
Index: p/ui/fonts.ts
===================================================================
--- app/ui/fonts.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,3 +1,0 @@
-import { Poppins } from 'next/font/google';
-
-export const poppins = Poppins({ weight: ['500'], subsets: ['latin'] });
Index: p/ui/global-navigation-indicator.tsx
===================================================================
--- app/ui/global-navigation-indicator.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,59 +1,0 @@
-'use client';
-
-import { useEffect, useState } from 'react';
-
-const NAVIGATION_START_EVENT = 'fein:navigation-start';
-
-export default function GlobalNavigationIndicator() {
-    const [visible, setVisible] = useState(false);
-
-    useEffect(() => {
-        function onNavigationStart() {
-            setVisible(true);
-        }
-
-        function onDocumentClick(event: MouseEvent) {
-            if (event.defaultPrevented) return;
-            const target = event.target as Element | null;
-            if (!target) return;
-
-            const anchor = target.closest('a[href]') as HTMLAnchorElement | null;
-            if (!anchor) return;
-            if (anchor.target && anchor.target !== '_self') return;
-            if (anchor.hasAttribute('download')) return;
-            if (anchor.getAttribute('href')?.startsWith('#')) return;
-
-            setVisible(true);
-        }
-
-        function onFormSubmit() {
-            setVisible(true);
-        }
-
-        window.addEventListener(NAVIGATION_START_EVENT, onNavigationStart);
-        document.addEventListener('click', onDocumentClick, true);
-        document.addEventListener('submit', onFormSubmit, true);
-
-        return () => {
-            window.removeEventListener(NAVIGATION_START_EVENT, onNavigationStart);
-            document.removeEventListener('click', onDocumentClick, true);
-            document.removeEventListener('submit', onFormSubmit, true);
-        };
-    }, []);
-
-    useEffect(() => {
-        if (!visible) return;
-        const timeoutId = window.setTimeout(() => setVisible(false), 1400);
-        return () => clearTimeout(timeoutId);
-    }, [visible]);
-
-    if (!visible) {
-        return null;
-    }
-
-    return (
-        <div className="pointer-events-none fixed inset-0 z-[95] flex items-center justify-center backdrop-blur-[2px] bg-white/5">
-            <div className="h-10 w-10 animate-spin rounded-full border-2 border-white/30 border-t-white/90 shadow-[0_0_24px_rgba(255,255,255,0.25)]" />
-        </div>
-    );
-}
Index: p/ui/global.css
===================================================================
--- app/ui/global.css	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,57 +1,0 @@
-@import "tailwindcss";
-
-input[type='number'] {
-  -moz-appearance: textfield;
-  appearance: textfield;
-}
-
-input[type='number']::-webkit-inner-spin-button {
-  -webkit-appearance: none;
-  margin: 0;
-}
-
-input[type='number']::-webkit-outer-spin-button {
-  -webkit-appearance: none;
-  margin: 0;
-}
-
-html,
-body {
-  height: 100%;
-  overflow: hidden;
-  overscroll-behavior: none;
-}
-
-::-webkit-scrollbar {
-  background-color: transparent;
-  width: 12px;
-}
-
-::-webkit-scrollbar-track {
-  background-color: transparent;
-}
-
-::-webkit-scrollbar-thumb {
-  border-radius: 20px;
-  border: 3px solid transparent;
-  background-color: rgba(0, 0, 0, 0);
-  background-clip: content-box;
-}
-
-/* For firefox/edge/IE: Hide scrollbars (but keep scrolling) */
-.no-scrollbar {
-  -ms-overflow-style: none;
-  /* IE/Edge */
-  scrollbar-width: none;
-  /* Firefox */
-}
-
-@layer utilities {
-  .bg-fein {
-    background: linear-gradient(180deg, #249e86 0%, #1d7f6a 100%);
-  }
-}
-
-.pb-safe {
-  padding-bottom: env(safe-area-inset-bottom);
-}
Index: p/ui/login-form.tsx
===================================================================
--- app/ui/login-form.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,136 +1,0 @@
-'use client';
-
-import { poppins } from '@/app/ui/fonts';
-import {
-  AtSymbolIcon,
-  KeyIcon,
-  ExclamationCircleIcon,
-} from '@heroicons/react/24/outline';
-import { Button } from './button';
-import { useActionState } from 'react';
-import { authenticate } from '@/app/(auth)/actions';
-import { useSearchParams } from 'next/navigation';
-import Link from 'next/link';
-
-export default function LoginForm() {
-  const searchParams = useSearchParams();
-  const callbackUrl = searchParams.get('callbackUrl') || '/dashboard';
-  const [errorMessage, formAction, isPending] = useActionState(
-    authenticate,
-    undefined,
-  );
-
-  return (
-    <form
-      action={formAction}
-      className="
-        w-full
-        max-w-sm
-        bg-transparent
-        backdrop-blur-md
-        rounded-2xl
-        px-6
-        py-8
-      "
-    >
-      <div className="space-y-4">
-        {/* Email */}
-        <div className="relative">
-          <input
-            className={`${poppins.className}
-              peer
-              w-full
-              h-12
-              rounded-lg
-              bg-white/30
-              pl-11
-              text-white
-              placeholder:text-white/60
-              focus:outline-none
-              focus:ring-2
-              focus:ring-white/50
-            `}
-            id="email"
-            type="email"
-            name="email"
-            placeholder="Email"
-            required
-          />
-          <AtSymbolIcon className="pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-white/70" />
-        </div>
-
-        {/* Password */}
-        <div className="relative">
-          <input
-            className={`${poppins.className}
-              peer
-              w-full
-              h-12
-              rounded-lg
-              bg-white/30
-              pl-11
-              text-white
-              placeholder:text-white/60
-              focus:outline-none
-              focus:ring-2
-              focus:ring-white/50
-            `}
-            id="password"
-            type="password"
-            name="password"
-            placeholder="Password"
-            required
-            minLength={6}
-          />
-          <KeyIcon className="pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-white/70" />
-        </div>
-      </div>
-
-
-      <input type="hidden" name="redirectTo" value={callbackUrl} />
-
-
-      <Button
-        className={`${poppins.className}
-          mt-6
-          w-full
-          h-12
-          rounded-lg
-          bg-[#1d7f6a]
-          hover:bg-[#166655]
-          text-white
-          text-lg
-          font-medium
-          flex 
-          items-center 
-          justify-center
-        `}
-        aria-disabled={isPending}
-      >
-        Log in
-      </Button>
-
-
-      <p
-        className={`${poppins.className} mt-4 text-sm text-center text-white/80 antialiased`}
-      >
-        Don&apos;t have an account?
-        <Link className={`${poppins.className} ml-1 font-medium underline antialiased`} href="/register">
-          Register
-        </Link>
-      </p>
-
-
-      {errorMessage && (
-        <div
-          className="flex h-8 items-end space-x-1"
-          aria-live="polite"
-          aria-atomic="true"
-        >
-          <ExclamationCircleIcon className="h-5 w-5 text-red-500" />
-          <span className="text-sm text-red-500">{errorMessage}</span>
-        </div>
-      )}
-    </form >
-  );
-}
Index: p/ui/register-form.tsx
===================================================================
--- app/ui/register-form.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,161 +1,0 @@
-'use client';
-
-import { poppins } from '@/app/ui/fonts';
-import {
-  AtSymbolIcon,
-  KeyIcon,
-  UserIcon,
-  ExclamationCircleIcon,
-} from '@heroicons/react/24/outline';
-import { Button } from './button';
-import { useActionState } from 'react';
-import { register } from '@/app/(auth)/actions';
-import { useSearchParams } from 'next/navigation';
-import Link from 'next/link';
-
-export default function RegisterForm() {
-  const searchParams = useSearchParams();
-  const callbackUrl = searchParams.get('callbackUrl') || '/dashboard';
-  const [errorMessage, formAction, isPending] = useActionState(
-    register,
-    undefined,
-  );
-
-  return (
-    <form
-      action={formAction}
-      className="
-        w-full
-        max-w-sm
-        bg-transparent
-        backdrop-blur-md
-        rounded-2xl
-        px-6
-        py-8
-      "
-    >
-      <div className="space-y-4">
-        {/* Name */}
-        <div className="relative">
-          <input
-            className={`${poppins.className}
-              peer
-              w-full
-              h-12
-              rounded-lg
-              bg-white/30
-              pl-11
-              text-white
-              placeholder:text-white/60
-              focus:outline-none
-              focus:ring-2
-              focus:ring-white/50
-            `}
-            type="text"
-            name="user_name"
-            placeholder="Name"
-            required
-          />
-          <UserIcon className="pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-white/70" />
-        </div>
-
-        {/* Email */}
-        <div className="relative">
-          <input
-            className={`${poppins.className}
-              peer
-              w-full
-              h-12
-              rounded-lg
-              bg-white/30
-              pl-11
-              text-white
-              placeholder:text-white/60
-              focus:outline-none
-              focus:ring-2
-              focus:ring-white/50
-            `}
-            type="email"
-            name="email"
-            placeholder="Email"
-            required
-          />
-          <AtSymbolIcon className="pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-white/70" />
-        </div>
-
-        {/* Password */}
-        <div className="relative">
-          <input
-            className={`${poppins.className}
-              peer
-              w-full
-              h-12
-              rounded-lg
-              bg-white/30
-              pl-11
-              text-white
-              placeholder:text-white/60
-              focus:outline-none
-              focus:ring-2
-              focus:ring-white/50
-            `}
-            type="password"
-            name="password"
-            placeholder="Password"
-            minLength={6}
-            required
-          />
-          <KeyIcon className="pointer-events-none absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-white/70" />
-        </div>
-      </div>
-
-      <input type="hidden" name="redirectTo" value={callbackUrl} />
-
-      <Button
-        className={`${poppins.className}
-          mt-6
-          w-full
-          h-12
-          rounded-lg
-          bg-[#1d7f6a]
-          hover:bg-[#166655]
-          text-white
-          text-lg
-          font-medium
-          flex
-          items-center
-          justify-center
-        `}
-        aria-disabled={isPending}
-      >
-        Register
-      </Button>
-
-      <p
-        className={`${poppins.className}
-          mt-4
-          text-sm
-          text-center
-          text-white/80
-          antialiased
-        `}
-      >
-        Already have an account?
-        <Link href="/login" className="ml-1 font-medium underline">
-          Log in
-        </Link>
-      </p>
-
-      {errorMessage && (
-        <div
-          className="flex h-8 items-end space-x-1"
-          aria-live="polite"
-          aria-atomic="true"
-        >
-          <ExclamationCircleIcon className="h-5 w-5 text-red-500" />
-          <span className="text-sm text-red-500">{errorMessage}</span>
-        </div>
-      )}
-    </form>
-  );
-}
Index: p/ui/skeletons.tsx
===================================================================
--- app/ui/skeletons.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,4 +1,0 @@
-// Loading animation
-const shimmer =
-  'before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_2s_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/60 before:to-transparent';
-
Index: p/ui/url-search-input.tsx
===================================================================
--- app/ui/url-search-input.tsx	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,57 +1,0 @@
-'use client';
-
-import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
-import { useSearchParams, usePathname, useRouter } from 'next/navigation';
-import { useDebouncedCallback } from 'use-debounce';
-import { poppins } from '@/app/ui/fonts';
-
-const NAVIGATION_START_EVENT = 'fein:navigation-start';
-
-export default function UrlSearchInput({
-    placeholder,
-    queryParam = 'query',
-    debounceMs = 300,
-    resetPageOnChange = false,
-    onNavigateStart,
-}: {
-    placeholder: string;
-    queryParam?: string;
-    debounceMs?: number;
-    resetPageOnChange?: boolean;
-    onNavigateStart?: () => void;
-}) {
-    const searchParams = useSearchParams();
-    const pathname = usePathname();
-    const { replace } = useRouter();
-
-    const handleSearch = useDebouncedCallback((term: string) => {
-        const params = new URLSearchParams(searchParams);
-
-        if (resetPageOnChange) {
-            params.set('page', '1');
-        }
-
-        if (term) {
-            params.set(queryParam, term);
-        } else {
-            params.delete(queryParam);
-        }
-
-        const nextQuery = params.toString();
-        window.dispatchEvent(new Event(NAVIGATION_START_EVENT));
-        onNavigateStart?.();
-        replace(nextQuery ? `${pathname}?${nextQuery}` : pathname, { scroll: false });
-    }, debounceMs);
-
-    return (
-        <div className="relative">
-            <MagnifyingGlassIcon className="pointer-events-none absolute left-3.5 top-1/2 h-5 w-5 -translate-y-1/2 text-white/60" />
-            <input
-                className={`${poppins.className} w-full h-12 rounded-xl bg-white/15 border border-white/15 pl-11 pr-4 text-white placeholder:text-white/50 focus:outline-none focus:ring-2 focus:ring-blue-500/60 focus:border-blue-500/40 transition`}
-                placeholder={placeholder}
-                onChange={(e) => handleSearch(e.target.value)}
-                defaultValue={searchParams.get(queryParam)?.toString()}
-            />
-        </div>
-    );
-}
Index: th.config.ts
===================================================================
--- auth.config.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,49 +1,0 @@
-import type { NextAuthConfig } from 'next-auth';
-
-const AUTH_ROUTES = ['/login', '/register'];
-const PUBLIC_ROUTES = ['/'];
-
-export const authConfig = {
-
-    pages: {
-        signIn: '/login',
-    },
-    callbacks: {
-        async jwt({ token, user }) {
-            if (user) {
-                token.id = user.id;
-            }
-            return token;
-        },
-
-        async session({ session, token }) {
-            if (session.user && token.id) {
-                session.user.id = token.id as string;
-            }
-            return session;
-        },
-
-        authorized({ auth, request: { nextUrl } }) {
-            const isLoggedIn = !!auth?.user;
-            const { pathname } = nextUrl;
-
-            const isAuthRoute = AUTH_ROUTES.some((route) =>
-                pathname.startsWith(route)
-            );
-            const isPublicRoute = PUBLIC_ROUTES.includes(pathname);
-
-            // Not logged in & trying to access protected route
-            if (!isLoggedIn && !isAuthRoute && !isPublicRoute) {
-                return false; // NextAuth will redirect to /login
-            }
-
-            // Logged in & trying to access auth or landing pages
-            if (isLoggedIn && (isAuthRoute || isPublicRoute)) {
-                return Response.redirect(new URL('/dashboard', nextUrl));
-            }
-
-            return true;
-        },
-    },
-    providers: [],
-} satisfies NextAuthConfig;
Index: th.d.ts
===================================================================
--- auth.d.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,13 +1,0 @@
-declare module 'next-auth' {
-    interface Session {
-        user: {
-            id: string; // stringified integer
-            name: string;
-            email: string;
-        };
-    }
-
-    interface JWT {
-        id: string;
-    }
-}
Index: th.ts
===================================================================
--- auth.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,49 +1,0 @@
-import NextAuth from 'next-auth';
-import Credentials from 'next-auth/providers/credentials';
-import { authConfig } from './auth.config';
-import { z } from 'zod';
-import type { User } from '@/app/lib/definitions';
-import bcrypt from 'bcrypt';
-import { sql } from '@/app/lib/db';
-
-async function getUser(email: string): Promise<User | undefined> {
-    try {
-        const user = await sql<User[]>`SELECT * FROM "user" WHERE email=${email}`;
-        return user[0];
-    } catch (error) {
-        console.error('Failed to fetch user:', error);
-        throw new Error('Failed to fetch user.');
-    }
-}
-
-export const { auth, signIn, signOut } = NextAuth({
-    ...authConfig,
-    providers: [
-        Credentials({
-            async authorize(credentials) {
-                const parsedCredentials = z
-                    .object({ email: z.string().email(), password: z.string().min(6) })
-                    .safeParse(credentials);
-
-                if (parsedCredentials.success) {
-                    const { email, password } = parsedCredentials.data;
-
-                    const user = await getUser(email);
-                    if (!user) return null;
-
-                    const passwordsMatch = await bcrypt.compare(password, user.password);
-                    if (passwordsMatch) {
-                        return {
-                            id: String(user.user_id),
-                            name: user.user_name,
-                            email: user.email,
-                        };
-                    }
-                }
-
-                console.log('Invalid credentials');
-                return null;
-            },
-        }),
-    ],
-});
Index: lint.config.mjs
===================================================================
--- eslint.config.mjs	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,9 +1,0 @@
-import { defineConfig, globalIgnores } from 'eslint/config';
-import nextVitals from 'eslint-config-next/core-web-vitals';
-
-const eslintConfig = defineConfig([
-    ...nextVitals,
-    globalIgnores(['.next/**', 'out/**', 'build/**', 'next-env.d.ts']),
-]);
-
-export default eslintConfig;
Index: ddleware.ts
===================================================================
--- middleware.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,19 +1,0 @@
-import NextAuth from 'next-auth';
-import { authConfig } from './auth.config';
-
-export default NextAuth(authConfig).auth;
-
-export const config = {
-    // https://nextjs.org/docs/app/api-reference/file-conventions/proxy#matcher
-    matcher: [
-        /*
-          Match all routes except:
-          - api
-          - _next/static
-          - _next/image
-          - favicon
-          - png images
-        */
-        '/((?!api|_next/static|_next/image|favicon.ico|.*\\.png$).*)',
-    ],
-};
Index: xt.config.ts
===================================================================
--- next.config.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,7 +1,0 @@
-import type { NextConfig } from 'next';
-
-const nextConfig: NextConfig = {
-  /* config options here */
-};
-
-export default nextConfig;
Index: ckage.json
===================================================================
--- package.json	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,42 +1,0 @@
-{
-  "private": true,
-  "scripts": {
-    "build": "next build",
-    "dev": "next dev --turbopack",
-    "start": "next start",
-    "lint": "eslint ."
-  },
-  "dependencies": {
-    "@heroicons/react": "^2.2.0",
-    "@tailwindcss/forms": "^0.5.11",
-    "autoprefixer": "10.4.23",
-    "bcrypt": "^6.0.0",
-    "bcryptjs": "^3.0.3",
-    "clsx": "^2.1.1",
-    "next": "15.5.9",
-    "next-auth": "5.0.0-beta.30",
-    "postgres": "^3.4.8",
-    "react": "latest",
-    "react-dom": "latest",
-    "tailwindcss": "4.1.18",
-    "typescript": "5.9.3",
-    "use-debounce": "^10.1.0",
-    "zod": "^4.3.5"
-  },
-  "devDependencies": {
-    "@tailwindcss/postcss": "^4.1.18",
-    "@types/bcrypt": "^6.0.0",
-    "@types/node": "25.0.9",
-    "@types/react": "19.2.8",
-    "@types/react-dom": "19.2.3",
-    "eslint": "^9.39.2",
-    "eslint-config-next": "^16.1.3",
-    "postcss": "8.5.6"
-  },
-  "pnpm": {
-    "onlyBuiltDependencies": [
-      "bcrypt",
-      "sharp"
-    ]
-  }
-}
Index: pm-lock.yaml
===================================================================
--- pnpm-lock.yaml	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,4224 +1,0 @@
-lockfileVersion: '9.0'
-
-settings:
-  autoInstallPeers: true
-  excludeLinksFromLockfile: false
-
-importers:
-
-  .:
-    dependencies:
-      '@heroicons/react':
-        specifier: ^2.2.0
-        version: 2.2.0(react@19.2.3)
-      '@tailwindcss/forms':
-        specifier: ^0.5.11
-        version: 0.5.11(tailwindcss@4.1.18)
-      autoprefixer:
-        specifier: 10.4.23
-        version: 10.4.23(postcss@8.5.6)
-      bcrypt:
-        specifier: ^6.0.0
-        version: 6.0.0
-      bcryptjs:
-        specifier: ^3.0.3
-        version: 3.0.3
-      clsx:
-        specifier: ^2.1.1
-        version: 2.1.1
-      next:
-        specifier: 15.5.9
-        version: 15.5.9(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      next-auth:
-        specifier: 5.0.0-beta.30
-        version: 5.0.0-beta.30(next@15.5.9(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)
-      postgres:
-        specifier: ^3.4.8
-        version: 3.4.8
-      react:
-        specifier: latest
-        version: 19.2.3
-      react-dom:
-        specifier: latest
-        version: 19.2.3(react@19.2.3)
-      tailwindcss:
-        specifier: 4.1.18
-        version: 4.1.18
-      typescript:
-        specifier: 5.9.3
-        version: 5.9.3
-      use-debounce:
-        specifier: ^10.1.0
-        version: 10.1.0(react@19.2.3)
-      zod:
-        specifier: ^4.3.5
-        version: 4.3.5
-    devDependencies:
-      '@tailwindcss/postcss':
-        specifier: ^4.1.18
-        version: 4.1.18
-      '@types/bcrypt':
-        specifier: ^6.0.0
-        version: 6.0.0
-      '@types/node':
-        specifier: 25.0.9
-        version: 25.0.9
-      '@types/react':
-        specifier: 19.2.8
-        version: 19.2.8
-      '@types/react-dom':
-        specifier: 19.2.3
-        version: 19.2.3(@types/react@19.2.8)
-      eslint:
-        specifier: ^9.39.2
-        version: 9.39.2(jiti@2.6.1)
-      eslint-config-next:
-        specifier: ^16.1.3
-        version: 16.1.3(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      postcss:
-        specifier: 8.5.6
-        version: 8.5.6
-
-packages:
-
-  '@alloc/quick-lru@5.2.0':
-    resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
-    engines: {node: '>=10'}
-
-  '@auth/core@0.41.0':
-    resolution: {integrity: sha512-Wd7mHPQ/8zy6Qj7f4T46vg3aoor8fskJm6g2Zyj064oQ3+p0xNZXAV60ww0hY+MbTesfu29kK14Zk5d5JTazXQ==}
-    peerDependencies:
-      '@simplewebauthn/browser': ^9.0.1
-      '@simplewebauthn/server': ^9.0.2
-      nodemailer: ^6.8.0
-    peerDependenciesMeta:
-      '@simplewebauthn/browser':
-        optional: true
-      '@simplewebauthn/server':
-        optional: true
-      nodemailer:
-        optional: true
-
-  '@babel/code-frame@7.28.6':
-    resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/compat-data@7.28.6':
-    resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/core@7.28.6':
-    resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/generator@7.28.6':
-    resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helper-compilation-targets@7.28.6':
-    resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helper-globals@7.28.0':
-    resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helper-module-imports@7.28.6':
-    resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helper-module-transforms@7.28.6':
-    resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
-
-  '@babel/helper-string-parser@7.27.1':
-    resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helper-validator-identifier@7.28.5':
-    resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helper-validator-option@7.27.1':
-    resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/helpers@7.28.6':
-    resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/parser@7.28.6':
-    resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==}
-    engines: {node: '>=6.0.0'}
-    hasBin: true
-
-  '@babel/template@7.28.6':
-    resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/traverse@7.28.6':
-    resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==}
-    engines: {node: '>=6.9.0'}
-
-  '@babel/types@7.28.6':
-    resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==}
-    engines: {node: '>=6.9.0'}
-
-  '@emnapi/core@1.8.1':
-    resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==}
-
-  '@emnapi/runtime@1.8.1':
-    resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==}
-
-  '@emnapi/wasi-threads@1.1.0':
-    resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
-
-  '@eslint-community/eslint-utils@4.9.1':
-    resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
-
-  '@eslint-community/regexpp@4.12.2':
-    resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
-    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
-
-  '@eslint/config-array@0.21.1':
-    resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@eslint/config-helpers@0.4.2':
-    resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@eslint/core@0.17.0':
-    resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@eslint/eslintrc@3.3.3':
-    resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@eslint/js@9.39.2':
-    resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@eslint/object-schema@2.1.7':
-    resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@eslint/plugin-kit@0.4.1':
-    resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@heroicons/react@2.2.0':
-    resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==}
-    peerDependencies:
-      react: '>= 16 || ^19.0.0-rc'
-
-  '@humanfs/core@0.19.1':
-    resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
-    engines: {node: '>=18.18.0'}
-
-  '@humanfs/node@0.16.7':
-    resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
-    engines: {node: '>=18.18.0'}
-
-  '@humanwhocodes/module-importer@1.0.1':
-    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
-    engines: {node: '>=12.22'}
-
-  '@humanwhocodes/retry@0.4.3':
-    resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
-    engines: {node: '>=18.18'}
-
-  '@img/colour@1.0.0':
-    resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
-    engines: {node: '>=18'}
-
-  '@img/sharp-darwin-arm64@0.34.5':
-    resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@img/sharp-darwin-x64@0.34.5':
-    resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [darwin]
-
-  '@img/sharp-libvips-darwin-arm64@1.2.4':
-    resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@img/sharp-libvips-darwin-x64@1.2.4':
-    resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
-    cpu: [x64]
-    os: [darwin]
-
-  '@img/sharp-libvips-linux-arm64@1.2.4':
-    resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-arm@1.2.4':
-    resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
-    cpu: [arm]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-ppc64@1.2.4':
-    resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
-    cpu: [ppc64]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-riscv64@1.2.4':
-    resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
-    cpu: [riscv64]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-s390x@1.2.4':
-    resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
-    cpu: [s390x]
-    os: [linux]
-
-  '@img/sharp-libvips-linux-x64@1.2.4':
-    resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
-    resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-libvips-linuxmusl-x64@1.2.4':
-    resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-linux-arm64@0.34.5':
-    resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-linux-arm@0.34.5':
-    resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm]
-    os: [linux]
-
-  '@img/sharp-linux-ppc64@0.34.5':
-    resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [ppc64]
-    os: [linux]
-
-  '@img/sharp-linux-riscv64@0.34.5':
-    resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [riscv64]
-    os: [linux]
-
-  '@img/sharp-linux-s390x@0.34.5':
-    resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [s390x]
-    os: [linux]
-
-  '@img/sharp-linux-x64@0.34.5':
-    resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-linuxmusl-arm64@0.34.5':
-    resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [linux]
-
-  '@img/sharp-linuxmusl-x64@0.34.5':
-    resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [linux]
-
-  '@img/sharp-wasm32@0.34.5':
-    resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [wasm32]
-
-  '@img/sharp-win32-arm64@0.34.5':
-    resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [arm64]
-    os: [win32]
-
-  '@img/sharp-win32-ia32@0.34.5':
-    resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [ia32]
-    os: [win32]
-
-  '@img/sharp-win32-x64@0.34.5':
-    resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-    cpu: [x64]
-    os: [win32]
-
-  '@jridgewell/gen-mapping@0.3.13':
-    resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
-
-  '@jridgewell/remapping@2.3.5':
-    resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
-
-  '@jridgewell/resolve-uri@3.1.2':
-    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
-    engines: {node: '>=6.0.0'}
-
-  '@jridgewell/sourcemap-codec@1.5.5':
-    resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
-
-  '@jridgewell/trace-mapping@0.3.31':
-    resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
-
-  '@napi-rs/wasm-runtime@0.2.12':
-    resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
-
-  '@next/env@15.5.9':
-    resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==}
-
-  '@next/eslint-plugin-next@16.1.3':
-    resolution: {integrity: sha512-MqBh3ltFAy0AZCRFVdjVjjeV7nEszJDaVIpDAnkQcn8U9ib6OEwkSnuK6xdYxMGPhV/Y4IlY6RbDipPOpLfBqQ==}
-
-  '@next/swc-darwin-arm64@15.5.7':
-    resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@next/swc-darwin-x64@15.5.7':
-    resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [darwin]
-
-  '@next/swc-linux-arm64-gnu@15.5.7':
-    resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [linux]
-
-  '@next/swc-linux-arm64-musl@15.5.7':
-    resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [linux]
-
-  '@next/swc-linux-x64-gnu@15.5.7':
-    resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [linux]
-
-  '@next/swc-linux-x64-musl@15.5.7':
-    resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [linux]
-
-  '@next/swc-win32-arm64-msvc@15.5.7':
-    resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [win32]
-
-  '@next/swc-win32-x64-msvc@15.5.7':
-    resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [win32]
-
-  '@nodelib/fs.scandir@2.1.5':
-    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
-    engines: {node: '>= 8'}
-
-  '@nodelib/fs.stat@2.0.5':
-    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
-    engines: {node: '>= 8'}
-
-  '@nodelib/fs.walk@1.2.8':
-    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
-    engines: {node: '>= 8'}
-
-  '@nolyfill/is-core-module@1.0.39':
-    resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
-    engines: {node: '>=12.4.0'}
-
-  '@panva/hkdf@1.2.1':
-    resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
-
-  '@rtsao/scc@1.1.0':
-    resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
-
-  '@swc/helpers@0.5.15':
-    resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
-
-  '@tailwindcss/forms@0.5.11':
-    resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==}
-    peerDependencies:
-      tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
-
-  '@tailwindcss/node@4.1.18':
-    resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
-
-  '@tailwindcss/oxide-android-arm64@4.1.18':
-    resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [android]
-
-  '@tailwindcss/oxide-darwin-arm64@4.1.18':
-    resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@tailwindcss/oxide-darwin-x64@4.1.18':
-    resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [darwin]
-
-  '@tailwindcss/oxide-freebsd-x64@4.1.18':
-    resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [freebsd]
-
-  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
-    resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==}
-    engines: {node: '>= 10'}
-    cpu: [arm]
-    os: [linux]
-
-  '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
-    resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [linux]
-
-  '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
-    resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [linux]
-
-  '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
-    resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [linux]
-
-  '@tailwindcss/oxide-linux-x64-musl@4.1.18':
-    resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [linux]
-
-  '@tailwindcss/oxide-wasm32-wasi@4.1.18':
-    resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
-    engines: {node: '>=14.0.0'}
-    cpu: [wasm32]
-    bundledDependencies:
-      - '@napi-rs/wasm-runtime'
-      - '@emnapi/core'
-      - '@emnapi/runtime'
-      - '@tybys/wasm-util'
-      - '@emnapi/wasi-threads'
-      - tslib
-
-  '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
-    resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==}
-    engines: {node: '>= 10'}
-    cpu: [arm64]
-    os: [win32]
-
-  '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
-    resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==}
-    engines: {node: '>= 10'}
-    cpu: [x64]
-    os: [win32]
-
-  '@tailwindcss/oxide@4.1.18':
-    resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==}
-    engines: {node: '>= 10'}
-
-  '@tailwindcss/postcss@4.1.18':
-    resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
-
-  '@tybys/wasm-util@0.10.1':
-    resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
-
-  '@types/bcrypt@6.0.0':
-    resolution: {integrity: sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==}
-
-  '@types/estree@1.0.8':
-    resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
-
-  '@types/json-schema@7.0.15':
-    resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
-
-  '@types/json5@0.0.29':
-    resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
-
-  '@types/node@25.0.9':
-    resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==}
-
-  '@types/react-dom@19.2.3':
-    resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
-    peerDependencies:
-      '@types/react': ^19.2.0
-
-  '@types/react@19.2.8':
-    resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==}
-
-  '@typescript-eslint/eslint-plugin@8.53.1':
-    resolution: {integrity: sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      '@typescript-eslint/parser': ^8.53.1
-      eslint: ^8.57.0 || ^9.0.0
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/parser@8.53.1':
-    resolution: {integrity: sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      eslint: ^8.57.0 || ^9.0.0
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/project-service@8.53.1':
-    resolution: {integrity: sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/scope-manager@8.53.1':
-    resolution: {integrity: sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@typescript-eslint/tsconfig-utils@8.53.1':
-    resolution: {integrity: sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/type-utils@8.53.1':
-    resolution: {integrity: sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      eslint: ^8.57.0 || ^9.0.0
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/types@8.53.1':
-    resolution: {integrity: sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@typescript-eslint/typescript-estree@8.53.1':
-    resolution: {integrity: sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/utils@8.53.1':
-    resolution: {integrity: sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      eslint: ^8.57.0 || ^9.0.0
-      typescript: '>=4.8.4 <6.0.0'
-
-  '@typescript-eslint/visitor-keys@8.53.1':
-    resolution: {integrity: sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  '@unrs/resolver-binding-android-arm-eabi@1.11.1':
-    resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==}
-    cpu: [arm]
-    os: [android]
-
-  '@unrs/resolver-binding-android-arm64@1.11.1':
-    resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==}
-    cpu: [arm64]
-    os: [android]
-
-  '@unrs/resolver-binding-darwin-arm64@1.11.1':
-    resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==}
-    cpu: [arm64]
-    os: [darwin]
-
-  '@unrs/resolver-binding-darwin-x64@1.11.1':
-    resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==}
-    cpu: [x64]
-    os: [darwin]
-
-  '@unrs/resolver-binding-freebsd-x64@1.11.1':
-    resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==}
-    cpu: [x64]
-    os: [freebsd]
-
-  '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1':
-    resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==}
-    cpu: [arm]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1':
-    resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==}
-    cpu: [arm]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-arm64-gnu@1.11.1':
-    resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
-    cpu: [arm64]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
-    resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
-    cpu: [arm64]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
-    resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
-    cpu: [ppc64]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
-    resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
-    cpu: [riscv64]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
-    resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
-    cpu: [riscv64]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
-    resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
-    cpu: [s390x]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
-    resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
-    cpu: [x64]
-    os: [linux]
-
-  '@unrs/resolver-binding-linux-x64-musl@1.11.1':
-    resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
-    cpu: [x64]
-    os: [linux]
-
-  '@unrs/resolver-binding-wasm32-wasi@1.11.1':
-    resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
-    engines: {node: '>=14.0.0'}
-    cpu: [wasm32]
-
-  '@unrs/resolver-binding-win32-arm64-msvc@1.11.1':
-    resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==}
-    cpu: [arm64]
-    os: [win32]
-
-  '@unrs/resolver-binding-win32-ia32-msvc@1.11.1':
-    resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==}
-    cpu: [ia32]
-    os: [win32]
-
-  '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
-    resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==}
-    cpu: [x64]
-    os: [win32]
-
-  acorn-jsx@5.3.2:
-    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
-    peerDependencies:
-      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
-
-  acorn@8.15.0:
-    resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
-    engines: {node: '>=0.4.0'}
-    hasBin: true
-
-  ajv@6.12.6:
-    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
-
-  ansi-styles@4.3.0:
-    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
-    engines: {node: '>=8'}
-
-  argparse@2.0.1:
-    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
-
-  aria-query@5.3.2:
-    resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
-    engines: {node: '>= 0.4'}
-
-  array-buffer-byte-length@1.0.2:
-    resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
-    engines: {node: '>= 0.4'}
-
-  array-includes@3.1.9:
-    resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==}
-    engines: {node: '>= 0.4'}
-
-  array.prototype.findlast@1.2.5:
-    resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
-    engines: {node: '>= 0.4'}
-
-  array.prototype.findlastindex@1.2.6:
-    resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==}
-    engines: {node: '>= 0.4'}
-
-  array.prototype.flat@1.3.3:
-    resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
-    engines: {node: '>= 0.4'}
-
-  array.prototype.flatmap@1.3.3:
-    resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
-    engines: {node: '>= 0.4'}
-
-  array.prototype.tosorted@1.1.4:
-    resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
-    engines: {node: '>= 0.4'}
-
-  arraybuffer.prototype.slice@1.0.4:
-    resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
-    engines: {node: '>= 0.4'}
-
-  ast-types-flow@0.0.8:
-    resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
-
-  async-function@1.0.0:
-    resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
-    engines: {node: '>= 0.4'}
-
-  autoprefixer@10.4.23:
-    resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==}
-    engines: {node: ^10 || ^12 || >=14}
-    hasBin: true
-    peerDependencies:
-      postcss: ^8.1.0
-
-  available-typed-arrays@1.0.7:
-    resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
-    engines: {node: '>= 0.4'}
-
-  axe-core@4.11.1:
-    resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==}
-    engines: {node: '>=4'}
-
-  axobject-query@4.1.0:
-    resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
-    engines: {node: '>= 0.4'}
-
-  balanced-match@1.0.2:
-    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
-  baseline-browser-mapping@2.9.15:
-    resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==}
-    hasBin: true
-
-  bcrypt@6.0.0:
-    resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==}
-    engines: {node: '>= 18'}
-
-  bcryptjs@3.0.3:
-    resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==}
-    hasBin: true
-
-  brace-expansion@1.1.12:
-    resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
-
-  brace-expansion@2.0.2:
-    resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
-
-  braces@3.0.3:
-    resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
-    engines: {node: '>=8'}
-
-  browserslist@4.28.1:
-    resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
-    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
-    hasBin: true
-
-  call-bind-apply-helpers@1.0.2:
-    resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
-    engines: {node: '>= 0.4'}
-
-  call-bind@1.0.8:
-    resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
-    engines: {node: '>= 0.4'}
-
-  call-bound@1.0.4:
-    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
-    engines: {node: '>= 0.4'}
-
-  callsites@3.1.0:
-    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
-    engines: {node: '>=6'}
-
-  caniuse-lite@1.0.30001765:
-    resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==}
-
-  chalk@4.1.2:
-    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
-    engines: {node: '>=10'}
-
-  client-only@0.0.1:
-    resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
-
-  clsx@2.1.1:
-    resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
-    engines: {node: '>=6'}
-
-  color-convert@2.0.1:
-    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
-    engines: {node: '>=7.0.0'}
-
-  color-name@1.1.4:
-    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-
-  concat-map@0.0.1:
-    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
-  convert-source-map@2.0.0:
-    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-
-  cross-spawn@7.0.6:
-    resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
-    engines: {node: '>= 8'}
-
-  csstype@3.2.3:
-    resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
-
-  damerau-levenshtein@1.0.8:
-    resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
-
-  data-view-buffer@1.0.2:
-    resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
-    engines: {node: '>= 0.4'}
-
-  data-view-byte-length@1.0.2:
-    resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
-    engines: {node: '>= 0.4'}
-
-  data-view-byte-offset@1.0.1:
-    resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
-    engines: {node: '>= 0.4'}
-
-  debug@3.2.7:
-    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
-
-  debug@4.4.3:
-    resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
-    engines: {node: '>=6.0'}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
-
-  deep-is@0.1.4:
-    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
-
-  define-data-property@1.1.4:
-    resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
-    engines: {node: '>= 0.4'}
-
-  define-properties@1.2.1:
-    resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
-    engines: {node: '>= 0.4'}
-
-  detect-libc@2.1.2:
-    resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
-    engines: {node: '>=8'}
-
-  doctrine@2.1.0:
-    resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
-    engines: {node: '>=0.10.0'}
-
-  dunder-proto@1.0.1:
-    resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
-    engines: {node: '>= 0.4'}
-
-  electron-to-chromium@1.5.267:
-    resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
-
-  emoji-regex@9.2.2:
-    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
-
-  enhanced-resolve@5.18.4:
-    resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
-    engines: {node: '>=10.13.0'}
-
-  es-abstract@1.24.1:
-    resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==}
-    engines: {node: '>= 0.4'}
-
-  es-define-property@1.0.1:
-    resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
-    engines: {node: '>= 0.4'}
-
-  es-errors@1.3.0:
-    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
-    engines: {node: '>= 0.4'}
-
-  es-iterator-helpers@1.2.2:
-    resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==}
-    engines: {node: '>= 0.4'}
-
-  es-object-atoms@1.1.1:
-    resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
-    engines: {node: '>= 0.4'}
-
-  es-set-tostringtag@2.1.0:
-    resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
-    engines: {node: '>= 0.4'}
-
-  es-shim-unscopables@1.1.0:
-    resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
-    engines: {node: '>= 0.4'}
-
-  es-to-primitive@1.3.0:
-    resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
-    engines: {node: '>= 0.4'}
-
-  escalade@3.2.0:
-    resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
-    engines: {node: '>=6'}
-
-  escape-string-regexp@4.0.0:
-    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
-    engines: {node: '>=10'}
-
-  eslint-config-next@16.1.3:
-    resolution: {integrity: sha512-q2Z87VSsoJcv+vgR+Dm8NPRf+rErXcRktuBR5y3umo/j5zLjIWH7rqBCh3X804gUGKbOrqbgsLUkqDE35C93Gw==}
-    peerDependencies:
-      eslint: '>=9.0.0'
-      typescript: '>=3.3.1'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-
-  eslint-import-resolver-node@0.3.9:
-    resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
-
-  eslint-import-resolver-typescript@3.10.1:
-    resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    peerDependencies:
-      eslint: '*'
-      eslint-plugin-import: '*'
-      eslint-plugin-import-x: '*'
-    peerDependenciesMeta:
-      eslint-plugin-import:
-        optional: true
-      eslint-plugin-import-x:
-        optional: true
-
-  eslint-module-utils@2.12.1:
-    resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      '@typescript-eslint/parser': '*'
-      eslint: '*'
-      eslint-import-resolver-node: '*'
-      eslint-import-resolver-typescript: '*'
-      eslint-import-resolver-webpack: '*'
-    peerDependenciesMeta:
-      '@typescript-eslint/parser':
-        optional: true
-      eslint:
-        optional: true
-      eslint-import-resolver-node:
-        optional: true
-      eslint-import-resolver-typescript:
-        optional: true
-      eslint-import-resolver-webpack:
-        optional: true
-
-  eslint-plugin-import@2.32.0:
-    resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      '@typescript-eslint/parser': '*'
-      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
-    peerDependenciesMeta:
-      '@typescript-eslint/parser':
-        optional: true
-
-  eslint-plugin-jsx-a11y@6.10.2:
-    resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==}
-    engines: {node: '>=4.0'}
-    peerDependencies:
-      eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9
-
-  eslint-plugin-react-hooks@7.0.1:
-    resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==}
-    engines: {node: '>=18'}
-    peerDependencies:
-      eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
-
-  eslint-plugin-react@7.37.5:
-    resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
-    engines: {node: '>=4'}
-    peerDependencies:
-      eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
-
-  eslint-scope@8.4.0:
-    resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  eslint-visitor-keys@3.4.3:
-    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
-  eslint-visitor-keys@4.2.1:
-    resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  eslint@9.39.2:
-    resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    hasBin: true
-    peerDependencies:
-      jiti: '*'
-    peerDependenciesMeta:
-      jiti:
-        optional: true
-
-  espree@10.4.0:
-    resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
-  esquery@1.7.0:
-    resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
-    engines: {node: '>=0.10'}
-
-  esrecurse@4.3.0:
-    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
-    engines: {node: '>=4.0'}
-
-  estraverse@5.3.0:
-    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
-    engines: {node: '>=4.0'}
-
-  esutils@2.0.3:
-    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
-    engines: {node: '>=0.10.0'}
-
-  fast-deep-equal@3.1.3:
-    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-
-  fast-glob@3.3.1:
-    resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
-    engines: {node: '>=8.6.0'}
-
-  fast-json-stable-stringify@2.1.0:
-    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
-
-  fast-levenshtein@2.0.6:
-    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
-
-  fastq@1.20.1:
-    resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
-
-  fdir@6.5.0:
-    resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
-    engines: {node: '>=12.0.0'}
-    peerDependencies:
-      picomatch: ^3 || ^4
-    peerDependenciesMeta:
-      picomatch:
-        optional: true
-
-  file-entry-cache@8.0.0:
-    resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
-    engines: {node: '>=16.0.0'}
-
-  fill-range@7.1.1:
-    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
-    engines: {node: '>=8'}
-
-  find-up@5.0.0:
-    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
-    engines: {node: '>=10'}
-
-  flat-cache@4.0.1:
-    resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
-    engines: {node: '>=16'}
-
-  flatted@3.3.3:
-    resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
-
-  for-each@0.3.5:
-    resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
-    engines: {node: '>= 0.4'}
-
-  fraction.js@5.3.4:
-    resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
-
-  function-bind@1.1.2:
-    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
-
-  function.prototype.name@1.1.8:
-    resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
-    engines: {node: '>= 0.4'}
-
-  functions-have-names@1.2.3:
-    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
-
-  generator-function@2.0.1:
-    resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==}
-    engines: {node: '>= 0.4'}
-
-  gensync@1.0.0-beta.2:
-    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
-    engines: {node: '>=6.9.0'}
-
-  get-intrinsic@1.3.0:
-    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
-    engines: {node: '>= 0.4'}
-
-  get-proto@1.0.1:
-    resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
-    engines: {node: '>= 0.4'}
-
-  get-symbol-description@1.1.0:
-    resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
-    engines: {node: '>= 0.4'}
-
-  get-tsconfig@4.13.0:
-    resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
-
-  glob-parent@5.1.2:
-    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
-    engines: {node: '>= 6'}
-
-  glob-parent@6.0.2:
-    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
-    engines: {node: '>=10.13.0'}
-
-  globals@14.0.0:
-    resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
-    engines: {node: '>=18'}
-
-  globals@16.4.0:
-    resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==}
-    engines: {node: '>=18'}
-
-  globalthis@1.0.4:
-    resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
-    engines: {node: '>= 0.4'}
-
-  gopd@1.2.0:
-    resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
-    engines: {node: '>= 0.4'}
-
-  graceful-fs@4.2.11:
-    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
-  has-bigints@1.1.0:
-    resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
-    engines: {node: '>= 0.4'}
-
-  has-flag@4.0.0:
-    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
-    engines: {node: '>=8'}
-
-  has-property-descriptors@1.0.2:
-    resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
-
-  has-proto@1.2.0:
-    resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
-    engines: {node: '>= 0.4'}
-
-  has-symbols@1.1.0:
-    resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
-    engines: {node: '>= 0.4'}
-
-  has-tostringtag@1.0.2:
-    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
-    engines: {node: '>= 0.4'}
-
-  hasown@2.0.2:
-    resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
-    engines: {node: '>= 0.4'}
-
-  hermes-estree@0.25.1:
-    resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
-
-  hermes-parser@0.25.1:
-    resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
-
-  ignore@5.3.2:
-    resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
-    engines: {node: '>= 4'}
-
-  ignore@7.0.5:
-    resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
-    engines: {node: '>= 4'}
-
-  import-fresh@3.3.1:
-    resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
-    engines: {node: '>=6'}
-
-  imurmurhash@0.1.4:
-    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
-    engines: {node: '>=0.8.19'}
-
-  internal-slot@1.1.0:
-    resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
-    engines: {node: '>= 0.4'}
-
-  is-array-buffer@3.0.5:
-    resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
-    engines: {node: '>= 0.4'}
-
-  is-async-function@2.1.1:
-    resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
-    engines: {node: '>= 0.4'}
-
-  is-bigint@1.1.0:
-    resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
-    engines: {node: '>= 0.4'}
-
-  is-boolean-object@1.2.2:
-    resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
-    engines: {node: '>= 0.4'}
-
-  is-bun-module@2.0.0:
-    resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==}
-
-  is-callable@1.2.7:
-    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
-    engines: {node: '>= 0.4'}
-
-  is-core-module@2.16.1:
-    resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
-    engines: {node: '>= 0.4'}
-
-  is-data-view@1.0.2:
-    resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
-    engines: {node: '>= 0.4'}
-
-  is-date-object@1.1.0:
-    resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
-    engines: {node: '>= 0.4'}
-
-  is-extglob@2.1.1:
-    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
-    engines: {node: '>=0.10.0'}
-
-  is-finalizationregistry@1.1.1:
-    resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
-    engines: {node: '>= 0.4'}
-
-  is-generator-function@1.1.2:
-    resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==}
-    engines: {node: '>= 0.4'}
-
-  is-glob@4.0.3:
-    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
-    engines: {node: '>=0.10.0'}
-
-  is-map@2.0.3:
-    resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
-    engines: {node: '>= 0.4'}
-
-  is-negative-zero@2.0.3:
-    resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
-    engines: {node: '>= 0.4'}
-
-  is-number-object@1.1.1:
-    resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
-    engines: {node: '>= 0.4'}
-
-  is-number@7.0.0:
-    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
-    engines: {node: '>=0.12.0'}
-
-  is-regex@1.2.1:
-    resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
-    engines: {node: '>= 0.4'}
-
-  is-set@2.0.3:
-    resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
-    engines: {node: '>= 0.4'}
-
-  is-shared-array-buffer@1.0.4:
-    resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
-    engines: {node: '>= 0.4'}
-
-  is-string@1.1.1:
-    resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
-    engines: {node: '>= 0.4'}
-
-  is-symbol@1.1.1:
-    resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
-    engines: {node: '>= 0.4'}
-
-  is-typed-array@1.1.15:
-    resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
-    engines: {node: '>= 0.4'}
-
-  is-weakmap@2.0.2:
-    resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
-    engines: {node: '>= 0.4'}
-
-  is-weakref@1.1.1:
-    resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
-    engines: {node: '>= 0.4'}
-
-  is-weakset@2.0.4:
-    resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
-    engines: {node: '>= 0.4'}
-
-  isarray@2.0.5:
-    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
-
-  isexe@2.0.0:
-    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-
-  iterator.prototype@1.1.5:
-    resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
-    engines: {node: '>= 0.4'}
-
-  jiti@2.6.1:
-    resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
-    hasBin: true
-
-  jose@6.1.3:
-    resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
-
-  js-tokens@4.0.0:
-    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
-  js-yaml@4.1.1:
-    resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
-    hasBin: true
-
-  jsesc@3.1.0:
-    resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
-    engines: {node: '>=6'}
-    hasBin: true
-
-  json-buffer@3.0.1:
-    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
-
-  json-schema-traverse@0.4.1:
-    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
-
-  json-stable-stringify-without-jsonify@1.0.1:
-    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
-
-  json5@1.0.2:
-    resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
-    hasBin: true
-
-  json5@2.2.3:
-    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
-    engines: {node: '>=6'}
-    hasBin: true
-
-  jsx-ast-utils@3.3.5:
-    resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
-    engines: {node: '>=4.0'}
-
-  keyv@4.5.4:
-    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
-
-  language-subtag-registry@0.3.23:
-    resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
-
-  language-tags@1.0.9:
-    resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
-    engines: {node: '>=0.10'}
-
-  levn@0.4.1:
-    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
-    engines: {node: '>= 0.8.0'}
-
-  lightningcss-android-arm64@1.30.2:
-    resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [arm64]
-    os: [android]
-
-  lightningcss-darwin-arm64@1.30.2:
-    resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [arm64]
-    os: [darwin]
-
-  lightningcss-darwin-x64@1.30.2:
-    resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [x64]
-    os: [darwin]
-
-  lightningcss-freebsd-x64@1.30.2:
-    resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [x64]
-    os: [freebsd]
-
-  lightningcss-linux-arm-gnueabihf@1.30.2:
-    resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [arm]
-    os: [linux]
-
-  lightningcss-linux-arm64-gnu@1.30.2:
-    resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [arm64]
-    os: [linux]
-
-  lightningcss-linux-arm64-musl@1.30.2:
-    resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [arm64]
-    os: [linux]
-
-  lightningcss-linux-x64-gnu@1.30.2:
-    resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [x64]
-    os: [linux]
-
-  lightningcss-linux-x64-musl@1.30.2:
-    resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [x64]
-    os: [linux]
-
-  lightningcss-win32-arm64-msvc@1.30.2:
-    resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [arm64]
-    os: [win32]
-
-  lightningcss-win32-x64-msvc@1.30.2:
-    resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
-    engines: {node: '>= 12.0.0'}
-    cpu: [x64]
-    os: [win32]
-
-  lightningcss@1.30.2:
-    resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
-    engines: {node: '>= 12.0.0'}
-
-  locate-path@6.0.0:
-    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
-    engines: {node: '>=10'}
-
-  lodash.merge@4.6.2:
-    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
-
-  loose-envify@1.4.0:
-    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
-    hasBin: true
-
-  lru-cache@5.1.1:
-    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
-
-  magic-string@0.30.21:
-    resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
-
-  math-intrinsics@1.1.0:
-    resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
-    engines: {node: '>= 0.4'}
-
-  merge2@1.4.1:
-    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
-    engines: {node: '>= 8'}
-
-  micromatch@4.0.8:
-    resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
-    engines: {node: '>=8.6'}
-
-  mini-svg-data-uri@1.4.4:
-    resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
-    hasBin: true
-
-  minimatch@3.1.2:
-    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
-
-  minimatch@9.0.5:
-    resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
-    engines: {node: '>=16 || 14 >=14.17'}
-
-  minimist@1.2.8:
-    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
-
-  ms@2.1.3:
-    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-
-  nanoid@3.3.11:
-    resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
-    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
-    hasBin: true
-
-  napi-postinstall@0.3.4:
-    resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==}
-    engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
-    hasBin: true
-
-  natural-compare@1.4.0:
-    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
-
-  next-auth@5.0.0-beta.30:
-    resolution: {integrity: sha512-+c51gquM3F6nMVmoAusRJ7RIoY0K4Ts9HCCwyy/BRoe4mp3msZpOzYMyb5LAYc1wSo74PMQkGDcaghIO7W6Xjg==}
-    peerDependencies:
-      '@simplewebauthn/browser': ^9.0.1
-      '@simplewebauthn/server': ^9.0.2
-      next: ^14.0.0-0 || ^15.0.0 || ^16.0.0
-      nodemailer: ^7.0.7
-      react: ^18.2.0 || ^19.0.0
-    peerDependenciesMeta:
-      '@simplewebauthn/browser':
-        optional: true
-      '@simplewebauthn/server':
-        optional: true
-      nodemailer:
-        optional: true
-
-  next@15.5.9:
-    resolution: {integrity: sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==}
-    engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
-    hasBin: true
-    peerDependencies:
-      '@opentelemetry/api': ^1.1.0
-      '@playwright/test': ^1.51.1
-      babel-plugin-react-compiler: '*'
-      react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
-      react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
-      sass: ^1.3.0
-    peerDependenciesMeta:
-      '@opentelemetry/api':
-        optional: true
-      '@playwright/test':
-        optional: true
-      babel-plugin-react-compiler:
-        optional: true
-      sass:
-        optional: true
-
-  node-addon-api@8.5.0:
-    resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==}
-    engines: {node: ^18 || ^20 || >= 21}
-
-  node-gyp-build@4.8.4:
-    resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
-    hasBin: true
-
-  node-releases@2.0.27:
-    resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
-
-  oauth4webapi@3.8.3:
-    resolution: {integrity: sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw==}
-
-  object-assign@4.1.1:
-    resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
-    engines: {node: '>=0.10.0'}
-
-  object-inspect@1.13.4:
-    resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
-    engines: {node: '>= 0.4'}
-
-  object-keys@1.1.1:
-    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
-    engines: {node: '>= 0.4'}
-
-  object.assign@4.1.7:
-    resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
-    engines: {node: '>= 0.4'}
-
-  object.entries@1.1.9:
-    resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
-    engines: {node: '>= 0.4'}
-
-  object.fromentries@2.0.8:
-    resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
-    engines: {node: '>= 0.4'}
-
-  object.groupby@1.0.3:
-    resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
-    engines: {node: '>= 0.4'}
-
-  object.values@1.2.1:
-    resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
-    engines: {node: '>= 0.4'}
-
-  optionator@0.9.4:
-    resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
-    engines: {node: '>= 0.8.0'}
-
-  own-keys@1.0.1:
-    resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
-    engines: {node: '>= 0.4'}
-
-  p-limit@3.1.0:
-    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
-    engines: {node: '>=10'}
-
-  p-locate@5.0.0:
-    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
-    engines: {node: '>=10'}
-
-  parent-module@1.0.1:
-    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
-    engines: {node: '>=6'}
-
-  path-exists@4.0.0:
-    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
-    engines: {node: '>=8'}
-
-  path-key@3.1.1:
-    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
-    engines: {node: '>=8'}
-
-  path-parse@1.0.7:
-    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
-
-  picocolors@1.1.1:
-    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
-
-  picomatch@2.3.1:
-    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
-    engines: {node: '>=8.6'}
-
-  picomatch@4.0.3:
-    resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
-    engines: {node: '>=12'}
-
-  possible-typed-array-names@1.1.0:
-    resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
-    engines: {node: '>= 0.4'}
-
-  postcss-value-parser@4.2.0:
-    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
-
-  postcss@8.4.31:
-    resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
-    engines: {node: ^10 || ^12 || >=14}
-
-  postcss@8.5.6:
-    resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
-    engines: {node: ^10 || ^12 || >=14}
-
-  postgres@3.4.8:
-    resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==}
-    engines: {node: '>=12'}
-
-  preact-render-to-string@6.5.11:
-    resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==}
-    peerDependencies:
-      preact: '>=10'
-
-  preact@10.24.3:
-    resolution: {integrity: sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==}
-
-  prelude-ls@1.2.1:
-    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
-    engines: {node: '>= 0.8.0'}
-
-  prop-types@15.8.1:
-    resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
-
-  punycode@2.3.1:
-    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
-    engines: {node: '>=6'}
-
-  queue-microtask@1.2.3:
-    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
-
-  react-dom@19.2.3:
-    resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==}
-    peerDependencies:
-      react: ^19.2.3
-
-  react-is@16.13.1:
-    resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
-
-  react@19.2.3:
-    resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==}
-    engines: {node: '>=0.10.0'}
-
-  reflect.getprototypeof@1.0.10:
-    resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
-    engines: {node: '>= 0.4'}
-
-  regexp.prototype.flags@1.5.4:
-    resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
-    engines: {node: '>= 0.4'}
-
-  resolve-from@4.0.0:
-    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
-    engines: {node: '>=4'}
-
-  resolve-pkg-maps@1.0.0:
-    resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
-
-  resolve@1.22.11:
-    resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
-    engines: {node: '>= 0.4'}
-    hasBin: true
-
-  resolve@2.0.0-next.5:
-    resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
-    hasBin: true
-
-  reusify@1.1.0:
-    resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
-    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
-
-  run-parallel@1.2.0:
-    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
-
-  safe-array-concat@1.1.3:
-    resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
-    engines: {node: '>=0.4'}
-
-  safe-push-apply@1.0.0:
-    resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
-    engines: {node: '>= 0.4'}
-
-  safe-regex-test@1.1.0:
-    resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
-    engines: {node: '>= 0.4'}
-
-  scheduler@0.27.0:
-    resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
-
-  semver@6.3.1:
-    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
-    hasBin: true
-
-  semver@7.7.3:
-    resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
-    engines: {node: '>=10'}
-    hasBin: true
-
-  set-function-length@1.2.2:
-    resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
-    engines: {node: '>= 0.4'}
-
-  set-function-name@2.0.2:
-    resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
-    engines: {node: '>= 0.4'}
-
-  set-proto@1.0.0:
-    resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
-    engines: {node: '>= 0.4'}
-
-  sharp@0.34.5:
-    resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
-    engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-
-  shebang-command@2.0.0:
-    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
-    engines: {node: '>=8'}
-
-  shebang-regex@3.0.0:
-    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
-    engines: {node: '>=8'}
-
-  side-channel-list@1.0.0:
-    resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
-    engines: {node: '>= 0.4'}
-
-  side-channel-map@1.0.1:
-    resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
-    engines: {node: '>= 0.4'}
-
-  side-channel-weakmap@1.0.2:
-    resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
-    engines: {node: '>= 0.4'}
-
-  side-channel@1.1.0:
-    resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
-    engines: {node: '>= 0.4'}
-
-  source-map-js@1.2.1:
-    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
-    engines: {node: '>=0.10.0'}
-
-  stable-hash@0.0.5:
-    resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
-
-  stop-iteration-iterator@1.1.0:
-    resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
-    engines: {node: '>= 0.4'}
-
-  string.prototype.includes@2.0.1:
-    resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==}
-    engines: {node: '>= 0.4'}
-
-  string.prototype.matchall@4.0.12:
-    resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
-    engines: {node: '>= 0.4'}
-
-  string.prototype.repeat@1.0.0:
-    resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
-
-  string.prototype.trim@1.2.10:
-    resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
-    engines: {node: '>= 0.4'}
-
-  string.prototype.trimend@1.0.9:
-    resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
-    engines: {node: '>= 0.4'}
-
-  string.prototype.trimstart@1.0.8:
-    resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
-    engines: {node: '>= 0.4'}
-
-  strip-bom@3.0.0:
-    resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
-    engines: {node: '>=4'}
-
-  strip-json-comments@3.1.1:
-    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
-    engines: {node: '>=8'}
-
-  styled-jsx@5.1.6:
-    resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
-    engines: {node: '>= 12.0.0'}
-    peerDependencies:
-      '@babel/core': '*'
-      babel-plugin-macros: '*'
-      react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
-    peerDependenciesMeta:
-      '@babel/core':
-        optional: true
-      babel-plugin-macros:
-        optional: true
-
-  supports-color@7.2.0:
-    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
-    engines: {node: '>=8'}
-
-  supports-preserve-symlinks-flag@1.0.0:
-    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
-    engines: {node: '>= 0.4'}
-
-  tailwindcss@4.1.18:
-    resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
-    hasBin: true
-
-  tapable@2.3.0:
-    resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
-    engines: {node: '>=6'}
-
-  tinyglobby@0.2.15:
-    resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
-    engines: {node: '>=12.0.0'}
-
-  to-regex-range@5.0.1:
-    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
-    engines: {node: '>=8.0'}
-
-  ts-api-utils@2.4.0:
-    resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==}
-    engines: {node: '>=18.12'}
-    peerDependencies:
-      typescript: '>=4.8.4'
-
-  tsconfig-paths@3.15.0:
-    resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
-
-  tslib@2.8.1:
-    resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
-  type-check@0.4.0:
-    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
-    engines: {node: '>= 0.8.0'}
-
-  typed-array-buffer@1.0.3:
-    resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
-    engines: {node: '>= 0.4'}
-
-  typed-array-byte-length@1.0.3:
-    resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
-    engines: {node: '>= 0.4'}
-
-  typed-array-byte-offset@1.0.4:
-    resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
-    engines: {node: '>= 0.4'}
-
-  typed-array-length@1.0.7:
-    resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
-    engines: {node: '>= 0.4'}
-
-  typescript-eslint@8.53.1:
-    resolution: {integrity: sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==}
-    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    peerDependencies:
-      eslint: ^8.57.0 || ^9.0.0
-      typescript: '>=4.8.4 <6.0.0'
-
-  typescript@5.9.3:
-    resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-
-  unbox-primitive@1.1.0:
-    resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
-    engines: {node: '>= 0.4'}
-
-  undici-types@7.16.0:
-    resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
-
-  unrs-resolver@1.11.1:
-    resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
-
-  update-browserslist-db@1.2.3:
-    resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
-    hasBin: true
-    peerDependencies:
-      browserslist: '>= 4.21.0'
-
-  uri-js@4.4.1:
-    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
-
-  use-debounce@10.1.0:
-    resolution: {integrity: sha512-lu87Za35V3n/MyMoEpD5zJv0k7hCn0p+V/fK2kWD+3k2u3kOCwO593UArbczg1fhfs2rqPEnHpULJ3KmGdDzvg==}
-    engines: {node: '>= 16.0.0'}
-    peerDependencies:
-      react: '*'
-
-  which-boxed-primitive@1.1.1:
-    resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
-    engines: {node: '>= 0.4'}
-
-  which-builtin-type@1.2.1:
-    resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
-    engines: {node: '>= 0.4'}
-
-  which-collection@1.0.2:
-    resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
-    engines: {node: '>= 0.4'}
-
-  which-typed-array@1.1.20:
-    resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==}
-    engines: {node: '>= 0.4'}
-
-  which@2.0.2:
-    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
-    engines: {node: '>= 8'}
-    hasBin: true
-
-  word-wrap@1.2.5:
-    resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
-    engines: {node: '>=0.10.0'}
-
-  yallist@3.1.1:
-    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
-
-  yocto-queue@0.1.0:
-    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
-    engines: {node: '>=10'}
-
-  zod-validation-error@4.0.2:
-    resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
-    engines: {node: '>=18.0.0'}
-    peerDependencies:
-      zod: ^3.25.0 || ^4.0.0
-
-  zod@4.3.5:
-    resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==}
-
-snapshots:
-
-  '@alloc/quick-lru@5.2.0': {}
-
-  '@auth/core@0.41.0':
-    dependencies:
-      '@panva/hkdf': 1.2.1
-      jose: 6.1.3
-      oauth4webapi: 3.8.3
-      preact: 10.24.3
-      preact-render-to-string: 6.5.11(preact@10.24.3)
-
-  '@babel/code-frame@7.28.6':
-    dependencies:
-      '@babel/helper-validator-identifier': 7.28.5
-      js-tokens: 4.0.0
-      picocolors: 1.1.1
-
-  '@babel/compat-data@7.28.6': {}
-
-  '@babel/core@7.28.6':
-    dependencies:
-      '@babel/code-frame': 7.28.6
-      '@babel/generator': 7.28.6
-      '@babel/helper-compilation-targets': 7.28.6
-      '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6)
-      '@babel/helpers': 7.28.6
-      '@babel/parser': 7.28.6
-      '@babel/template': 7.28.6
-      '@babel/traverse': 7.28.6
-      '@babel/types': 7.28.6
-      '@jridgewell/remapping': 2.3.5
-      convert-source-map: 2.0.0
-      debug: 4.4.3
-      gensync: 1.0.0-beta.2
-      json5: 2.2.3
-      semver: 6.3.1
-    transitivePeerDependencies:
-      - supports-color
-
-  '@babel/generator@7.28.6':
-    dependencies:
-      '@babel/parser': 7.28.6
-      '@babel/types': 7.28.6
-      '@jridgewell/gen-mapping': 0.3.13
-      '@jridgewell/trace-mapping': 0.3.31
-      jsesc: 3.1.0
-
-  '@babel/helper-compilation-targets@7.28.6':
-    dependencies:
-      '@babel/compat-data': 7.28.6
-      '@babel/helper-validator-option': 7.27.1
-      browserslist: 4.28.1
-      lru-cache: 5.1.1
-      semver: 6.3.1
-
-  '@babel/helper-globals@7.28.0': {}
-
-  '@babel/helper-module-imports@7.28.6':
-    dependencies:
-      '@babel/traverse': 7.28.6
-      '@babel/types': 7.28.6
-    transitivePeerDependencies:
-      - supports-color
-
-  '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)':
-    dependencies:
-      '@babel/core': 7.28.6
-      '@babel/helper-module-imports': 7.28.6
-      '@babel/helper-validator-identifier': 7.28.5
-      '@babel/traverse': 7.28.6
-    transitivePeerDependencies:
-      - supports-color
-
-  '@babel/helper-string-parser@7.27.1': {}
-
-  '@babel/helper-validator-identifier@7.28.5': {}
-
-  '@babel/helper-validator-option@7.27.1': {}
-
-  '@babel/helpers@7.28.6':
-    dependencies:
-      '@babel/template': 7.28.6
-      '@babel/types': 7.28.6
-
-  '@babel/parser@7.28.6':
-    dependencies:
-      '@babel/types': 7.28.6
-
-  '@babel/template@7.28.6':
-    dependencies:
-      '@babel/code-frame': 7.28.6
-      '@babel/parser': 7.28.6
-      '@babel/types': 7.28.6
-
-  '@babel/traverse@7.28.6':
-    dependencies:
-      '@babel/code-frame': 7.28.6
-      '@babel/generator': 7.28.6
-      '@babel/helper-globals': 7.28.0
-      '@babel/parser': 7.28.6
-      '@babel/template': 7.28.6
-      '@babel/types': 7.28.6
-      debug: 4.4.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@babel/types@7.28.6':
-    dependencies:
-      '@babel/helper-string-parser': 7.27.1
-      '@babel/helper-validator-identifier': 7.28.5
-
-  '@emnapi/core@1.8.1':
-    dependencies:
-      '@emnapi/wasi-threads': 1.1.0
-      tslib: 2.8.1
-    optional: true
-
-  '@emnapi/runtime@1.8.1':
-    dependencies:
-      tslib: 2.8.1
-    optional: true
-
-  '@emnapi/wasi-threads@1.1.0':
-    dependencies:
-      tslib: 2.8.1
-    optional: true
-
-  '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))':
-    dependencies:
-      eslint: 9.39.2(jiti@2.6.1)
-      eslint-visitor-keys: 3.4.3
-
-  '@eslint-community/regexpp@4.12.2': {}
-
-  '@eslint/config-array@0.21.1':
-    dependencies:
-      '@eslint/object-schema': 2.1.7
-      debug: 4.4.3
-      minimatch: 3.1.2
-    transitivePeerDependencies:
-      - supports-color
-
-  '@eslint/config-helpers@0.4.2':
-    dependencies:
-      '@eslint/core': 0.17.0
-
-  '@eslint/core@0.17.0':
-    dependencies:
-      '@types/json-schema': 7.0.15
-
-  '@eslint/eslintrc@3.3.3':
-    dependencies:
-      ajv: 6.12.6
-      debug: 4.4.3
-      espree: 10.4.0
-      globals: 14.0.0
-      ignore: 5.3.2
-      import-fresh: 3.3.1
-      js-yaml: 4.1.1
-      minimatch: 3.1.2
-      strip-json-comments: 3.1.1
-    transitivePeerDependencies:
-      - supports-color
-
-  '@eslint/js@9.39.2': {}
-
-  '@eslint/object-schema@2.1.7': {}
-
-  '@eslint/plugin-kit@0.4.1':
-    dependencies:
-      '@eslint/core': 0.17.0
-      levn: 0.4.1
-
-  '@heroicons/react@2.2.0(react@19.2.3)':
-    dependencies:
-      react: 19.2.3
-
-  '@humanfs/core@0.19.1': {}
-
-  '@humanfs/node@0.16.7':
-    dependencies:
-      '@humanfs/core': 0.19.1
-      '@humanwhocodes/retry': 0.4.3
-
-  '@humanwhocodes/module-importer@1.0.1': {}
-
-  '@humanwhocodes/retry@0.4.3': {}
-
-  '@img/colour@1.0.0':
-    optional: true
-
-  '@img/sharp-darwin-arm64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-darwin-arm64': 1.2.4
-    optional: true
-
-  '@img/sharp-darwin-x64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-darwin-x64': 1.2.4
-    optional: true
-
-  '@img/sharp-libvips-darwin-arm64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-darwin-x64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linux-arm64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linux-arm@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linux-ppc64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linux-riscv64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linux-s390x@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linux-x64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
-    optional: true
-
-  '@img/sharp-libvips-linuxmusl-x64@1.2.4':
-    optional: true
-
-  '@img/sharp-linux-arm64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-arm64': 1.2.4
-    optional: true
-
-  '@img/sharp-linux-arm@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-arm': 1.2.4
-    optional: true
-
-  '@img/sharp-linux-ppc64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-ppc64': 1.2.4
-    optional: true
-
-  '@img/sharp-linux-riscv64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-riscv64': 1.2.4
-    optional: true
-
-  '@img/sharp-linux-s390x@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-s390x': 1.2.4
-    optional: true
-
-  '@img/sharp-linux-x64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linux-x64': 1.2.4
-    optional: true
-
-  '@img/sharp-linuxmusl-arm64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
-    optional: true
-
-  '@img/sharp-linuxmusl-x64@0.34.5':
-    optionalDependencies:
-      '@img/sharp-libvips-linuxmusl-x64': 1.2.4
-    optional: true
-
-  '@img/sharp-wasm32@0.34.5':
-    dependencies:
-      '@emnapi/runtime': 1.8.1
-    optional: true
-
-  '@img/sharp-win32-arm64@0.34.5':
-    optional: true
-
-  '@img/sharp-win32-ia32@0.34.5':
-    optional: true
-
-  '@img/sharp-win32-x64@0.34.5':
-    optional: true
-
-  '@jridgewell/gen-mapping@0.3.13':
-    dependencies:
-      '@jridgewell/sourcemap-codec': 1.5.5
-      '@jridgewell/trace-mapping': 0.3.31
-
-  '@jridgewell/remapping@2.3.5':
-    dependencies:
-      '@jridgewell/gen-mapping': 0.3.13
-      '@jridgewell/trace-mapping': 0.3.31
-
-  '@jridgewell/resolve-uri@3.1.2': {}
-
-  '@jridgewell/sourcemap-codec@1.5.5': {}
-
-  '@jridgewell/trace-mapping@0.3.31':
-    dependencies:
-      '@jridgewell/resolve-uri': 3.1.2
-      '@jridgewell/sourcemap-codec': 1.5.5
-
-  '@napi-rs/wasm-runtime@0.2.12':
-    dependencies:
-      '@emnapi/core': 1.8.1
-      '@emnapi/runtime': 1.8.1
-      '@tybys/wasm-util': 0.10.1
-    optional: true
-
-  '@next/env@15.5.9': {}
-
-  '@next/eslint-plugin-next@16.1.3':
-    dependencies:
-      fast-glob: 3.3.1
-
-  '@next/swc-darwin-arm64@15.5.7':
-    optional: true
-
-  '@next/swc-darwin-x64@15.5.7':
-    optional: true
-
-  '@next/swc-linux-arm64-gnu@15.5.7':
-    optional: true
-
-  '@next/swc-linux-arm64-musl@15.5.7':
-    optional: true
-
-  '@next/swc-linux-x64-gnu@15.5.7':
-    optional: true
-
-  '@next/swc-linux-x64-musl@15.5.7':
-    optional: true
-
-  '@next/swc-win32-arm64-msvc@15.5.7':
-    optional: true
-
-  '@next/swc-win32-x64-msvc@15.5.7':
-    optional: true
-
-  '@nodelib/fs.scandir@2.1.5':
-    dependencies:
-      '@nodelib/fs.stat': 2.0.5
-      run-parallel: 1.2.0
-
-  '@nodelib/fs.stat@2.0.5': {}
-
-  '@nodelib/fs.walk@1.2.8':
-    dependencies:
-      '@nodelib/fs.scandir': 2.1.5
-      fastq: 1.20.1
-
-  '@nolyfill/is-core-module@1.0.39': {}
-
-  '@panva/hkdf@1.2.1': {}
-
-  '@rtsao/scc@1.1.0': {}
-
-  '@swc/helpers@0.5.15':
-    dependencies:
-      tslib: 2.8.1
-
-  '@tailwindcss/forms@0.5.11(tailwindcss@4.1.18)':
-    dependencies:
-      mini-svg-data-uri: 1.4.4
-      tailwindcss: 4.1.18
-
-  '@tailwindcss/node@4.1.18':
-    dependencies:
-      '@jridgewell/remapping': 2.3.5
-      enhanced-resolve: 5.18.4
-      jiti: 2.6.1
-      lightningcss: 1.30.2
-      magic-string: 0.30.21
-      source-map-js: 1.2.1
-      tailwindcss: 4.1.18
-
-  '@tailwindcss/oxide-android-arm64@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-darwin-arm64@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-darwin-x64@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-freebsd-x64@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-linux-x64-musl@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-wasm32-wasi@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
-    optional: true
-
-  '@tailwindcss/oxide@4.1.18':
-    optionalDependencies:
-      '@tailwindcss/oxide-android-arm64': 4.1.18
-      '@tailwindcss/oxide-darwin-arm64': 4.1.18
-      '@tailwindcss/oxide-darwin-x64': 4.1.18
-      '@tailwindcss/oxide-freebsd-x64': 4.1.18
-      '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18
-      '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18
-      '@tailwindcss/oxide-linux-arm64-musl': 4.1.18
-      '@tailwindcss/oxide-linux-x64-gnu': 4.1.18
-      '@tailwindcss/oxide-linux-x64-musl': 4.1.18
-      '@tailwindcss/oxide-wasm32-wasi': 4.1.18
-      '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
-      '@tailwindcss/oxide-win32-x64-msvc': 4.1.18
-
-  '@tailwindcss/postcss@4.1.18':
-    dependencies:
-      '@alloc/quick-lru': 5.2.0
-      '@tailwindcss/node': 4.1.18
-      '@tailwindcss/oxide': 4.1.18
-      postcss: 8.5.6
-      tailwindcss: 4.1.18
-
-  '@tybys/wasm-util@0.10.1':
-    dependencies:
-      tslib: 2.8.1
-    optional: true
-
-  '@types/bcrypt@6.0.0':
-    dependencies:
-      '@types/node': 25.0.9
-
-  '@types/estree@1.0.8': {}
-
-  '@types/json-schema@7.0.15': {}
-
-  '@types/json5@0.0.29': {}
-
-  '@types/node@25.0.9':
-    dependencies:
-      undici-types: 7.16.0
-
-  '@types/react-dom@19.2.3(@types/react@19.2.8)':
-    dependencies:
-      '@types/react': 19.2.8
-
-  '@types/react@19.2.8':
-    dependencies:
-      csstype: 3.2.3
-
-  '@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
-    dependencies:
-      '@eslint-community/regexpp': 4.12.2
-      '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      '@typescript-eslint/scope-manager': 8.53.1
-      '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      '@typescript-eslint/visitor-keys': 8.53.1
-      eslint: 9.39.2(jiti@2.6.1)
-      ignore: 7.0.5
-      natural-compare: 1.4.0
-      ts-api-utils: 2.4.0(typescript@5.9.3)
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
-    dependencies:
-      '@typescript-eslint/scope-manager': 8.53.1
-      '@typescript-eslint/types': 8.53.1
-      '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3)
-      '@typescript-eslint/visitor-keys': 8.53.1
-      debug: 4.4.3
-      eslint: 9.39.2(jiti@2.6.1)
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@typescript-eslint/project-service@8.53.1(typescript@5.9.3)':
-    dependencies:
-      '@typescript-eslint/tsconfig-utils': 8.53.1(typescript@5.9.3)
-      '@typescript-eslint/types': 8.53.1
-      debug: 4.4.3
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@typescript-eslint/scope-manager@8.53.1':
-    dependencies:
-      '@typescript-eslint/types': 8.53.1
-      '@typescript-eslint/visitor-keys': 8.53.1
-
-  '@typescript-eslint/tsconfig-utils@8.53.1(typescript@5.9.3)':
-    dependencies:
-      typescript: 5.9.3
-
-  '@typescript-eslint/type-utils@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
-    dependencies:
-      '@typescript-eslint/types': 8.53.1
-      '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3)
-      '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      debug: 4.4.3
-      eslint: 9.39.2(jiti@2.6.1)
-      ts-api-utils: 2.4.0(typescript@5.9.3)
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@typescript-eslint/types@8.53.1': {}
-
-  '@typescript-eslint/typescript-estree@8.53.1(typescript@5.9.3)':
-    dependencies:
-      '@typescript-eslint/project-service': 8.53.1(typescript@5.9.3)
-      '@typescript-eslint/tsconfig-utils': 8.53.1(typescript@5.9.3)
-      '@typescript-eslint/types': 8.53.1
-      '@typescript-eslint/visitor-keys': 8.53.1
-      debug: 4.4.3
-      minimatch: 9.0.5
-      semver: 7.7.3
-      tinyglobby: 0.2.15
-      ts-api-utils: 2.4.0(typescript@5.9.3)
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@typescript-eslint/utils@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
-    dependencies:
-      '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
-      '@typescript-eslint/scope-manager': 8.53.1
-      '@typescript-eslint/types': 8.53.1
-      '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3)
-      eslint: 9.39.2(jiti@2.6.1)
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  '@typescript-eslint/visitor-keys@8.53.1':
-    dependencies:
-      '@typescript-eslint/types': 8.53.1
-      eslint-visitor-keys: 4.2.1
-
-  '@unrs/resolver-binding-android-arm-eabi@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-android-arm64@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-darwin-arm64@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-darwin-x64@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-freebsd-x64@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-arm64-gnu@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-linux-x64-musl@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-wasm32-wasi@1.11.1':
-    dependencies:
-      '@napi-rs/wasm-runtime': 0.2.12
-    optional: true
-
-  '@unrs/resolver-binding-win32-arm64-msvc@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-win32-ia32-msvc@1.11.1':
-    optional: true
-
-  '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
-    optional: true
-
-  acorn-jsx@5.3.2(acorn@8.15.0):
-    dependencies:
-      acorn: 8.15.0
-
-  acorn@8.15.0: {}
-
-  ajv@6.12.6:
-    dependencies:
-      fast-deep-equal: 3.1.3
-      fast-json-stable-stringify: 2.1.0
-      json-schema-traverse: 0.4.1
-      uri-js: 4.4.1
-
-  ansi-styles@4.3.0:
-    dependencies:
-      color-convert: 2.0.1
-
-  argparse@2.0.1: {}
-
-  aria-query@5.3.2: {}
-
-  array-buffer-byte-length@1.0.2:
-    dependencies:
-      call-bound: 1.0.4
-      is-array-buffer: 3.0.5
-
-  array-includes@3.1.9:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-object-atoms: 1.1.1
-      get-intrinsic: 1.3.0
-      is-string: 1.1.1
-      math-intrinsics: 1.1.0
-
-  array.prototype.findlast@1.2.5:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-      es-shim-unscopables: 1.1.0
-
-  array.prototype.findlastindex@1.2.6:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-      es-shim-unscopables: 1.1.0
-
-  array.prototype.flat@1.3.3:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-shim-unscopables: 1.1.0
-
-  array.prototype.flatmap@1.3.3:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-shim-unscopables: 1.1.0
-
-  array.prototype.tosorted@1.1.4:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      es-shim-unscopables: 1.1.0
-
-  arraybuffer.prototype.slice@1.0.4:
-    dependencies:
-      array-buffer-byte-length: 1.0.2
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      get-intrinsic: 1.3.0
-      is-array-buffer: 3.0.5
-
-  ast-types-flow@0.0.8: {}
-
-  async-function@1.0.0: {}
-
-  autoprefixer@10.4.23(postcss@8.5.6):
-    dependencies:
-      browserslist: 4.28.1
-      caniuse-lite: 1.0.30001765
-      fraction.js: 5.3.4
-      picocolors: 1.1.1
-      postcss: 8.5.6
-      postcss-value-parser: 4.2.0
-
-  available-typed-arrays@1.0.7:
-    dependencies:
-      possible-typed-array-names: 1.1.0
-
-  axe-core@4.11.1: {}
-
-  axobject-query@4.1.0: {}
-
-  balanced-match@1.0.2: {}
-
-  baseline-browser-mapping@2.9.15: {}
-
-  bcrypt@6.0.0:
-    dependencies:
-      node-addon-api: 8.5.0
-      node-gyp-build: 4.8.4
-
-  bcryptjs@3.0.3: {}
-
-  brace-expansion@1.1.12:
-    dependencies:
-      balanced-match: 1.0.2
-      concat-map: 0.0.1
-
-  brace-expansion@2.0.2:
-    dependencies:
-      balanced-match: 1.0.2
-
-  braces@3.0.3:
-    dependencies:
-      fill-range: 7.1.1
-
-  browserslist@4.28.1:
-    dependencies:
-      baseline-browser-mapping: 2.9.15
-      caniuse-lite: 1.0.30001765
-      electron-to-chromium: 1.5.267
-      node-releases: 2.0.27
-      update-browserslist-db: 1.2.3(browserslist@4.28.1)
-
-  call-bind-apply-helpers@1.0.2:
-    dependencies:
-      es-errors: 1.3.0
-      function-bind: 1.1.2
-
-  call-bind@1.0.8:
-    dependencies:
-      call-bind-apply-helpers: 1.0.2
-      es-define-property: 1.0.1
-      get-intrinsic: 1.3.0
-      set-function-length: 1.2.2
-
-  call-bound@1.0.4:
-    dependencies:
-      call-bind-apply-helpers: 1.0.2
-      get-intrinsic: 1.3.0
-
-  callsites@3.1.0: {}
-
-  caniuse-lite@1.0.30001765: {}
-
-  chalk@4.1.2:
-    dependencies:
-      ansi-styles: 4.3.0
-      supports-color: 7.2.0
-
-  client-only@0.0.1: {}
-
-  clsx@2.1.1: {}
-
-  color-convert@2.0.1:
-    dependencies:
-      color-name: 1.1.4
-
-  color-name@1.1.4: {}
-
-  concat-map@0.0.1: {}
-
-  convert-source-map@2.0.0: {}
-
-  cross-spawn@7.0.6:
-    dependencies:
-      path-key: 3.1.1
-      shebang-command: 2.0.0
-      which: 2.0.2
-
-  csstype@3.2.3: {}
-
-  damerau-levenshtein@1.0.8: {}
-
-  data-view-buffer@1.0.2:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      is-data-view: 1.0.2
-
-  data-view-byte-length@1.0.2:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      is-data-view: 1.0.2
-
-  data-view-byte-offset@1.0.1:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      is-data-view: 1.0.2
-
-  debug@3.2.7:
-    dependencies:
-      ms: 2.1.3
-
-  debug@4.4.3:
-    dependencies:
-      ms: 2.1.3
-
-  deep-is@0.1.4: {}
-
-  define-data-property@1.1.4:
-    dependencies:
-      es-define-property: 1.0.1
-      es-errors: 1.3.0
-      gopd: 1.2.0
-
-  define-properties@1.2.1:
-    dependencies:
-      define-data-property: 1.1.4
-      has-property-descriptors: 1.0.2
-      object-keys: 1.1.1
-
-  detect-libc@2.1.2: {}
-
-  doctrine@2.1.0:
-    dependencies:
-      esutils: 2.0.3
-
-  dunder-proto@1.0.1:
-    dependencies:
-      call-bind-apply-helpers: 1.0.2
-      es-errors: 1.3.0
-      gopd: 1.2.0
-
-  electron-to-chromium@1.5.267: {}
-
-  emoji-regex@9.2.2: {}
-
-  enhanced-resolve@5.18.4:
-    dependencies:
-      graceful-fs: 4.2.11
-      tapable: 2.3.0
-
-  es-abstract@1.24.1:
-    dependencies:
-      array-buffer-byte-length: 1.0.2
-      arraybuffer.prototype.slice: 1.0.4
-      available-typed-arrays: 1.0.7
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      data-view-buffer: 1.0.2
-      data-view-byte-length: 1.0.2
-      data-view-byte-offset: 1.0.1
-      es-define-property: 1.0.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-      es-set-tostringtag: 2.1.0
-      es-to-primitive: 1.3.0
-      function.prototype.name: 1.1.8
-      get-intrinsic: 1.3.0
-      get-proto: 1.0.1
-      get-symbol-description: 1.1.0
-      globalthis: 1.0.4
-      gopd: 1.2.0
-      has-property-descriptors: 1.0.2
-      has-proto: 1.2.0
-      has-symbols: 1.1.0
-      hasown: 2.0.2
-      internal-slot: 1.1.0
-      is-array-buffer: 3.0.5
-      is-callable: 1.2.7
-      is-data-view: 1.0.2
-      is-negative-zero: 2.0.3
-      is-regex: 1.2.1
-      is-set: 2.0.3
-      is-shared-array-buffer: 1.0.4
-      is-string: 1.1.1
-      is-typed-array: 1.1.15
-      is-weakref: 1.1.1
-      math-intrinsics: 1.1.0
-      object-inspect: 1.13.4
-      object-keys: 1.1.1
-      object.assign: 4.1.7
-      own-keys: 1.0.1
-      regexp.prototype.flags: 1.5.4
-      safe-array-concat: 1.1.3
-      safe-push-apply: 1.0.0
-      safe-regex-test: 1.1.0
-      set-proto: 1.0.0
-      stop-iteration-iterator: 1.1.0
-      string.prototype.trim: 1.2.10
-      string.prototype.trimend: 1.0.9
-      string.prototype.trimstart: 1.0.8
-      typed-array-buffer: 1.0.3
-      typed-array-byte-length: 1.0.3
-      typed-array-byte-offset: 1.0.4
-      typed-array-length: 1.0.7
-      unbox-primitive: 1.1.0
-      which-typed-array: 1.1.20
-
-  es-define-property@1.0.1: {}
-
-  es-errors@1.3.0: {}
-
-  es-iterator-helpers@1.2.2:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      es-set-tostringtag: 2.1.0
-      function-bind: 1.1.2
-      get-intrinsic: 1.3.0
-      globalthis: 1.0.4
-      gopd: 1.2.0
-      has-property-descriptors: 1.0.2
-      has-proto: 1.2.0
-      has-symbols: 1.1.0
-      internal-slot: 1.1.0
-      iterator.prototype: 1.1.5
-      safe-array-concat: 1.1.3
-
-  es-object-atoms@1.1.1:
-    dependencies:
-      es-errors: 1.3.0
-
-  es-set-tostringtag@2.1.0:
-    dependencies:
-      es-errors: 1.3.0
-      get-intrinsic: 1.3.0
-      has-tostringtag: 1.0.2
-      hasown: 2.0.2
-
-  es-shim-unscopables@1.1.0:
-    dependencies:
-      hasown: 2.0.2
-
-  es-to-primitive@1.3.0:
-    dependencies:
-      is-callable: 1.2.7
-      is-date-object: 1.1.0
-      is-symbol: 1.1.1
-
-  escalade@3.2.0: {}
-
-  escape-string-regexp@4.0.0: {}
-
-  eslint-config-next@16.1.3(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
-    dependencies:
-      '@next/eslint-plugin-next': 16.1.3
-      eslint: 9.39.2(jiti@2.6.1)
-      eslint-import-resolver-node: 0.3.9
-      eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
-      eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
-      eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
-      eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
-      eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1))
-      globals: 16.4.0
-      typescript-eslint: 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-    optionalDependencies:
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - '@typescript-eslint/parser'
-      - eslint-import-resolver-webpack
-      - eslint-plugin-import-x
-      - supports-color
-
-  eslint-import-resolver-node@0.3.9:
-    dependencies:
-      debug: 3.2.7
-      is-core-module: 2.16.1
-      resolve: 1.22.11
-    transitivePeerDependencies:
-      - supports-color
-
-  eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
-    dependencies:
-      '@nolyfill/is-core-module': 1.0.39
-      debug: 4.4.3
-      eslint: 9.39.2(jiti@2.6.1)
-      get-tsconfig: 4.13.0
-      is-bun-module: 2.0.0
-      stable-hash: 0.0.5
-      tinyglobby: 0.2.15
-      unrs-resolver: 1.11.1
-    optionalDependencies:
-      eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
-    transitivePeerDependencies:
-      - supports-color
-
-  eslint-module-utils@2.12.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
-    dependencies:
-      debug: 3.2.7
-    optionalDependencies:
-      '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      eslint: 9.39.2(jiti@2.6.1)
-      eslint-import-resolver-node: 0.3.9
-      eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
-    transitivePeerDependencies:
-      - supports-color
-
-  eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
-    dependencies:
-      '@rtsao/scc': 1.1.0
-      array-includes: 3.1.9
-      array.prototype.findlastindex: 1.2.6
-      array.prototype.flat: 1.3.3
-      array.prototype.flatmap: 1.3.3
-      debug: 3.2.7
-      doctrine: 2.1.0
-      eslint: 9.39.2(jiti@2.6.1)
-      eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
-      hasown: 2.0.2
-      is-core-module: 2.16.1
-      is-glob: 4.0.3
-      minimatch: 3.1.2
-      object.fromentries: 2.0.8
-      object.groupby: 1.0.3
-      object.values: 1.2.1
-      semver: 6.3.1
-      string.prototype.trimend: 1.0.9
-      tsconfig-paths: 3.15.0
-    optionalDependencies:
-      '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-    transitivePeerDependencies:
-      - eslint-import-resolver-typescript
-      - eslint-import-resolver-webpack
-      - supports-color
-
-  eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.2(jiti@2.6.1)):
-    dependencies:
-      aria-query: 5.3.2
-      array-includes: 3.1.9
-      array.prototype.flatmap: 1.3.3
-      ast-types-flow: 0.0.8
-      axe-core: 4.11.1
-      axobject-query: 4.1.0
-      damerau-levenshtein: 1.0.8
-      emoji-regex: 9.2.2
-      eslint: 9.39.2(jiti@2.6.1)
-      hasown: 2.0.2
-      jsx-ast-utils: 3.3.5
-      language-tags: 1.0.9
-      minimatch: 3.1.2
-      object.fromentries: 2.0.8
-      safe-regex-test: 1.1.0
-      string.prototype.includes: 2.0.1
-
-  eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)):
-    dependencies:
-      '@babel/core': 7.28.6
-      '@babel/parser': 7.28.6
-      eslint: 9.39.2(jiti@2.6.1)
-      hermes-parser: 0.25.1
-      zod: 4.3.5
-      zod-validation-error: 4.0.2(zod@4.3.5)
-    transitivePeerDependencies:
-      - supports-color
-
-  eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)):
-    dependencies:
-      array-includes: 3.1.9
-      array.prototype.findlast: 1.2.5
-      array.prototype.flatmap: 1.3.3
-      array.prototype.tosorted: 1.1.4
-      doctrine: 2.1.0
-      es-iterator-helpers: 1.2.2
-      eslint: 9.39.2(jiti@2.6.1)
-      estraverse: 5.3.0
-      hasown: 2.0.2
-      jsx-ast-utils: 3.3.5
-      minimatch: 3.1.2
-      object.entries: 1.1.9
-      object.fromentries: 2.0.8
-      object.values: 1.2.1
-      prop-types: 15.8.1
-      resolve: 2.0.0-next.5
-      semver: 6.3.1
-      string.prototype.matchall: 4.0.12
-      string.prototype.repeat: 1.0.0
-
-  eslint-scope@8.4.0:
-    dependencies:
-      esrecurse: 4.3.0
-      estraverse: 5.3.0
-
-  eslint-visitor-keys@3.4.3: {}
-
-  eslint-visitor-keys@4.2.1: {}
-
-  eslint@9.39.2(jiti@2.6.1):
-    dependencies:
-      '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
-      '@eslint-community/regexpp': 4.12.2
-      '@eslint/config-array': 0.21.1
-      '@eslint/config-helpers': 0.4.2
-      '@eslint/core': 0.17.0
-      '@eslint/eslintrc': 3.3.3
-      '@eslint/js': 9.39.2
-      '@eslint/plugin-kit': 0.4.1
-      '@humanfs/node': 0.16.7
-      '@humanwhocodes/module-importer': 1.0.1
-      '@humanwhocodes/retry': 0.4.3
-      '@types/estree': 1.0.8
-      ajv: 6.12.6
-      chalk: 4.1.2
-      cross-spawn: 7.0.6
-      debug: 4.4.3
-      escape-string-regexp: 4.0.0
-      eslint-scope: 8.4.0
-      eslint-visitor-keys: 4.2.1
-      espree: 10.4.0
-      esquery: 1.7.0
-      esutils: 2.0.3
-      fast-deep-equal: 3.1.3
-      file-entry-cache: 8.0.0
-      find-up: 5.0.0
-      glob-parent: 6.0.2
-      ignore: 5.3.2
-      imurmurhash: 0.1.4
-      is-glob: 4.0.3
-      json-stable-stringify-without-jsonify: 1.0.1
-      lodash.merge: 4.6.2
-      minimatch: 3.1.2
-      natural-compare: 1.4.0
-      optionator: 0.9.4
-    optionalDependencies:
-      jiti: 2.6.1
-    transitivePeerDependencies:
-      - supports-color
-
-  espree@10.4.0:
-    dependencies:
-      acorn: 8.15.0
-      acorn-jsx: 5.3.2(acorn@8.15.0)
-      eslint-visitor-keys: 4.2.1
-
-  esquery@1.7.0:
-    dependencies:
-      estraverse: 5.3.0
-
-  esrecurse@4.3.0:
-    dependencies:
-      estraverse: 5.3.0
-
-  estraverse@5.3.0: {}
-
-  esutils@2.0.3: {}
-
-  fast-deep-equal@3.1.3: {}
-
-  fast-glob@3.3.1:
-    dependencies:
-      '@nodelib/fs.stat': 2.0.5
-      '@nodelib/fs.walk': 1.2.8
-      glob-parent: 5.1.2
-      merge2: 1.4.1
-      micromatch: 4.0.8
-
-  fast-json-stable-stringify@2.1.0: {}
-
-  fast-levenshtein@2.0.6: {}
-
-  fastq@1.20.1:
-    dependencies:
-      reusify: 1.1.0
-
-  fdir@6.5.0(picomatch@4.0.3):
-    optionalDependencies:
-      picomatch: 4.0.3
-
-  file-entry-cache@8.0.0:
-    dependencies:
-      flat-cache: 4.0.1
-
-  fill-range@7.1.1:
-    dependencies:
-      to-regex-range: 5.0.1
-
-  find-up@5.0.0:
-    dependencies:
-      locate-path: 6.0.0
-      path-exists: 4.0.0
-
-  flat-cache@4.0.1:
-    dependencies:
-      flatted: 3.3.3
-      keyv: 4.5.4
-
-  flatted@3.3.3: {}
-
-  for-each@0.3.5:
-    dependencies:
-      is-callable: 1.2.7
-
-  fraction.js@5.3.4: {}
-
-  function-bind@1.1.2: {}
-
-  function.prototype.name@1.1.8:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      functions-have-names: 1.2.3
-      hasown: 2.0.2
-      is-callable: 1.2.7
-
-  functions-have-names@1.2.3: {}
-
-  generator-function@2.0.1: {}
-
-  gensync@1.0.0-beta.2: {}
-
-  get-intrinsic@1.3.0:
-    dependencies:
-      call-bind-apply-helpers: 1.0.2
-      es-define-property: 1.0.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-      function-bind: 1.1.2
-      get-proto: 1.0.1
-      gopd: 1.2.0
-      has-symbols: 1.1.0
-      hasown: 2.0.2
-      math-intrinsics: 1.1.0
-
-  get-proto@1.0.1:
-    dependencies:
-      dunder-proto: 1.0.1
-      es-object-atoms: 1.1.1
-
-  get-symbol-description@1.1.0:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      get-intrinsic: 1.3.0
-
-  get-tsconfig@4.13.0:
-    dependencies:
-      resolve-pkg-maps: 1.0.0
-
-  glob-parent@5.1.2:
-    dependencies:
-      is-glob: 4.0.3
-
-  glob-parent@6.0.2:
-    dependencies:
-      is-glob: 4.0.3
-
-  globals@14.0.0: {}
-
-  globals@16.4.0: {}
-
-  globalthis@1.0.4:
-    dependencies:
-      define-properties: 1.2.1
-      gopd: 1.2.0
-
-  gopd@1.2.0: {}
-
-  graceful-fs@4.2.11: {}
-
-  has-bigints@1.1.0: {}
-
-  has-flag@4.0.0: {}
-
-  has-property-descriptors@1.0.2:
-    dependencies:
-      es-define-property: 1.0.1
-
-  has-proto@1.2.0:
-    dependencies:
-      dunder-proto: 1.0.1
-
-  has-symbols@1.1.0: {}
-
-  has-tostringtag@1.0.2:
-    dependencies:
-      has-symbols: 1.1.0
-
-  hasown@2.0.2:
-    dependencies:
-      function-bind: 1.1.2
-
-  hermes-estree@0.25.1: {}
-
-  hermes-parser@0.25.1:
-    dependencies:
-      hermes-estree: 0.25.1
-
-  ignore@5.3.2: {}
-
-  ignore@7.0.5: {}
-
-  import-fresh@3.3.1:
-    dependencies:
-      parent-module: 1.0.1
-      resolve-from: 4.0.0
-
-  imurmurhash@0.1.4: {}
-
-  internal-slot@1.1.0:
-    dependencies:
-      es-errors: 1.3.0
-      hasown: 2.0.2
-      side-channel: 1.1.0
-
-  is-array-buffer@3.0.5:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      get-intrinsic: 1.3.0
-
-  is-async-function@2.1.1:
-    dependencies:
-      async-function: 1.0.0
-      call-bound: 1.0.4
-      get-proto: 1.0.1
-      has-tostringtag: 1.0.2
-      safe-regex-test: 1.1.0
-
-  is-bigint@1.1.0:
-    dependencies:
-      has-bigints: 1.1.0
-
-  is-boolean-object@1.2.2:
-    dependencies:
-      call-bound: 1.0.4
-      has-tostringtag: 1.0.2
-
-  is-bun-module@2.0.0:
-    dependencies:
-      semver: 7.7.3
-
-  is-callable@1.2.7: {}
-
-  is-core-module@2.16.1:
-    dependencies:
-      hasown: 2.0.2
-
-  is-data-view@1.0.2:
-    dependencies:
-      call-bound: 1.0.4
-      get-intrinsic: 1.3.0
-      is-typed-array: 1.1.15
-
-  is-date-object@1.1.0:
-    dependencies:
-      call-bound: 1.0.4
-      has-tostringtag: 1.0.2
-
-  is-extglob@2.1.1: {}
-
-  is-finalizationregistry@1.1.1:
-    dependencies:
-      call-bound: 1.0.4
-
-  is-generator-function@1.1.2:
-    dependencies:
-      call-bound: 1.0.4
-      generator-function: 2.0.1
-      get-proto: 1.0.1
-      has-tostringtag: 1.0.2
-      safe-regex-test: 1.1.0
-
-  is-glob@4.0.3:
-    dependencies:
-      is-extglob: 2.1.1
-
-  is-map@2.0.3: {}
-
-  is-negative-zero@2.0.3: {}
-
-  is-number-object@1.1.1:
-    dependencies:
-      call-bound: 1.0.4
-      has-tostringtag: 1.0.2
-
-  is-number@7.0.0: {}
-
-  is-regex@1.2.1:
-    dependencies:
-      call-bound: 1.0.4
-      gopd: 1.2.0
-      has-tostringtag: 1.0.2
-      hasown: 2.0.2
-
-  is-set@2.0.3: {}
-
-  is-shared-array-buffer@1.0.4:
-    dependencies:
-      call-bound: 1.0.4
-
-  is-string@1.1.1:
-    dependencies:
-      call-bound: 1.0.4
-      has-tostringtag: 1.0.2
-
-  is-symbol@1.1.1:
-    dependencies:
-      call-bound: 1.0.4
-      has-symbols: 1.1.0
-      safe-regex-test: 1.1.0
-
-  is-typed-array@1.1.15:
-    dependencies:
-      which-typed-array: 1.1.20
-
-  is-weakmap@2.0.2: {}
-
-  is-weakref@1.1.1:
-    dependencies:
-      call-bound: 1.0.4
-
-  is-weakset@2.0.4:
-    dependencies:
-      call-bound: 1.0.4
-      get-intrinsic: 1.3.0
-
-  isarray@2.0.5: {}
-
-  isexe@2.0.0: {}
-
-  iterator.prototype@1.1.5:
-    dependencies:
-      define-data-property: 1.1.4
-      es-object-atoms: 1.1.1
-      get-intrinsic: 1.3.0
-      get-proto: 1.0.1
-      has-symbols: 1.1.0
-      set-function-name: 2.0.2
-
-  jiti@2.6.1: {}
-
-  jose@6.1.3: {}
-
-  js-tokens@4.0.0: {}
-
-  js-yaml@4.1.1:
-    dependencies:
-      argparse: 2.0.1
-
-  jsesc@3.1.0: {}
-
-  json-buffer@3.0.1: {}
-
-  json-schema-traverse@0.4.1: {}
-
-  json-stable-stringify-without-jsonify@1.0.1: {}
-
-  json5@1.0.2:
-    dependencies:
-      minimist: 1.2.8
-
-  json5@2.2.3: {}
-
-  jsx-ast-utils@3.3.5:
-    dependencies:
-      array-includes: 3.1.9
-      array.prototype.flat: 1.3.3
-      object.assign: 4.1.7
-      object.values: 1.2.1
-
-  keyv@4.5.4:
-    dependencies:
-      json-buffer: 3.0.1
-
-  language-subtag-registry@0.3.23: {}
-
-  language-tags@1.0.9:
-    dependencies:
-      language-subtag-registry: 0.3.23
-
-  levn@0.4.1:
-    dependencies:
-      prelude-ls: 1.2.1
-      type-check: 0.4.0
-
-  lightningcss-android-arm64@1.30.2:
-    optional: true
-
-  lightningcss-darwin-arm64@1.30.2:
-    optional: true
-
-  lightningcss-darwin-x64@1.30.2:
-    optional: true
-
-  lightningcss-freebsd-x64@1.30.2:
-    optional: true
-
-  lightningcss-linux-arm-gnueabihf@1.30.2:
-    optional: true
-
-  lightningcss-linux-arm64-gnu@1.30.2:
-    optional: true
-
-  lightningcss-linux-arm64-musl@1.30.2:
-    optional: true
-
-  lightningcss-linux-x64-gnu@1.30.2:
-    optional: true
-
-  lightningcss-linux-x64-musl@1.30.2:
-    optional: true
-
-  lightningcss-win32-arm64-msvc@1.30.2:
-    optional: true
-
-  lightningcss-win32-x64-msvc@1.30.2:
-    optional: true
-
-  lightningcss@1.30.2:
-    dependencies:
-      detect-libc: 2.1.2
-    optionalDependencies:
-      lightningcss-android-arm64: 1.30.2
-      lightningcss-darwin-arm64: 1.30.2
-      lightningcss-darwin-x64: 1.30.2
-      lightningcss-freebsd-x64: 1.30.2
-      lightningcss-linux-arm-gnueabihf: 1.30.2
-      lightningcss-linux-arm64-gnu: 1.30.2
-      lightningcss-linux-arm64-musl: 1.30.2
-      lightningcss-linux-x64-gnu: 1.30.2
-      lightningcss-linux-x64-musl: 1.30.2
-      lightningcss-win32-arm64-msvc: 1.30.2
-      lightningcss-win32-x64-msvc: 1.30.2
-
-  locate-path@6.0.0:
-    dependencies:
-      p-locate: 5.0.0
-
-  lodash.merge@4.6.2: {}
-
-  loose-envify@1.4.0:
-    dependencies:
-      js-tokens: 4.0.0
-
-  lru-cache@5.1.1:
-    dependencies:
-      yallist: 3.1.1
-
-  magic-string@0.30.21:
-    dependencies:
-      '@jridgewell/sourcemap-codec': 1.5.5
-
-  math-intrinsics@1.1.0: {}
-
-  merge2@1.4.1: {}
-
-  micromatch@4.0.8:
-    dependencies:
-      braces: 3.0.3
-      picomatch: 2.3.1
-
-  mini-svg-data-uri@1.4.4: {}
-
-  minimatch@3.1.2:
-    dependencies:
-      brace-expansion: 1.1.12
-
-  minimatch@9.0.5:
-    dependencies:
-      brace-expansion: 2.0.2
-
-  minimist@1.2.8: {}
-
-  ms@2.1.3: {}
-
-  nanoid@3.3.11: {}
-
-  napi-postinstall@0.3.4: {}
-
-  natural-compare@1.4.0: {}
-
-  next-auth@5.0.0-beta.30(next@15.5.9(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3):
-    dependencies:
-      '@auth/core': 0.41.0
-      next: 15.5.9(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
-      react: 19.2.3
-
-  next@15.5.9(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
-    dependencies:
-      '@next/env': 15.5.9
-      '@swc/helpers': 0.5.15
-      caniuse-lite: 1.0.30001765
-      postcss: 8.4.31
-      react: 19.2.3
-      react-dom: 19.2.3(react@19.2.3)
-      styled-jsx: 5.1.6(@babel/core@7.28.6)(react@19.2.3)
-    optionalDependencies:
-      '@next/swc-darwin-arm64': 15.5.7
-      '@next/swc-darwin-x64': 15.5.7
-      '@next/swc-linux-arm64-gnu': 15.5.7
-      '@next/swc-linux-arm64-musl': 15.5.7
-      '@next/swc-linux-x64-gnu': 15.5.7
-      '@next/swc-linux-x64-musl': 15.5.7
-      '@next/swc-win32-arm64-msvc': 15.5.7
-      '@next/swc-win32-x64-msvc': 15.5.7
-      sharp: 0.34.5
-    transitivePeerDependencies:
-      - '@babel/core'
-      - babel-plugin-macros
-
-  node-addon-api@8.5.0: {}
-
-  node-gyp-build@4.8.4: {}
-
-  node-releases@2.0.27: {}
-
-  oauth4webapi@3.8.3: {}
-
-  object-assign@4.1.1: {}
-
-  object-inspect@1.13.4: {}
-
-  object-keys@1.1.1: {}
-
-  object.assign@4.1.7:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-object-atoms: 1.1.1
-      has-symbols: 1.1.0
-      object-keys: 1.1.1
-
-  object.entries@1.1.9:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-object-atoms: 1.1.1
-
-  object.fromentries@2.0.8:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-object-atoms: 1.1.1
-
-  object.groupby@1.0.3:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-
-  object.values@1.2.1:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-object-atoms: 1.1.1
-
-  optionator@0.9.4:
-    dependencies:
-      deep-is: 0.1.4
-      fast-levenshtein: 2.0.6
-      levn: 0.4.1
-      prelude-ls: 1.2.1
-      type-check: 0.4.0
-      word-wrap: 1.2.5
-
-  own-keys@1.0.1:
-    dependencies:
-      get-intrinsic: 1.3.0
-      object-keys: 1.1.1
-      safe-push-apply: 1.0.0
-
-  p-limit@3.1.0:
-    dependencies:
-      yocto-queue: 0.1.0
-
-  p-locate@5.0.0:
-    dependencies:
-      p-limit: 3.1.0
-
-  parent-module@1.0.1:
-    dependencies:
-      callsites: 3.1.0
-
-  path-exists@4.0.0: {}
-
-  path-key@3.1.1: {}
-
-  path-parse@1.0.7: {}
-
-  picocolors@1.1.1: {}
-
-  picomatch@2.3.1: {}
-
-  picomatch@4.0.3: {}
-
-  possible-typed-array-names@1.1.0: {}
-
-  postcss-value-parser@4.2.0: {}
-
-  postcss@8.4.31:
-    dependencies:
-      nanoid: 3.3.11
-      picocolors: 1.1.1
-      source-map-js: 1.2.1
-
-  postcss@8.5.6:
-    dependencies:
-      nanoid: 3.3.11
-      picocolors: 1.1.1
-      source-map-js: 1.2.1
-
-  postgres@3.4.8: {}
-
-  preact-render-to-string@6.5.11(preact@10.24.3):
-    dependencies:
-      preact: 10.24.3
-
-  preact@10.24.3: {}
-
-  prelude-ls@1.2.1: {}
-
-  prop-types@15.8.1:
-    dependencies:
-      loose-envify: 1.4.0
-      object-assign: 4.1.1
-      react-is: 16.13.1
-
-  punycode@2.3.1: {}
-
-  queue-microtask@1.2.3: {}
-
-  react-dom@19.2.3(react@19.2.3):
-    dependencies:
-      react: 19.2.3
-      scheduler: 0.27.0
-
-  react-is@16.13.1: {}
-
-  react@19.2.3: {}
-
-  reflect.getprototypeof@1.0.10:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-      get-intrinsic: 1.3.0
-      get-proto: 1.0.1
-      which-builtin-type: 1.2.1
-
-  regexp.prototype.flags@1.5.4:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-errors: 1.3.0
-      get-proto: 1.0.1
-      gopd: 1.2.0
-      set-function-name: 2.0.2
-
-  resolve-from@4.0.0: {}
-
-  resolve-pkg-maps@1.0.0: {}
-
-  resolve@1.22.11:
-    dependencies:
-      is-core-module: 2.16.1
-      path-parse: 1.0.7
-      supports-preserve-symlinks-flag: 1.0.0
-
-  resolve@2.0.0-next.5:
-    dependencies:
-      is-core-module: 2.16.1
-      path-parse: 1.0.7
-      supports-preserve-symlinks-flag: 1.0.0
-
-  reusify@1.1.0: {}
-
-  run-parallel@1.2.0:
-    dependencies:
-      queue-microtask: 1.2.3
-
-  safe-array-concat@1.1.3:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      get-intrinsic: 1.3.0
-      has-symbols: 1.1.0
-      isarray: 2.0.5
-
-  safe-push-apply@1.0.0:
-    dependencies:
-      es-errors: 1.3.0
-      isarray: 2.0.5
-
-  safe-regex-test@1.1.0:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      is-regex: 1.2.1
-
-  scheduler@0.27.0: {}
-
-  semver@6.3.1: {}
-
-  semver@7.7.3: {}
-
-  set-function-length@1.2.2:
-    dependencies:
-      define-data-property: 1.1.4
-      es-errors: 1.3.0
-      function-bind: 1.1.2
-      get-intrinsic: 1.3.0
-      gopd: 1.2.0
-      has-property-descriptors: 1.0.2
-
-  set-function-name@2.0.2:
-    dependencies:
-      define-data-property: 1.1.4
-      es-errors: 1.3.0
-      functions-have-names: 1.2.3
-      has-property-descriptors: 1.0.2
-
-  set-proto@1.0.0:
-    dependencies:
-      dunder-proto: 1.0.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-
-  sharp@0.34.5:
-    dependencies:
-      '@img/colour': 1.0.0
-      detect-libc: 2.1.2
-      semver: 7.7.3
-    optionalDependencies:
-      '@img/sharp-darwin-arm64': 0.34.5
-      '@img/sharp-darwin-x64': 0.34.5
-      '@img/sharp-libvips-darwin-arm64': 1.2.4
-      '@img/sharp-libvips-darwin-x64': 1.2.4
-      '@img/sharp-libvips-linux-arm': 1.2.4
-      '@img/sharp-libvips-linux-arm64': 1.2.4
-      '@img/sharp-libvips-linux-ppc64': 1.2.4
-      '@img/sharp-libvips-linux-riscv64': 1.2.4
-      '@img/sharp-libvips-linux-s390x': 1.2.4
-      '@img/sharp-libvips-linux-x64': 1.2.4
-      '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
-      '@img/sharp-libvips-linuxmusl-x64': 1.2.4
-      '@img/sharp-linux-arm': 0.34.5
-      '@img/sharp-linux-arm64': 0.34.5
-      '@img/sharp-linux-ppc64': 0.34.5
-      '@img/sharp-linux-riscv64': 0.34.5
-      '@img/sharp-linux-s390x': 0.34.5
-      '@img/sharp-linux-x64': 0.34.5
-      '@img/sharp-linuxmusl-arm64': 0.34.5
-      '@img/sharp-linuxmusl-x64': 0.34.5
-      '@img/sharp-wasm32': 0.34.5
-      '@img/sharp-win32-arm64': 0.34.5
-      '@img/sharp-win32-ia32': 0.34.5
-      '@img/sharp-win32-x64': 0.34.5
-    optional: true
-
-  shebang-command@2.0.0:
-    dependencies:
-      shebang-regex: 3.0.0
-
-  shebang-regex@3.0.0: {}
-
-  side-channel-list@1.0.0:
-    dependencies:
-      es-errors: 1.3.0
-      object-inspect: 1.13.4
-
-  side-channel-map@1.0.1:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      get-intrinsic: 1.3.0
-      object-inspect: 1.13.4
-
-  side-channel-weakmap@1.0.2:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      get-intrinsic: 1.3.0
-      object-inspect: 1.13.4
-      side-channel-map: 1.0.1
-
-  side-channel@1.1.0:
-    dependencies:
-      es-errors: 1.3.0
-      object-inspect: 1.13.4
-      side-channel-list: 1.0.0
-      side-channel-map: 1.0.1
-      side-channel-weakmap: 1.0.2
-
-  source-map-js@1.2.1: {}
-
-  stable-hash@0.0.5: {}
-
-  stop-iteration-iterator@1.1.0:
-    dependencies:
-      es-errors: 1.3.0
-      internal-slot: 1.1.0
-
-  string.prototype.includes@2.0.1:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-
-  string.prototype.matchall@4.0.12:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-errors: 1.3.0
-      es-object-atoms: 1.1.1
-      get-intrinsic: 1.3.0
-      gopd: 1.2.0
-      has-symbols: 1.1.0
-      internal-slot: 1.1.0
-      regexp.prototype.flags: 1.5.4
-      set-function-name: 2.0.2
-      side-channel: 1.1.0
-
-  string.prototype.repeat@1.0.0:
-    dependencies:
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-
-  string.prototype.trim@1.2.10:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-data-property: 1.1.4
-      define-properties: 1.2.1
-      es-abstract: 1.24.1
-      es-object-atoms: 1.1.1
-      has-property-descriptors: 1.0.2
-
-  string.prototype.trimend@1.0.9:
-    dependencies:
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      define-properties: 1.2.1
-      es-object-atoms: 1.1.1
-
-  string.prototype.trimstart@1.0.8:
-    dependencies:
-      call-bind: 1.0.8
-      define-properties: 1.2.1
-      es-object-atoms: 1.1.1
-
-  strip-bom@3.0.0: {}
-
-  strip-json-comments@3.1.1: {}
-
-  styled-jsx@5.1.6(@babel/core@7.28.6)(react@19.2.3):
-    dependencies:
-      client-only: 0.0.1
-      react: 19.2.3
-    optionalDependencies:
-      '@babel/core': 7.28.6
-
-  supports-color@7.2.0:
-    dependencies:
-      has-flag: 4.0.0
-
-  supports-preserve-symlinks-flag@1.0.0: {}
-
-  tailwindcss@4.1.18: {}
-
-  tapable@2.3.0: {}
-
-  tinyglobby@0.2.15:
-    dependencies:
-      fdir: 6.5.0(picomatch@4.0.3)
-      picomatch: 4.0.3
-
-  to-regex-range@5.0.1:
-    dependencies:
-      is-number: 7.0.0
-
-  ts-api-utils@2.4.0(typescript@5.9.3):
-    dependencies:
-      typescript: 5.9.3
-
-  tsconfig-paths@3.15.0:
-    dependencies:
-      '@types/json5': 0.0.29
-      json5: 1.0.2
-      minimist: 1.2.8
-      strip-bom: 3.0.0
-
-  tslib@2.8.1: {}
-
-  type-check@0.4.0:
-    dependencies:
-      prelude-ls: 1.2.1
-
-  typed-array-buffer@1.0.3:
-    dependencies:
-      call-bound: 1.0.4
-      es-errors: 1.3.0
-      is-typed-array: 1.1.15
-
-  typed-array-byte-length@1.0.3:
-    dependencies:
-      call-bind: 1.0.8
-      for-each: 0.3.5
-      gopd: 1.2.0
-      has-proto: 1.2.0
-      is-typed-array: 1.1.15
-
-  typed-array-byte-offset@1.0.4:
-    dependencies:
-      available-typed-arrays: 1.0.7
-      call-bind: 1.0.8
-      for-each: 0.3.5
-      gopd: 1.2.0
-      has-proto: 1.2.0
-      is-typed-array: 1.1.15
-      reflect.getprototypeof: 1.0.10
-
-  typed-array-length@1.0.7:
-    dependencies:
-      call-bind: 1.0.8
-      for-each: 0.3.5
-      gopd: 1.2.0
-      is-typed-array: 1.1.15
-      possible-typed-array-names: 1.1.0
-      reflect.getprototypeof: 1.0.10
-
-  typescript-eslint@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
-    dependencies:
-      '@typescript-eslint/eslint-plugin': 8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3)
-      '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
-      eslint: 9.39.2(jiti@2.6.1)
-      typescript: 5.9.3
-    transitivePeerDependencies:
-      - supports-color
-
-  typescript@5.9.3: {}
-
-  unbox-primitive@1.1.0:
-    dependencies:
-      call-bound: 1.0.4
-      has-bigints: 1.1.0
-      has-symbols: 1.1.0
-      which-boxed-primitive: 1.1.1
-
-  undici-types@7.16.0: {}
-
-  unrs-resolver@1.11.1:
-    dependencies:
-      napi-postinstall: 0.3.4
-    optionalDependencies:
-      '@unrs/resolver-binding-android-arm-eabi': 1.11.1
-      '@unrs/resolver-binding-android-arm64': 1.11.1
-      '@unrs/resolver-binding-darwin-arm64': 1.11.1
-      '@unrs/resolver-binding-darwin-x64': 1.11.1
-      '@unrs/resolver-binding-freebsd-x64': 1.11.1
-      '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1
-      '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1
-      '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1
-      '@unrs/resolver-binding-linux-arm64-musl': 1.11.1
-      '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1
-      '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1
-      '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1
-      '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1
-      '@unrs/resolver-binding-linux-x64-gnu': 1.11.1
-      '@unrs/resolver-binding-linux-x64-musl': 1.11.1
-      '@unrs/resolver-binding-wasm32-wasi': 1.11.1
-      '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1
-      '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1
-      '@unrs/resolver-binding-win32-x64-msvc': 1.11.1
-
-  update-browserslist-db@1.2.3(browserslist@4.28.1):
-    dependencies:
-      browserslist: 4.28.1
-      escalade: 3.2.0
-      picocolors: 1.1.1
-
-  uri-js@4.4.1:
-    dependencies:
-      punycode: 2.3.1
-
-  use-debounce@10.1.0(react@19.2.3):
-    dependencies:
-      react: 19.2.3
-
-  which-boxed-primitive@1.1.1:
-    dependencies:
-      is-bigint: 1.1.0
-      is-boolean-object: 1.2.2
-      is-number-object: 1.1.1
-      is-string: 1.1.1
-      is-symbol: 1.1.1
-
-  which-builtin-type@1.2.1:
-    dependencies:
-      call-bound: 1.0.4
-      function.prototype.name: 1.1.8
-      has-tostringtag: 1.0.2
-      is-async-function: 2.1.1
-      is-date-object: 1.1.0
-      is-finalizationregistry: 1.1.1
-      is-generator-function: 1.1.2
-      is-regex: 1.2.1
-      is-weakref: 1.1.1
-      isarray: 2.0.5
-      which-boxed-primitive: 1.1.1
-      which-collection: 1.0.2
-      which-typed-array: 1.1.20
-
-  which-collection@1.0.2:
-    dependencies:
-      is-map: 2.0.3
-      is-set: 2.0.3
-      is-weakmap: 2.0.2
-      is-weakset: 2.0.4
-
-  which-typed-array@1.1.20:
-    dependencies:
-      available-typed-arrays: 1.0.7
-      call-bind: 1.0.8
-      call-bound: 1.0.4
-      for-each: 0.3.5
-      get-proto: 1.0.1
-      gopd: 1.2.0
-      has-tostringtag: 1.0.2
-
-  which@2.0.2:
-    dependencies:
-      isexe: 2.0.0
-
-  word-wrap@1.2.5: {}
-
-  yallist@3.1.1: {}
-
-  yocto-queue@0.1.0: {}
-
-  zod-validation-error@4.0.2(zod@4.3.5):
-    dependencies:
-      zod: 4.3.5
-
-  zod@4.3.5: {}
Index: stcss.config.mjs
===================================================================
--- postcss.config.mjs	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,6 +1,0 @@
-export default {
-  plugins: {
-    '@tailwindcss/postcss': {},
-    // autoprefixer is no longer needed in v4, as it's included by default with LightningCSS
-  },
-};
Index: ilwind.config.ts
===================================================================
--- tailwind.config.ts	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,29 +1,0 @@
-import type { Config } from 'tailwindcss';
-
-const config: Config = {
-  content: [
-    './pages/**/*.{js,ts,jsx,tsx,mdx}',
-    './components/**/*.{js,ts,jsx,tsx,mdx}',
-    './app/**/*.{js,ts,jsx,tsx,mdx}',
-  ],
-  theme: {
-    extend: {
-      colors: {
-        fein: {
-          primary: '#249e86',
-          primaryDark: '#1d7f6a',
-          accent: '#1d7f6a',
-        },
-      },
-    },
-    keyframes: {
-      shimmer: {
-        '100%': {
-          transform: 'translateX(100%)',
-        },
-      },
-    },
-  },
-  plugins: [require('@tailwindcss/forms')],
-};
-export default config;
Index: config.json
===================================================================
--- tsconfig.json	(revision 95953b25a807e0a7c0d989529f8d1a97350fdea2)
+++ 	(revision )
@@ -1,44 +1,0 @@
-{
-  "compilerOptions": {
-    "target": "ES2017",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "strict": true,
-    "noEmit": true,
-    "esModuleInterop": true,
-    "module": "esnext",
-    "moduleResolution": "bundler",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "jsx": "preserve",
-    "incremental": true,
-    "plugins": [
-      {
-        "name": "next"
-      }
-    ],
-    "baseUrl": ".",
-    "paths": {
-      "@/*": [
-        "./*"
-      ]
-    }
-  },
-  "include": [
-    "next-env.d.ts",
-    "**/*.ts",
-    "**/*.tsx",
-    ".next/types/**/*.ts",
-    "app/lib/placeholder-data.ts",
-    "scripts/seed.js",
-    ".next/dev/types/**/*.ts"
-  ],
-  "exclude": [
-    "node_modules"
-  ]
-}
