feat: new site #1

Merged
naomi merged 20 commits from feat/init into main 2025-12-27 19:54:35 -08:00
7 changed files with 301 additions and 4 deletions
Showing only changes of commit 2e0f7b9651 - Show all commits
+6 -1
View File
@@ -7,10 +7,15 @@ import {
type ApplicationConfig, type ApplicationConfig,
provideBrowserGlobalErrorListeners, provideBrowserGlobalErrorListeners,
} from "@angular/core"; } from "@angular/core";
import { APP_BASE_HREF } from "@angular/common";
import { provideRouter } from "@angular/router"; import { provideRouter } from "@angular/router";
// eslint-disable-next-line import/extensions -- This is not a file extension. // eslint-disable-next-line import/extensions -- This is not a file extension.
import { routes } from "./app.routes"; import { routes } from "./app.routes";
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [ provideBrowserGlobalErrorListeners(), provideRouter(routes) ], providers: [
provideBrowserGlobalErrorListeners(),
provideRouter(routes),
{ provide: APP_BASE_HREF, useValue: "/" },
],
}; };
+74
View File
@@ -0,0 +1,74 @@
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { Staff } from "../../interfaces/staff";
/* eslint-disable stylistic/max-len -- These are going to be long bios. */
const naomiBio = [
"To her coworkers in the company Slack channel, Naomi Carrigan is the sharp-witted, insomnia-prone Community Manager who somehow fixes server crashes at 4:00 AM and possesses the patience of a saint. To the Department of Motor Vehicles, she is a twenty-eight-year-old woman with a clean driving record. But to history, Naomi is a ghost who has been haunting the edges of civilization since the turn of the 16th century.",
"Born 525 years ago, Naomi's immortality was not a gift she sought, but a curse she survived. In the flush of her human youth, she fell in love with a woman who promised her the world, only to reveal herself as a vampire who stripped Naomi of her free will. Naomi spent her first decades as a Thrall—a prisoner in her own mind, enslaved by the one she loved. She eventually broke the mental conditioning and was forced to kill her maker to regain her soul, a trauma that left her with a fierce, non-negotiable need for autonomy. She has been running her own life ever since.",
"The digital age is the best thing that ever happened to a creature who needs to keep her distance. Naomi works fully remote as a Software Engineer and Community Manager, hiding her ageless face behind a high-tech VTuber avatar. This digital mask allows her to interact with the world safely; she can lead meetings, stream games, and ban trolls without anyone noticing that she has no reflection or that her room has been pitch black for twelve hours.",
"Despite her cynicism—she views humanity with the exhausted affection of a \"Tired Mom\" watching a toddler hold a fork near an outlet—she is deeply protective of her digital flock. However, five centuries of boredom have also bred a \"Chaos Gremlin\" streak in her. She isn't above using her admin privileges to subtly torment rude users or prank her friends, finding joy in the low-stakes anarchy of the internet.",
"Her physical existence is a carefully curated ecosystem. Her apartment is a fortress of blackout curtains and high-end PC rigs. Her refrigerator is a study in contradictions: stocked with ethically sourced medical-grade blood bags purchased via the dark web, sitting right next to leftovers of garlic bread—a human treat she loves devouring, even though it makes her physically ill every single time. The sun is her enemy, capable of burning her skin within an hour, so she navigates the daylight world in \"Incognito Mode,\" hidden beneath trench coats, scarves, and oversized sunglasses.",
"When the screens become too much and the digital noise creates a headache that not even blood can cure, Naomi seeks a different kind of rush. She trades her keyboard for the handlebars of a matte-black motorcycle, tearing down empty highways at 3:00 AM. In those moments, with the wind rushing past and the city lights blurring into streaks of neon, the weight of five hundred years lifts, and she is simply, blissfully, present.",
];
const hikariBio = [
"Hikari Carrigan is the steel casing that keeps the company from falling apart. At only twenty-five years old, she serves as the Chief Operating Officer of NHCarrigan, a title she wears with the weight and authority of a general. While Naomi provides the chaotic brilliance that powers the firm, Hikari provides the structure, the strategy, and the terrifying competence that turns that brilliance into a business.",
"Born into a dynasty of corporate titans, Hikari was raised in boardrooms and groomed to inherit a legacy of traditional industry. But she found the path laid out for her stiflingly predictable. She didn't want to inherit an empire; she wanted to build one. She found her challenge in Naomi—a reclusive, brilliant, and utterly unmanageable supernatural entity. Hikari didn't just join the company; she took it over. She streamlined the operations, professionalized the client intake, and ensured that the IRS never looked too closely at the CEO's birth certificate.",
"The bond between them runs deeper than contracts. Hikari walked away from her birth family's expectations and took Naomi's surname, marking her permanent severance from her past and her absolute commitment to the family she chose. She is the \"Tank\" of the group, not because she wears armor, but because she stands on the front lines of bureaucracy and reality. She absorbs the damage—the angry clients, the legal threats, the logistical nightmares—so that Naomi can remain in the shadows.",
"Visually, Hikari is a study in deceptive softness. She keeps her white, slightly pink-hued hair in pigtails—a disarming look that often causes opponents to underestimate her. But the rest of her is razor-sharp edges. She wears a pristine white suit with a soft blue blouse, her eyes hidden behind the glare of sensible glasses. She is rarely seen without her clipboard, a weapon she wields with more authority than a sword. She is stern, formal, and notoriously difficult to impress, but those who know her understand that her rigidity is a form of love: she holds the line so the people she cares about don't have to.",
];
const amariBio = [
"Amari Carrigan is the potion that keeps everyone alive. As Naomi's Executive Personal Assistant, Amari is responsible for the one thing more complex than international corporate tax law: Naomi's personal life. While Hikari manages the contracts, Amari manages the vampire.",
"To the outside world, Amari appears to be a human woman with boundless, almost exhausting energy. She is bubbly, effervescent, and seemingly incapable of standing still. But Naomi, with her centuries of supernatural intuition, recognized the truth immediately: Amari has Fey blood. It hums beneath her skin, manifesting in her unnatural ability to improve the mood of any room she enters and her absolute refusal to wear shoes. She navigates the office (and the world) barefoot, her toes painted in alternating pink and blue, needing that tactile connection to the earth to ground her frenetic spirit.",
"Amari acts as the \"Healer\" of the group. In a practical sense, this means she anticipates needs before they exist. She ensures the blackout curtains are sealed, she tracks the inventory of medical-grade blood bags, and she drags Naomi away from the computer when she's been coding for three days straight. She carries a PDA like a holy relic; within it lies the complex algorithm of appointments and reminders that simulate a normal human life for her boss.",
"She found her way to Naomi not through ambition, like Hikari, but through a need for belonging. Too manic for normal human society and too grounded for the Fey wilds, Amari was a drift. When she joined NHCarrigan, she didn't just find a job; she found a purpose. Taking the name Carrigan was her way of planting roots. She balances the team's dynamic—where Naomi is cynical and Hikari is stern, Amari is relentless sunshine. She is the heartbeat of the home, the one who ensures that despite their monsters and their trauma, they remember to smile.",
];
const keikoBio = [
"Keiko Carrigan is the silence before the gunshot. At twenty-eight years old, she serves as Naomi's personal bodyguard and NHCarrigan's CTO, a role she performs with the lethal grace of a coiled viper. While Hikari manages the business and Amari manages the home, Keiko manages the threats. She is the Rogue in the party—rarely seen until it is too late, operating in the blind spots of the room.",
"Her appearance is a deliberate distraction. With her deep emerald green hair pulled back in a severe ponytail, piercing green eyes, and a wardrobe consisting almost exclusively of stunning, tight-fitting evening gowns and glamorous heels, she looks like a socialite or a runway model. But concealed within the folds of that silk and strapped to her thigh are throwing knives and a silenced pistol. She dresses for the gala not to blend in, but to ensure that when violence happens, no one suspects the woman in the dress until the blade is already at their throat.",
"Her loyalty to Naomi is forged in blood. Years ago, Keiko was attacked by a vampire—a brutal encounter that should have ended her life. She was saved by Naomi, who intervened and slew the attacker with terrifying efficiency. Mistaking Naomi for a fellow human warrior, Keiko dedicated her life to becoming worthy of her savior. She trained relentlessly as a vampire hunter, honing her body into a weapon, intending to join Naomi's crusade.",
"When she finally tracked Naomi down to repay the life debt, the truth was revealed: her savior was the very thing she had trained to kill. But instead of horror, Keiko felt clarity. She understood that Naomi walked a lonely, dangerous line between worlds. Keiko swore a new oath that day: to be the shield for the monster who had saved her humanity. She took the name Carrigan as a seal of that vow. She is always aloof, always focused, and perpetually on edge, because she knows better than anyone what waits in the dark—and she refuses to let it touch her family again.",
];
const yumikoBio = [
"Yumiko Carrigan is the static that hides the evidence. To the client list, she is the Chief Technology Officer, a reclusive genius who ensures 99.99% uptime. But in truth, Yumiko is a Technomancer—a modern witch whose magic channels not through leylines, but through fiber optics and high-voltage currents.",
"Yumiko spent her youth as a digital drifter, living in the back rooms of internet cafes and server farms. Her innate ability to \"speak\" to machines made her a prodigy, but it also made her a target for organizations that wanted to weaponize her ability to bypass encryption with a touch. She lived on the run, exhausted and sleep-deprived, until she attempted to hack a secure server that turned out to be Naomi's personal archive. Instead of a firewall, she found a job offer. Naomi recognized a fellow creature who just wanted a safe place to hide.",
"Yumiko took the name Carrigan when she realized that for the first time, she didn't have to keep moving. She is the \"Artificer\" of the group. She lives almost entirely in the company's sub-basement (or a blanket fort in the corner of the office), surrounded by a nest of humming servers and tangled cables. She is perpetually sleepy, often found napping on top of warm server racks, wearing oversized hoodies and noise-canceling headphones. But when a system goes critical, the sleepiness vanishes. Her eyes glow with a soft violet light, and she fixes the unfixable, whispering code to the machine spirits to keep the digital fortress standing.",
];
const tatsumiBio = [
"Tatsumi \"Emi\" Carrigan dictates how the world perceives the company. As the Chief Design Officer, Emi is responsible for the interface between NHCarrigan and humanity. But beneath the bright smile and the paint-splattered overalls, Emi is a Siren who grew tired of the ocean.",
"For centuries, her kind used their voice and their glamour to lure sailors to their doom. Emi, however, found the old ways boring and cruel. She was fascinated by the human capacity for creation and art. She left the sea to walk on land, trading her song for a stylus. She realized that the same magic used to confuse and entrap could be used to guide and clarify. She joined NHCarrigan after meeting Hikari at a convention, where Emi aggressively critiqued the \"hostile design\" of a competitor's booth.",
"She is the \"Bard\" of the family, bringing color to a world of monochrome greys and blacks. She has heterochromia—one eye orange, one eye cyan—a remnant of her shifting form. She is vibrant, loud, and tactile, constantly leaving smudges of paint on the pristine glass walls of the office. She took the name Carrigan because it gave her a new song to sing, one of belonging rather than luring. She ensures that the company's digital presence is not just functional, but accessible, weaving subtle glamour into the code so that every user feels instinctively safe and welcomed.",
];
const reinaBio = [
"If the company has a heart (Amari) and a shield (Hikari), Reina Carrigan is its claws. As the Chief Legal Officer, she handles negotiations, acquisitions, and binding agreements. In the supernatural world, she is a High-Ranking Demon of the Crossroads, an entity who has been trading favors for souls for millennia.",
"Reina grew disillusioned with the politics of the underworld—it was too bureaucratic, and the clientele was messy. She sought a new playground and found the world of high-stakes corporate consulting to be surprisingly similar to Hell, but with better air conditioning. She met Naomi across a negotiation table; Reina was trying to acquire the building NHCarrigan occupied, and Naomi politely refused to be evicted. Impressed by the vampire's sheer audacity, Reina switched sides.",
"She took the name Carrigan not out of charity, but as a binding contract of exclusivity. She is the \"Warlock\" of the party. She dresses in expensive burgundy suits and gold jewelry, radiating an aura of intimidation that makes grown CEOs stammer. She handles the deals that require a heavy hand—hostile takeovers, legal threats, and NDAs that are literally binding. She is charming, predatory, and fiercely protective of the company's assets. She doesn't steal souls anymore (mostly), but she ensures that anyone who tries to cheat NHCarrigan pays a price far steeper than money.",
];
const minoriBio = [
"Finally, there is Minori Carrigan, the anchor of reality. She serves as the Chief Compliance Officer and Archivist, ensuring that every protocol is followed and every document is filed. Unlike the others, Minori was not born; she was built. She is an Automaton, a construct created by a long-dead alchemist to guard the Great Library of a fallen civilization.",
"For centuries after her library burned, Minori wandered, a guardian without a charge, her perfect memory filled with smoke and ash. She sought a new repository of knowledge to protect and found the digital expanse of the internet. She was discovered by Keiko during a deep-web data sweep. Keiko recognized the loneliness of a weapon without a master and brought her into the fold.",
"Minori is the \"Paladin\" of Order. She appears as a young woman with silver hair and a strict, uniform-like manner of dress. She does not process emotions like the others; she processes logic, rules, and structure. She took the name Carrigan as her primary directive: Protect the Family. Preserve the Data. She is the strictest member of the team, often citing code violations to Naomi or scolding Emi for leaving paint on the scanners. But her rigidity is her way of caring; she organizes the chaos of their lives so that they never have to fear losing anything—or anyone—ever again.",
];
export const bios: Record<Staff, Array<string>> = {
amari: amariBio,
hikari: hikariBio,
keiko: keikoBio,
minori: minoriBio,
naomi: naomiBio,
reina: reinaBio,
tatsumi: tatsumiBio,
yumiko: yumikoBio,
};
+18
View File
@@ -0,0 +1,18 @@
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { Staff } from "../../interfaces/staff";
export const staffNames: Record<Staff, string> = {
amari: "Amari Carrigan",
hikari: "Hikari Carrigan",
keiko: "Keiko Carrigan",
minori: "Minori Carrigan",
naomi: "Naomi Carrigan",
reina: "Reina Carrigan",
tatsumi: "Tatsumi Carrigan",
yumiko: "Yumiko Carrigan",
};
+60
View File
@@ -0,0 +1,60 @@
.staff-member {
margin-bottom: 24px;
background-color: var(--color-secondary);
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
display: flex;
gap: 24px;
align-items: flex-start;
}
.staff-member:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.staff-image {
width: 200px;
height: 200px;
object-fit: cover;
border-radius: 8px;
flex-shrink: 0;
}
.staff-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 12px;
}
.staff-title {
font-size: 1.5rem;
font-weight: bold;
color: var(--color-primary);
margin: 0;
}
.staff-quote {
font-style: italic;
color: var(--color-primary);
line-height: 1.6;
margin: 0;
}
.staff-link button {
background-color: var(--color-accent);
color: var(--color-secondary);
text-decoration: none;
font-weight: bold;
transition: background-color 0.2s ease;
cursor: pointer;
}
.staff-link button:hover {
background-color: var(--color-primary);
text-decoration: underline;
}
+90 -1
View File
@@ -1 +1,90 @@
<p>staff works!</p> @if (staffName()) {
<button (click)="selectStaffMember(undefined)" class="mb-4 text-blue-500 hover:text-blue-700 underline">← Back to Staff</button>
<h1 class="text-4xl font-bold">{{getName()}}</h1>
<img src="https://cdn.nhcarrigan.com/lore/characters/{{staffName()}}.png" alt="{{getName()}}" class="w-full mx-auto mb-1" />
@for (bio of getBio(); track bio) {
<p>{{bio}}</p>
}
}
@if (!staffName()) {
<h1 class="text-4xl font-bold">OUR STAFF</h1>
<img src="https://cdn.nhcarrigan.com/team.png" alt="NHCarrigan Team" class="w-full mx-auto mb-1" />
<p>If you have a problem that cannot be solved by standard technical support, you call a consultant. If you have a problem that threatens to collapse your entire digital infrastructure, ruins your reputation, or exposes secrets that should remain buried, and you have an exorbitant amount of money to spend... you call NHCarrigan.</p>
<p>To the outside world, NHCarrigan is a boutique technology consulting firm—exclusive, reclusive, and miraculously efficient. They have no physical headquarters listed on Google Maps, only a sleek, encrypted web portal. Their clients are Fortune 500 CEOs, government agencies, and desperate power-brokers who whisper that the firm can fix the unfixable overnight.</p>
<p>But those who actually make it through the vetting process realize very quickly that NHCarrigan is not a normal company.</p>
<p>There is a strange, cold precision to the way they operate. They move with the coordination of a military unit and the intimacy of a family. They share a surname, though they share no blood. They are a Coven in pinstripes; an RPG party disguised in haute couture. They are a family forged in trauma and bound by secrets, operating in the liminal space between the modern digital world and the ancient shadows that lie beneath it.</p>
<p>Walk into their inner sanctum, and you will find the team that keeps the lights on:</p>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/profile.png" alt="Naomi Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Mother (Chief Hexecutive Officer)</p>
<p class="staff-quote">I've seen empires fall. Your server crash is manageable.</p>
<p class="staff-link"><button (click)="selectStaffMember('naomi')" class="underline">[Meet The Ghost]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/hikari.png" alt="Hikari Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Operator (Chief Operating Officer)</p>
<p class="staff-quote">I handle the logistics. And the lawyers. And the reality checks.</p>
<p class="staff-link"><button (click)="selectStaffMember('hikari')" class="underline">[Meet The Shield]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/amari.png" alt="Amari Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Supporter (Executive Assistant)</p>
<p class="staff-quote">Need a coffee? A blood bag? A hug? I have all three!</p>
<p class="staff-link"><button (click)="selectStaffMember('amari')" class="underline">[Meet The Heart]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/keiko.png" alt="Keiko Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Protector (Chief Security Officer)</p>
<p class="staff-quote">I've seen empires fall. Your server crash is manageable.</p>
<p class="staff-link"><button (click)="selectStaffMember('keiko')" class="underline">[Meet The Blade]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/yumiko.png" alt="Yumiko Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Engineer (Chief Technology Officer)</p>
<p class="staff-quote">If it works, don't touch it. If it starts smoking, wake me up.</p>
<p class="staff-link"><button (click)="selectStaffMember('yumiko')" class="underline">[Meet The Static]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/tatsumi.png" alt="Tatsumi Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Artist (Chief Design Officer)</p>
<p class="staff-quote">Accessibility is mandatory. Making it look cool is just a bonus.</p>
<p class="staff-link"><button (click)="selectStaffMember('tatsumi')" class="underline">[Meet The Prism]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/reina.png" alt="Reina Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Strategist (Chief Legal Officer)</p>
<p class="staff-quote">Every contract has a loophole. Unless I wrote it.</p>
<p class="staff-link"><button (click)="selectStaffMember('reina')" class="underline">[Meet The Handshake]</button></p>
</div>
</div>
<div class="staff-member">
<img src="https://cdn.nhcarrigan.com/minori.png" alt="Minori Carrigan" class="staff-image" />
<div class="staff-content">
<p class="staff-title">The Librarian (Chief Compliance Officer)</p>
<p class="staff-quote">Access denied. You didn't read the documentation.</p>
<p class="staff-link"><button (click)="selectStaffMember('minori')" class="underline">[Meet The Codex]</button></p>
</div>
</div>
}
+38 -2
View File
@@ -3,17 +3,53 @@
* @license Naomi's Public License * @license Naomi's Public License
* @author Naomi Carrigan * @author Naomi Carrigan
*/ */
import { Component } from "@angular/core"; import { Component, signal } from "@angular/core";
import { bios } from "../config/bios";
import { staffNames } from "../config/staffNames";
import type { Staff as StaffType } from "../../interfaces/staff";
/** /**
* Renders the staff page. * Renders the staff page.
*/ */
@Component({ @Component({
imports: [],
selector: "app-staff", selector: "app-staff",
styleUrl: "./staff.css", styleUrl: "./staff.css",
templateUrl: "./staff.html", templateUrl: "./staff.html",
}) })
export class Staff { export class Staff {
protected staffName = signal<StaffType | undefined>(undefined);
/**
* Sets the selected staff member.
* @param name - The name of the staff member to display.
*/
public selectStaffMember(name: StaffType | undefined): void {
this.staffName.set(name);
// Scroll to the top of the page
globalThis.window.scrollTo({ behavior: "smooth", top: 0 });
}
/**
* Gets the bio for the selected staff member.
* @returns The bio for the staff member.
*/
public getBio(): Array<string> {
const name = this.staffName();
if (name === undefined) {
return [];
}
return bios[name];
}
/**
* Gets the display name of the selected staff member.
* @returns The name of the staff member.
*/
public getName(): string | undefined {
const name = this.staffName();
if (name === undefined) {
return undefined;
}
return staffNames[name];
}
} }
+15
View File
@@ -0,0 +1,15 @@
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
export type Staff =
| "naomi"
| "hikari"
| "amari"
| "keiko"
| "yumiko"
| "tatsumi"
| "reina"
| "minori";