.naomi.party username for Bluesky.",
+ name: "Nymira",
+ premium: true,
+ url: "https://naomi.party",
+ wip: true,
+ },
+ {
+ avatar: null,
+ category: "websites",
+ description: "A website outlining our policies, legal agreements, community rules, and product information.",
+ name: "NHCarrigan Documentation",
+ premium: false,
+ url: "https://docs.nhcarrigan.com",
+ wip: true,
+ },
+ {
+ avatar: null,
+ category: "websites",
+ description: "A self-hosted Discourse instance for our community.",
+ name: "Fourm",
+ premium: false,
+ url: "https://forum.nhcarrigan.com",
+ wip: false,
+ },
+ {
+ avatar: null,
+ category: "websites",
+ description: "A self-hosted Gitea instance to hold all of our source code.",
+ name: "Gitea",
+ premium: false,
+ url: "https://git.nhcarrigan.com",
+ wip: false,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/hikari.png",
+ category: "websites",
+ description: "This dashboard!",
+ name: "Hikari",
+ premium: false,
+ url: "https://hikari.nhcarrigan.com",
+ wip: true,
+ },
+ {
+ avatar: null,
+ category: "community",
+ description: "A Discord, Slack, and Bluesky bot that provides you motherly love and encouragement.",
+ name: "Mommy Bot",
+ premium: false,
+ url: "https://mommy-bot.nhcarrigan.com",
+ wip: false,
+ },
+ {
+ avatar: null,
+ category: "websites",
+ description: "A quick web app that provides you motherly love and encouragements.",
+ name: "Mommy",
+ premium: false,
+ url: "https://mommy.nhcarrigan.com",
+ wip: false,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/lucinda.png",
+ category: "websites",
+ description: "A kanban-style task management site.",
+ name: "Lucinda",
+ premium: false,
+ url: "https://lucinda.nhcarrigan.com",
+ wip: false,
+ },
+ {
+ avatar: null,
+ category: "websites",
+ description: "Our homepage and marketing landing.",
+ name: "NHCarrigan",
+ premium: false,
+ url: "https://nhcarrigan.com",
+ wip: false,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/vitalia.png",
+ category: "websites",
+ description: "A full-featured nutrition tracker with community-driven nutrient data.",
+ name: "Vitalia",
+ premium: true,
+ url: "https://vitalia.nhcarrigan.com",
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/octavia.png",
+ category: "apps",
+ description: "Linux-native music player application with a focus on handling large libraries with minimal memory.",
+ name: "Octavia",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/maribelle.png",
+ category: "community",
+ description: "A Discord bot that allows you to configure daily progress huddle reminders for your server members.",
+ name: "Maribelle",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/sorielle.png",
+ category: "community",
+ description: "A Discord bot that allows servers to specify a venting channel for automatic deletion.",
+ name: "Sorielle",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/verena.png",
+ category: "community",
+ description: "A Discord bot that allows identity and age verification.",
+ name: "Verena",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/thalassa.png",
+ category: "apps",
+ description: "A rich presence application for Linux.",
+ name: "Thalassa",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/aeris.png",
+ category: "websites",
+ description: "An authentication service featuring magic links and support for multiple social media platforms",
+ name: "Aeris",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/liora.png",
+ category: "community",
+ description: "A Discord bot that allows your server members to specify 'highlight' words, which they'll get pinged on if a message contains that word.",
+ name: "Liora",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/thessalia.png",
+ category: "community",
+ description: "An RPG game on Discord",
+ name: "Thessalia",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/callista.png",
+ category: "community",
+ description: "A user-installable Discord bot that allows you to bookmark messages and save a link and copy in your DMs.",
+ name: "Callista",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/isolda.png",
+ category: "apps",
+ description: "Modern, sleek email client for the web or desktop",
+ name: "Isolda",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/meliora.png",
+ category: "websites",
+ description: "Embeddable chat widget, comment section, and full support flow utility.",
+ name: "Meliora",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/aurelia.png",
+ category: "websites",
+ description: "Blogging platform with markdown editor",
+ name: "Aurelia",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/eirene.png",
+ category: "community",
+ description: "Website and Discord activity that allows you to participate in code challenges competitively or collaboratively",
+ name: "Eirene",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/amirei.png",
+ category: "websites",
+ description: "A quick social link aggregator for 'link in bio' pages.",
+ name: "Amirei",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/zephra.png",
+ category: "websites",
+ description: "Microblogging social media platform.",
+ name: "Zephra",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/oriana.png",
+ category: "websites",
+ description: "Uptime monitoring tool with status pages",
+ name: "Oriana",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/lyra.png",
+ category: "websites",
+ description: "A web-based API mocking tool, allowing you to create temporary endpoints for a front-end to hit, test webhook payloads, and more!",
+ name: "Lyra",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/selene.png",
+ category: "apps",
+ description: "A local-only privacy-focused REST API client.",
+ name: "Selene",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/sybil.png",
+ category: "community",
+ description: "A Discord bot that syndicates forum threads to an indexable website and generates help articles based on resolved conversations.",
+ name: "Sybil",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/calenelle.png",
+ category: "websites",
+ description: "A group coordination app with event scheduling and such.",
+ name: "Calenelle",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/rowena.png",
+ category: "websites",
+ description: "Web app that allows you to create and share forms, and track responses in a user friendly table.",
+ name: "Rowena",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/alouette.png",
+ category: "websites",
+ description: "A web server that allows you to set up arbitrary webhooks and format them to post on Discord.",
+ name: "Alouette",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/clarion.png",
+ category: "community",
+ description: "A Discord bot with dashboard that allows server mangers to post and edit announcements, rules, and similar.",
+ name: "Clarion",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/elowyn.png",
+ category: "websites",
+ description: "A quick website that helps you format text.",
+ name: "Elowyn",
+ premium: false,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/evangeline.png",
+ category: "community",
+ description: "A Discord bot that allows you to configure canned replies, retrieve them anywhere on discord, and easily copy + paste them into chat.",
+ name: "Evangeline",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/theodora.png",
+ category: "community",
+ description: "A Discord bot that generates 100 days of code reminders.",
+ name: "Theodora",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+ {
+ avatar: "https://cdn.nhcarrigan.com/new-avatars/vivienne.png",
+ category: "websites",
+ description: "An RSS feed reader/management site.",
+ name: "Vivienne",
+ premium: true,
+ url: null,
+ wip: true,
+ },
+];
diff --git a/client/src/app/home/home.css b/client/src/app/home/home.css
index e69de29..f54fb81 100644
--- a/client/src/app/home/home.css
+++ b/client/src/app/home/home.css
@@ -0,0 +1,94 @@
+ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+#one {
+ transform: translateY(-200vh);
+ animation: slide-down 2s forwards;
+ font-size: 1.3rem;
+}
+
+#two {
+ transform: translateY(200vh);
+ animation: slide-up 2s forwards 2s;
+}
+
+#three {
+ transform: translateX(-200vw);
+ animation: slide-left 2s forwards 4s;
+}
+
+#four {
+ transform: translateX(200vw);
+ animation: slide-right 2s forwards 6s;
+}
+
+#five {
+ transform: translateX(-200vw);
+ animation: slide-left 2s forwards 8s;
+}
+
+#six {
+ transform: translateX(200vw);
+ animation: slide-right 2s forwards 10s;
+}
+
+#fade {
+ opacity: 0;
+ animation: fade-in 2s forwards 12s;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-evenly;
+ align-items: center;
+ flex-wrap: wrap;
+}
+
+.btn {
+ display: inline-block;
+ padding: 10px 20px;
+ background-color: var(--foreground);
+ color: var(--background);
+ text-decoration: none;
+ border-radius: 50px;
+ border: 2px solid white;
+}
+
+.btn:hover {
+ background-color: var(--background);
+ color: var(--foreground);
+ transition: background-color 0.3s, color 0.3s;
+}
+
+@keyframes slide-left {
+ 100% { transform: translateX(0%); }
+}
+
+@keyframes slide-right {
+ 100% { transform: translateX(0%); }
+}
+
+@keyframes slide-up {
+ 100% { transform: translateY(0%); }
+}
+
+@keyframes slide-down {
+ 100% { transform: translateY(0%); }
+}
+
+@keyframes fade-in {
+ 100% { opacity: 1; }
+}
+
+@keyframes background-color {
+ 0% { background-color: var(--foreground); }
+ 100% { background-color: var(--background); }
+}
+
+@media screen and (prefers-reduced-motion: reduce) {
+ * {
+ animation: none !important;
+ transform: none !important;
+ }
+}
diff --git a/client/src/app/home/home.html b/client/src/app/home/home.html
index 2652c7b..63372e4 100644
--- a/client/src/app/home/home.html
+++ b/client/src/app/home/home.html
@@ -1,8 +1,20 @@
Hi there, I'm Hikari~!
-
-
- I am here to help you with all of NHCarrigan's products, including things like managing your subscriptions and configuring applications!
-
-
- Naomi is still hard at work bringing me to life! We would love to hear your thoughts in our community~!
-
+
+How may I help you today?
+I can assist you with:
+
+ - Finding a product to suit your needs
+ - Manage your account, subscriptions, and licenses
+ - Modifying settings for individual products
+ - Answering your specific questions with a chat assistant
+
+
diff --git a/client/src/app/nav/nav.css b/client/src/app/nav/nav.css
new file mode 100644
index 0000000..2bb2a1b
--- /dev/null
+++ b/client/src/app/nav/nav.css
@@ -0,0 +1,65 @@
+nav {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 40px;
+ color: var(--foreground);
+ background-color: var(--background);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-left: 15px;
+ padding-right: 15px;
+}
+
+nav a:not(#logo) {
+ text-decoration: none;
+ padding: 0 15px;
+ font-size: 1.2rem;
+}
+
+nav a:hover:not(#logo) {
+ text-decoration: underline;
+ color: var(--background);
+ background-color: var(--foreground);
+}
+
+img {
+ height: 30px;
+ width: auto;
+ margin-right: 15px;
+}
+
+hr {
+ width: 100%;
+ border: none;
+ border-top: 1px solid var(--foreground);
+ margin: 0;
+}
+
+.dropdown {
+ display: none;
+}
+
+.dropdown.open {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ right: 0;
+ top: 40px;
+ background-color: var(--background);
+ color: var(--foreground);
+ border: 1px solid var(--foreground);
+ border-radius: 5px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
+}
+
+#logo {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
+ text-decoration: none;
+ font-size: 2rem;
+}
diff --git a/client/src/app/nav/nav.html b/client/src/app/nav/nav.html
new file mode 100644
index 0000000..4170929
--- /dev/null
+++ b/client/src/app/nav/nav.html
@@ -0,0 +1,19 @@
+
diff --git a/client/src/app/nav/nav.ts b/client/src/app/nav/nav.ts
new file mode 100644
index 0000000..fdae55f
--- /dev/null
+++ b/client/src/app/nav/nav.ts
@@ -0,0 +1,28 @@
+/**
+ * @copyright nhcarrigan
+ * @license Naomi's Public License
+ * @author Naomi Carrigan
+ */
+
+import { CommonModule } from "@angular/common";
+import { Component } from "@angular/core";
+
+@Component({
+ imports: [ CommonModule ],
+ selector: "app-nav",
+ styleUrl: "./nav.css",
+ templateUrl: "./nav.html",
+})
+export class Nav {
+ public navOpen = false;
+ public dropdownClass = "dropdown";
+
+ public toggleNav(): void {
+ this.navOpen = !this.navOpen;
+ if (this.navOpen) {
+ this.dropdownClass = "dropdown open";
+ } else {
+ this.dropdownClass = "dropdown";
+ }
+ }
+}
diff --git a/client/src/app/products/products.css b/client/src/app/products/products.css
new file mode 100644
index 0000000..3c78adc
--- /dev/null
+++ b/client/src/app/products/products.css
@@ -0,0 +1,85 @@
+a.product {
+ text-decoration: none;
+}
+
+a.product:hover {
+ background-color: var(--background);
+ color: var(--foreground);
+}
+
+.product:not(a) {
+ cursor: default;
+ border: 2px dashed grey;
+}
+
+.btn {
+ display: inline-block;
+ padding: 10px 20px;
+ background-color: var(--foreground);
+ color: var(--background);
+ text-decoration: none;
+ border-radius: 50px;
+ border: 2px solid white;
+ font-family: 'OpenDyslexic', monospace;
+}
+
+.btn:disabled {
+ background-color: var(--background);
+ color: var(--foreground);
+}
+
+.btn:hover {
+ background-color: var(--background);
+ color: var(--foreground);
+ transition: background-color 0.3s, color 0.3s;
+}
+
+.product {
+ display: grid;
+ grid-template-areas: "logo title icon" "logo description icon";
+ grid-template-columns: 100px 1fr auto;
+ background-color: var(--foreground);
+ color: var(--background);
+ border: 2px solid white;
+ border-radius: 50px;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+ padding-right: 20px;
+ align-items: center;
+}
+
+.icons {
+ grid-area: icon;
+ font-size: 2rem;
+ display: grid;
+ grid-template-columns: repeat(2, auto);
+ gap: 10px;
+}
+
+.title {
+ grid-area: title;
+ font-size: 1.5rem;
+ font-weight: bold;
+}
+
+.description {
+ grid-area: description;
+ font-size: 1rem;
+ margin-top: 10px;
+}
+
+.logo {
+ grid-area: logo;
+ width: 100px;
+ height: 100px;
+ border-radius: 50%;
+}
+
+.row {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-evenly;
+ align-items: center;
+ flex-wrap: wrap;
+}
diff --git a/client/src/app/products/products.html b/client/src/app/products/products.html
new file mode 100644
index 0000000..bdb4e9e
--- /dev/null
+++ b/client/src/app/products/products.html
@@ -0,0 +1,150 @@
+Products
+
+Excellent! What sort of product are you looking for?
+
+
+
+
+
+
+And would you like to apply a filter?
+
+
+
+
+
+
+
+
+ Oh dear, it appears there are no products in this category yet! Please check
+ back later.
+
+
+
+I want something custom...
diff --git a/client/src/app/products/products.ts b/client/src/app/products/products.ts
new file mode 100644
index 0000000..d23e86e
--- /dev/null
+++ b/client/src/app/products/products.ts
@@ -0,0 +1,78 @@
+/**
+ * @copyright nhcarrigan
+ * @license Naomi's Public License
+ * @author Naomi Carrigan
+ */
+
+import { CommonModule } from "@angular/common";
+import { Component } from "@angular/core";
+import { products } from "../config/products.js";
+
+@Component({
+ imports: [ CommonModule ],
+ selector: "app-products",
+ styleUrl: "./products.css",
+ templateUrl: "./products.html",
+})
+export class Products {
+ public view: (typeof products)[number]["category"] | "all"
+ = "all";
+ public products: typeof products = [];
+ public readonly filters: {
+ wip: boolean;
+ prod: boolean;
+ paid: boolean;
+ free: boolean;
+ } = {
+ free: true,
+ paid: true,
+ prod: true,
+ wip: true,
+ };
+
+ public constructor() {
+ this.selectCategory("all");
+ }
+
+ public selectCategory(
+ category: (typeof products)[number]["category"] | "all",
+ ): void {
+ this.view = category;
+ const sortedProducts = products.sort((a, b) => {
+ return a.name.localeCompare(b.name);
+ });
+ if (this.view === "all") {
+ this.products = sortedProducts;
+ return;
+ }
+ this.products = sortedProducts.filter((product) => {
+ return product.category === this.view;
+ });
+ }
+
+ public toggleFilter(
+ filter: "wip" | "prod" | "paid" | "free",
+ ): void {
+ this.filters[filter] = !this.filters[filter];
+ this.applyFilters();
+ }
+
+ private applyFilters(): void {
+ this.selectCategory(this.view);
+ this.products = this.products.filter((product) => {
+ if (!this.filters.wip && product.wip) {
+ return false;
+ }
+ if (!this.filters.prod && !product.wip) {
+ return false;
+ }
+ if (!this.filters.paid && product.premium) {
+ return false;
+ }
+ if (!this.filters.free && !product.premium) {
+ return false;
+ }
+ return true;
+ });
+ }
+}
diff --git a/client/src/app/soon/soon.css b/client/src/app/soon/soon.css
new file mode 100644
index 0000000..fb675d8
--- /dev/null
+++ b/client/src/app/soon/soon.css
@@ -0,0 +1,15 @@
+.btn {
+ display: inline-block;
+ padding: 10px 20px;
+ background-color: var(--foreground);
+ color: var(--background);
+ text-decoration: none;
+ border-radius: 50px;
+ border: 2px solid white;
+}
+
+.btn:hover {
+ background-color: var(--background);
+ color: var(--foreground);
+ transition: background-color 0.3s, color 0.3s;
+}
diff --git a/client/src/app/soon/soon.html b/client/src/app/soon/soon.html
new file mode 100644
index 0000000..c83961b
--- /dev/null
+++ b/client/src/app/soon/soon.html
@@ -0,0 +1,16 @@
+Oh dear~!
+
+You appear to have become lost!
+
+ Either this feature is still under construction, or you have tried to go
+ somewhere that does not exist.
+
+Do not worry, I can guide you back. Where would you like to go?
+
diff --git a/client/src/app/soon/soon.ts b/client/src/app/soon/soon.ts
new file mode 100644
index 0000000..1b82b5e
--- /dev/null
+++ b/client/src/app/soon/soon.ts
@@ -0,0 +1,17 @@
+/**
+ * @copyright nhcarrigan
+ * @license Naomi's Public License
+ * @author Naomi Carrigan
+ */
+
+import { Component } from "@angular/core";
+
+@Component({
+ imports: [],
+ selector: "app-soon",
+ styleUrl: "./soon.css",
+ templateUrl: "./soon.html",
+})
+export class Soon {
+
+}
diff --git a/client/src/index.html b/client/src/index.html
index 7955438..3ab1cd9 100644
--- a/client/src/index.html
+++ b/client/src/index.html
@@ -1,15 +1,24 @@
-
+
-
-
- Hikari
-
-
-
-
-
-
-
-
-
+
+
+ Hikari
+
+
+
+
+
+
+
+
+
+
diff --git a/client/src/styles.css b/client/src/styles.css
index 90d4ee0..9bdbeee 100644
--- a/client/src/styles.css
+++ b/client/src/styles.css
@@ -1 +1,102 @@
-/* You can add global styles to this file, and also import other style files */
+@font-face {
+ font-family: 'OpenDyslexic';
+ src: url('https://cdn.nhcarrigan.com/fonts/OpenDyslexicMono-Regular.otf') format('opentype');
+}
+
+:root {
+ --foreground: #2a0a18;
+ --background: #ffb6c1bb;
+}
+
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+html {
+ font-family: 'OpenDyslexic', monospace;
+ cursor: url('https://cdn.nhcarrigan.com/cursors/cursor.cur'), auto;
+ min-height: 100vh;
+ min-width: 100vw;
+}
+body::before {
+ background: url(https://cdn.nhcarrigan.com/background.png);
+ background-size: cover;
+ background-position: center;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+ content: "";
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ opacity: 1;
+ pointer-events: none;
+}
+main {
+ color: var(--foreground);
+ background-color: var(--background);
+ text-align: center;
+ border-radius: 10px;
+ width: 100vw;
+ margin-bottom: 85px;
+ margin-top: 50px;
+ min-height: calc(100vh - 85px - 50px);
+}
+footer {
+ width: 100%;
+ color: var(--foreground);
+ background-color: var(--background);
+ position: fixed;
+ bottom: 0;
+ height: 75px;
+ padding: 0 10px;
+}
+#footer-inner-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 75px;
+}
+#footer-badge-container {
+ display: grid;
+ grid-template-columns: repeat(8, 1fr);
+ align-items: center;
+ justify-content: space-around;
+}
+#audio-theme-button, #theme-select-button {
+ background: none;
+ border: none;
+ cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
+ color: var(--foreground);
+}
+a {
+ color: unset;
+ cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
+}
+.btn:not(:disabled) {
+ cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
+}
+#tree-nation-offset-website {
+ display: flex;
+ align-items: center;
+}
+.is-dark {
+ --foreground: #ffb6c1;
+ --background: #2a0a18bb;
+}
+@media screen and (max-width: 625px) {
+ #tree-nation-offset-website {
+ display: none;
+ }
+ footer, #footer-inner-container {
+ height: 50px;
+ justify-content: space-around;
+ }
+ main {
+ margin-bottom: 60px;
+ }
+}