From c826ed650279a29193752b2d66592ed94aeba323 Mon Sep 17 00:00:00 2001 From: Rina Date: Fri, 17 Apr 2026 00:26:03 +0100 Subject: [PATCH] First Version --- .gitignore | 10 + .htaccess | 133 ++++++++++++ 400.html | 109 ++++++++++ 403.html | 109 ++++++++++ 404.html | 109 ++++++++++ 422.html | 109 ++++++++++ 500.html | 109 ++++++++++ 502.html | 109 ++++++++++ 503.html | 109 ++++++++++ LICENSE | 18 -- README.md | 193 ++++++++++++++++- coming-soon.html | 169 +++++++++++++++ contact.html | 206 ++++++++++++++++++ css/about.css | 42 ++++ css/base.css | 57 +++++ css/buttons.css | 67 ++++++ css/cards.css | 171 +++++++++++++++ css/contact.css | 143 +++++++++++++ css/footer.css | 107 ++++++++++ css/hero.css | 118 +++++++++++ css/index.css | 46 ++++ css/legal.css | 432 +++++++++++++++++++++++++++++++++++++ css/navbar.css | 162 ++++++++++++++ css/responsive.css | 146 +++++++++++++ css/sections.css | 53 +++++ css/stats.css | 59 ++++++ css/themes.css | 82 +++++++ css/utility.css | 92 ++++++++ favicon.svg | 12 ++ index.html | 223 +++++++++++++++++++ js/main.js | 230 ++++++++++++++++++++ js/theme.js | 44 ++++ privacy.html | 519 +++++++++++++++++++++++++++++++++++++++++++++ robots.txt | 4 + sitemap.xml | 73 +++++++ status.html | 173 +++++++++++++++ terms.html | 334 +++++++++++++++++++++++++++++ 37 files changed, 4862 insertions(+), 19 deletions(-) create mode 100644 .gitignore create mode 100644 .htaccess create mode 100644 400.html create mode 100644 403.html create mode 100644 404.html create mode 100644 422.html create mode 100644 500.html create mode 100644 502.html create mode 100644 503.html delete mode 100644 LICENSE create mode 100644 coming-soon.html create mode 100644 contact.html create mode 100644 css/about.css create mode 100644 css/base.css create mode 100644 css/buttons.css create mode 100644 css/cards.css create mode 100644 css/contact.css create mode 100644 css/footer.css create mode 100644 css/hero.css create mode 100644 css/index.css create mode 100644 css/legal.css create mode 100644 css/navbar.css create mode 100644 css/responsive.css create mode 100644 css/sections.css create mode 100644 css/stats.css create mode 100644 css/themes.css create mode 100644 css/utility.css create mode 100644 favicon.svg create mode 100644 index.html create mode 100644 js/main.js create mode 100644 js/theme.js create mode 100644 privacy.html create mode 100644 robots.txt create mode 100644 sitemap.xml create mode 100644 status.html create mode 100644 terms.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b66077 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# OS +.DS_Store +Thumbs.db +*~ + +# Editor +*.swp +*.swo +.vscode/ +.idea/ \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..ff40dba --- /dev/null +++ b/.htaccess @@ -0,0 +1,133 @@ +# ArcaneNeko Website - .htaccess Configuration +# Apache server configuration rules + +# Enable Rewrite Engine +RewriteEngine On +RewriteBase / + +# ============================================ +# Remove .html extension from URLs +# ============================================ +RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f +RewriteRule ^(.*)$ $1.html [L] + +# ============================================ +# SECURITY & BASIC PROTECTION +# ============================================ + +# Block access to hidden files (dotfiles) + + Require all denied + + +# Block access to config and environment files + + Require all denied + + +# ============================================ +# CUSTOM ERROR PAGES +# ============================================ +ErrorDocument 400 /400 +ErrorDocument 403 /403 +ErrorDocument 404 /404 +ErrorDocument 500 /500 +ErrorDocument 502 /502 +ErrorDocument 503 /503 + +# ============================================ +# CACHE CONTROL & PERFORMANCE +# ============================================ + +# Static assets caching - 1 year + + Header set Cache-Control "max-age=31536000, public" + + +# HTML documents - no cache + + Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate" + Header set Pragma "no-cache" + Header set Expires "0" + + +# ============================================ +# BROWSER CACHING & COMPRESSION +# ============================================ + +# Enable Gzip compression (mod_deflate) + + AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/x-javascript application/json application/rss+xml font/ttf font/otf + + +# ============================================ +# MIME TYPES & FONT ACCESS +# ============================================ + +# Allow CORS for web fonts + + Header set Access-Control-Allow-Origin "*" + + +# ============================================ +# SECURITY HEADERS +# ============================================ + +Header set X-Content-Type-Options "nosniff" +Header set X-Frame-Options "DENY" +Header set X-XSS-Protection "1; mode=block" +Header set Referrer-Policy "strict-origin-when-cross-origin" +Header set Permissions-Policy "geolocation=(), microphone=(), camera=()" + +# ============================================ +# SITEMAP +# ============================================ +RewriteRule ^sitemap\.xml$ /sitemap.xml [L] + +# ============================================ +# ROBOTS.TXT +# ============================================ +RewriteRule ^robots\.txt$ /robots.txt [L] + +# ============================================ +# HTTPS & FORCE SSL (optional) +# ============================================ +# Uncomment the next 3 lines to force HTTPS redirect +# RewriteCond %{HTTPS} off +# RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + +# ============================================ +# PHP & SERVER-SIDE PROCESSING (optional) +# ============================================ +# If your site needs PHP, uncomment: +# AddType application/x-httpd-php .php +# DirectoryIndex index.php index.html + +# ============================================ +# CLIENT SIDE ROUTING (SPA support - optional) +# ============================================ +# For single-page applications, route all non-file/non-api requests to index.html +# Uncomment if you implement client-side routing +# +# RewriteCond %{REQUEST_FILENAME} !-f +# RewriteCond %{REQUEST_FILENAME} !-d +# RewriteRule ^ index.html [L] + +# ============================================ +# NGINX COMPATIBILITY NOTES +# ============================================ +# This .htaccess is for Apache. If running with Nginx: +# - Nginx does not support .htaccess; rules must be in server config +# - ErrorDocument directives need server-level config in Nginx +# - Header directives need 'add_header' in Nginx context +# - Rewrite rules need 'rewrite' directive in Nginx +# +# Example Nginx config for static assets: +# location ~* \.(ico|pdf|flv|jpg|jpeg|png|gif|webp|svg|eot|otf|woff|woff2|ttf|css|js)$ { +# expires 1y; +# add_header Cache-Control "public"; +# try_files $uri =404; +# } +# +# Example Nginx config for sitemap: +# rewrite ^/sitemap.xml$ /sitemap.xml break; \ No newline at end of file diff --git a/400.html b/400.html new file mode 100644 index 0000000..ea9fcf6 --- /dev/null +++ b/400.html @@ -0,0 +1,109 @@ + + + + + + 400 - Bad Request | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
400
+

Bad Request

+

The request could not be processed due to a client error.

+ +
+
+ + + + \ No newline at end of file diff --git a/403.html b/403.html new file mode 100644 index 0000000..9176d6a --- /dev/null +++ b/403.html @@ -0,0 +1,109 @@ + + + + + + 403 - Forbidden | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
403
+

Access Denied

+

You don't have permission to access this resource.

+ +
+
+ + + + \ No newline at end of file diff --git a/404.html b/404.html new file mode 100644 index 0000000..7006511 --- /dev/null +++ b/404.html @@ -0,0 +1,109 @@ + + + + + + 404 - Page Not Found | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
404
+

Page Not Found

+

The page you're looking for doesn't exist.

+ +
+
+ + + + \ No newline at end of file diff --git a/422.html b/422.html new file mode 100644 index 0000000..3b573d8 --- /dev/null +++ b/422.html @@ -0,0 +1,109 @@ + + + + + + 422 - Unprocessable Entity | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
422
+

Unprocessable Entity

+

The request could not be processed due to semantic errors.

+ +
+
+ + + + \ No newline at end of file diff --git a/500.html b/500.html new file mode 100644 index 0000000..82acaaa --- /dev/null +++ b/500.html @@ -0,0 +1,109 @@ + + + + + + 500 - Internal Server Error | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
500
+

Internal Server Error

+

Something went wrong on our end.

+ +
+
+ + + + \ No newline at end of file diff --git a/502.html b/502.html new file mode 100644 index 0000000..a127296 --- /dev/null +++ b/502.html @@ -0,0 +1,109 @@ + + + + + + 502 - Bad Gateway | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
502
+

Bad Gateway

+

The server, while acting as a gateway or proxy, received an invalid response from the upstream server.

+ +
+
+ + + + \ No newline at end of file diff --git a/503.html b/503.html new file mode 100644 index 0000000..d41f4e8 --- /dev/null +++ b/503.html @@ -0,0 +1,109 @@ + + + + + + 503 - Service Unavailable | ArcaneNeko + + + + + + + + + + + + + + + +
+
+
+
503
+

Service Unavailable

+

The server is temporarily unable to handle the request. This is often due to maintenance or temporary overload.

+ +
+
+ + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index eab6767..0000000 --- a/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -MIT License - -Copyright (c) 2026 ArcaneNeko - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 749ab6a..e182a8e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,193 @@ -# Website +# ArcaneNeko Website +The official ArcaneNeko website - open source and available under the MIT License. + +## License + +MIT License - see [LICENSE](../LICENSE) for details. + +## Overview + +This is a static HTML/CSS/JS website showcasing ArcaneNeko's services and projects. It's designed to be simple, fast, and easily customizable. + +## Features + +- **Static HTML** — No frameworks, just clean semantic HTML +- **Responsive Design** — Works on mobile, tablet, and desktop +- **Theme System** — Three built-in themes: crimson (default), dark, light +- **Theme Toggle** — Users can switch between themes with persisted preference +- **Modular CSS** — Easy to add custom themes +- **No Dependencies** — Plain CSS and vanilla JavaScript +- **Accessible** — ARIA labels and keyboard navigation support +- **Self-contained Error Pages** — Error pages include header/footer and all CSS/JS + +## File Structure + +``` +ArcaneNekoWebsite/ +├── index.html # Main landing page +├── status.html # Arcane Status product page +├── privacy.html # Privacy policy +├── terms.html # Terms of service +├── contact.html # Contact page +├── coming-soon.html # Coming soon page +├── 400.html # Bad Request error page +├── 403.html # Forbidden error page +├── 404.html # Not Found error page +├── 422.html # Unprocessable Entity error page +├── 500.html # Internal Server Error page +├── 502.html # Bad Gateway error page +├── 503.html # Service Unavailable error page +├── favicon.svg # Favicon +├── robots.txt # Robots.txt +├── sitemap.xml # XML sitemap for search engines +├── .htaccess # Apache configuration +├── css/ +│ ├── index.css # Main CSS (imports all others) +│ ├── themes.css # Theme CSS variables +│ ├── base.css # Base reset and styles +│ ├── navbar.css # Navbar styles +│ ├── hero.css # Hero section styles +│ ├── buttons.css # Button styles +│ ├── stats.css # Stats bar styles +│ ├── about.css # About section styles +│ ├── sections.css # Generic section styles +│ ├── cards.css # Card & feature styles +│ ├── footer.css # Footer styles +│ ├── legal.css # Legal page styles +│ ├── contact.css # Contact page styles +│ ├── utility.css # Utility styles +│ └── responsive.css # Mobile/tablet breakpoints +├── js/ +│ ├── theme.js # Theme switching logic +│ └── main.js # Main initialization +└── README.md +``` + +## Error Pages + +The website includes 7 self-contained error pages: + +| Page | Description | +|------|-----------| +| `400.html` | Bad Request | +| `403.html` | Forbidden/Access Denied | +| `404.html` | Page Not Found | +| `422.html` | Unprocessable Entity | +| `500.html` | Internal Server Error | +| `502.html` | Bad Gateway | +| `503.html` | Service Unavailable | + +Each error page includes: +- Full website header (navbar with navigation links, theme toggle, mobile hamburger menu) +- Full website footer (brand, community links, services links, legal links) +- Embedded CSS (themes, navbar, footer, error content, responsive styles) +- Embedded JavaScript (theme switching, mobile menu) +- Theme selection that persists via localStorage +- Responsive design for all screen sizes + +The error pages are configured in `.htaccess` - see the [Apache Configuration](#apache-configuration) section below. + +## Customization + +### Creating a Custom Theme + +1. Edit `css/themes.css` to add your theme: + +```css +[data-theme="custom"] { + --bg: #your-bg-color; + --bg-alt: #your-bg-alt-color; + --accent: #your-accent-color; + /* ... add other variables */ +} +``` + +2. Update the `THEMES` array in `js/theme.js` to include your theme: + +```javascript +const THEMES = ['crimson', 'dark', 'light', 'custom']; +``` + +3. Add theme icons and labels in `js/theme.js`: + +```javascript +const THEME_ICONS = { + custom: '...', +}; + +const THEME_LABELS = { + custom: 'Switch to custom theme', +}; +``` + +### Adding New Pages + +1. Copy an existing page (e.g., `contact.html`) +2. Update the navbar links in all HTML files to include your new page +3. Add footer links in the same way + +### Modifying CSS + +Each CSS file contains specific component styles: +- **themes.css** - Theme variables +- **navbar.css** - Navbar and mobile menu +- **hero.css** - Hero section +- **buttons.css** - Button styles +- **cards.css** - Cards and features +- **footer.css** - Footer +- **legal.css** - Legal pages +- **contact.css** - Contact & coming soon + +## Apache Configuration + +The `.htaccess` file provides: + +### URL Rewriting +- Removes `.html` extension from URLs (e.g., `/about` instead of `/about.html`) + +### Custom Error Pages +- Maps HTTP errors to error pages: + - `400` → `/400` + - `403` → `/403` + - `404` → `/404` + - `500` → `/500` + - `502` → `/502` + - `503` → `/503` + +### Security +- Blocks access to hidden files (dotfiles) +- Blocks access to config/environment files (`.env`, `.config`, `.log`, etc.) +- Sets security headers (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy, Permissions-Policy) + +### Performance +- Static assets caching (1 year for images, fonts, CSS, JS) +- No cache for HTML documents +- Gzip compression for HTML, CSS, JS, text, fonts + +### Sitemap & Robots.txt +- `sitemap.xml` - XML sitemap for search engines +- `robots.txt` - Robots.txt allowing all crawlers and pointing to sitemap + +### HTTPS (Optional) +- Uncomment lines to force HTTPS redirect + +### Nginx Compatibility + +If using Nginx instead of Apache: +- These rules must be translated to Nginx config or handled upstream +- ErrorDocument directives need server-level configuration in Nginx +- Header directives need `add_header` in Nginx context +- Rewrite rules need `rewrite` directive in Nginx + +The `.htaccess` file contains notes for Nginx compatibility at the bottom. + +## Browser Support + +- Chrome/Edge 90+ +- Firefox 88+ +- Safari 14+ + +## Deployment + +Simply upload all files to any web server or static hosting service. No server-side code required. \ No newline at end of file diff --git a/coming-soon.html b/coming-soon.html new file mode 100644 index 0000000..f7d8bbc --- /dev/null +++ b/coming-soon.html @@ -0,0 +1,169 @@ + + + + + + Coming Soon | ArcaneNeko + + + + + + + + + + + + + +
+ + +
+
Coming Soon
+

Something Exciting Is Brewing

+

We're working on something new. Stay tuned for updates.

+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/contact.html b/contact.html new file mode 100644 index 0000000..f27b5e2 --- /dev/null +++ b/contact.html @@ -0,0 +1,206 @@ + + + + + + Contact Us | ArcaneNeko + + + + "> + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

How to reach us

+ +
+ +
+ +

General Enquiries

+

Questions about ArcaneNeko, our projects, or anything else? We'd love to hear from you.

+ + hello@arcaneneko.com → + +
+ +
+ +

Support

+

Need help with your Git account, Neovoxis, or any of our services? Support enquiries go here.

+ + support@arcaneneko.com → + +
+ +
+ +

Security Reports

+

Found a vulnerability? Please report it responsibly before public disclosure. We take all reports seriously.

+ + security@arcaneneko.com → + +
+ +
+ +

Abuse Reports

+

Report content or accounts that violate our Terms of Service, including harassment, spam, or illegal content.

+ + abuse@arcaneneko.com → + +
+ +
+ +

Legal & Privacy

+

Data access requests, GDPR/UK GDPR rights, or legal enquiries. See our Privacy Policy for your rights.

+ + legal@arcaneneko.com → + +
+ +
+ +

Community

+

Want to chat with us and the community in real time? Join us on Neovoxis, it's our own platform and we're active there.

+ + Join Neovoxis → + +
+ +
+ +

+ Response times: We're a small, volunteer-run team. We aim to reply to all emails within a few days. Security reports are prioritised and will receive a response within 48 hours where possible. We don't have a support ticket system, a plain email is all you need. +

+ +
+
+
+ + + + + + + + + + diff --git a/css/about.css b/css/about.css new file mode 100644 index 0000000..785e7c6 --- /dev/null +++ b/css/about.css @@ -0,0 +1,42 @@ +/* + * About Section Styles + */ + +.about { + padding: 8rem 0; +} + +.about-inner { + max-width: 680px; + margin: 0 auto; + text-align: center; +} + +.about-eyebrow { + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 1rem; + display: block; +} + +.about h2 { + font-size: 2.5rem; + font-weight: 800; + letter-spacing: -1px; + margin-bottom: 1.75rem; + color: var(--text); +} + +.about p { + color: var(--text-muted); + font-size: 1.05rem; + line-height: 1.85; + margin-bottom: 1rem; +} + +.about p:last-child { + margin-bottom: 0; +} diff --git a/css/base.css b/css/base.css new file mode 100644 index 0000000..67b90a5 --- /dev/null +++ b/css/base.css @@ -0,0 +1,57 @@ +/* + * Base Styles - Reset and foundational styles + */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + font-family: 'Inter', 'Segoe UI', system-ui, sans-serif; + background-color: var(--bg); + color: var(--text); + line-height: 1.6; + overflow-x: hidden; + transition: background-color 0.3s ease, color 0.3s ease; +} + +.container { + max-width: 1100px; + margin: 0 auto; + padding: 0 2rem; +} + +a { + color: var(--accent); + text-decoration: none; +} + +a:hover { + text-decoration: underline; + color: var(--accent-light); +} + +.skip-link { + position: absolute; + left: 1rem; + top: -3rem; + z-index: 2000; + background: var(--accent); + color: #fff; + text-decoration: none; + font-weight: 700; + padding: 0.75rem 1rem; + border-radius: 10px; + box-shadow: 0 8px 24px var(--accent-glow); + transition: top 0.2s ease; +} + +.skip-link:focus { + top: 1rem; +} diff --git a/css/buttons.css b/css/buttons.css new file mode 100644 index 0000000..33777d8 --- /dev/null +++ b/css/buttons.css @@ -0,0 +1,67 @@ +/* + * Button Styles + */ + +.btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.875rem 2rem; + background: var(--accent); + color: #fff; + text-decoration: none; + border-radius: 10px; + font-weight: 600; + font-size: 0.95rem; + transition: all 0.25s ease; + box-shadow: 0 4px 24px var(--accent-glow); + border: none; + cursor: pointer; +} + +.btn:hover { + background: var(--accent-light); + transform: translateY(-2px); + box-shadow: 0 8px 32px var(--accent-glow); + color: #fff; + text-decoration: none; +} + +.btn-outline { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.875rem 2rem; + background: var(--bg-card); + border: 1px solid var(--glass-border); + color: var(--text-2); + text-decoration: none; + border-radius: 10px; + font-weight: 600; + font-size: 0.95rem; + transition: all 0.25s ease; + backdrop-filter: blur(10px); + cursor: pointer; +} + +.btn-outline:hover { + border-color: var(--accent); + color: var(--accent-light); + background: var(--bg-card-hover); + transform: translateY(-2px); + box-shadow: 0 4px 16px var(--accent-glow-sm); + text-decoration: none; +} + +a:focus-visible, +button:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; + border-radius: 4px; +} + +.btn:focus-visible, +.btn-outline:focus-visible { + outline: 2px solid var(--accent-light); + outline-offset: 3px; +} diff --git a/css/cards.css b/css/cards.css new file mode 100644 index 0000000..175cc20 --- /dev/null +++ b/css/cards.css @@ -0,0 +1,171 @@ +/* + * Card Styles + */ + +.card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 1.5rem; +} + +.card { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 20px; + padding: 2.5rem; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + box-shadow: + 0 4px 24px var(--shadow-deep), + inset 0 1px 0 var(--inset-shine); + transition: all 0.35s ease; + position: relative; + overflow: hidden; +} + +.card::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + opacity: 0; + transition: opacity 0.3s ease; +} + +.card:hover { + border-color: var(--glass-border-hover); + transform: translateY(-6px); + box-shadow: + 0 20px 48px var(--shadow-deep), + 0 0 0 1px var(--accent-glow-sm), + inset 0 1px 0 var(--inset-shine); +} + +.card:hover::after { + opacity: 1; +} + +.card-icon { + width: 52px; + height: 52px; + background: linear-gradient(135deg, var(--accent-dark) 0%, var(--accent) 100%); + border-radius: 14px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 1.5rem; + box-shadow: 0 4px 16px var(--accent-glow); +} + +.card-icon svg { + width: 24px; + height: 24px; + stroke: #fff; +} + +.card .badge { + display: inline-block; + padding: 0.3rem 0.85rem; + background: var(--accent-glow-sm); + border: 1px solid var(--accent-glow); + color: var(--accent-light); + font-size: 0.7rem; + font-weight: 700; + border-radius: 6px; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-bottom: 1.25rem; +} + +.card h3 { + font-size: 1.4rem; + font-weight: 700; + margin-bottom: 0.75rem; + color: var(--text); + letter-spacing: -0.3px; +} + +.card p { + color: var(--text-muted); + font-size: 0.95rem; + line-height: 1.8; + margin-bottom: 2rem; +} + +.card-link { + color: var(--accent); + text-decoration: none; + font-weight: 600; + font-size: 0.9rem; + display: inline-flex; + align-items: center; + gap: 0.4rem; + transition: all 0.2s; +} + +.card-link:hover { + color: var(--accent-light); + gap: 0.8rem; + text-decoration: none; +} + +/* Feature cards */ +.feature-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); + gap: 1.5rem; +} + +.feature-card { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 16px; + padding: 2rem; + backdrop-filter: blur(16px); + transition: all 0.3s ease; +} + +.feature-card:hover { + border-color: var(--glass-border-hover); + transform: translateY(-4px); +} + +.feature-card h3 { + font-size: 1.15rem; + font-weight: 700; + color: var(--accent); + margin-bottom: 0.6rem; +} + +.feature-card p { + color: var(--text-muted); + font-size: 0.9rem; + line-height: 1.7; +} + +/* Scroll reveal */ +.reveal { + opacity: 0; + transform: translateY(28px) scale(0.98); + transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); +} + +.reveal.visible { + opacity: 1; + transform: translateY(0) scale(1); +} + +.reveal:nth-child(2) { transition-delay: 0.12s; } +.reveal:nth-child(3) { transition-delay: 0.24s; } +.reveal:nth-child(4) { transition-delay: 0.36s; } + +@media (prefers-reduced-motion: reduce) { + .reveal { + opacity: 1; + transform: none; + transition: none; + } +} diff --git a/css/contact.css b/css/contact.css new file mode 100644 index 0000000..ec1b4f5 --- /dev/null +++ b/css/contact.css @@ -0,0 +1,143 @@ +/* + * Contact Page Styles + */ + +.contact-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1.5rem; + margin-bottom: 4rem; +} + +.contact-card { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 20px; + padding: 2rem; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.contact-card::after { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + opacity: 0; + transition: opacity 0.3s; +} + +.contact-card:hover { + border-color: var(--glass-border-hover); + transform: translateY(-4px); + box-shadow: 0 16px 40px var(--shadow-deep); +} + +.contact-card:hover::after { opacity: 1; } + +.contact-card-icon { + width: 44px; + height: 44px; + background: linear-gradient(135deg, var(--accent-dark) 0%, var(--accent) 100%); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 1.25rem; + box-shadow: 0 4px 12px var(--accent-glow); +} + +.contact-card-icon svg { + width: 20px; + height: 20px; + stroke: #fff; +} + +.contact-card h3 { + font-size: 1.1rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.5rem; +} + +.contact-card p { + color: var(--text-muted); + font-size: 0.9rem; + line-height: 1.65; + margin-bottom: 1.25rem; +} + +.contact-card a.contact-email { + display: inline-flex; + align-items: center; + gap: 0.4rem; + color: var(--accent); + text-decoration: none; + font-weight: 600; + font-size: 0.9rem; + transition: all 0.2s; +} + +.contact-card a.contact-email:hover { + color: var(--accent-light); + gap: 0.7rem; +} + +.contact-note { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-left: 3px solid var(--accent); + border-radius: 0 12px 12px 0; + padding: 1.25rem 1.5rem; + color: var(--text-muted); + font-size: 0.9rem; + line-height: 1.7; +} + +.contact-note strong { + color: var(--text-2); +} + +/* Coming soon */ +.coming-soon-hero { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + position: relative; + padding: 8rem 2rem 6rem; + overflow: hidden; +} + +.coming-soon-content { + position: relative; + z-index: 1; + max-width: 600px; +} + +.coming-soon-badge { + display: inline-block; + padding: 0.5rem 1.25rem; + background: var(--accent-glow-sm); + border: 1px solid var(--accent-glow); + color: var(--accent-light); + font-size: 0.75rem; + font-weight: 700; + border-radius: 100px; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-bottom: 2rem; +} + +.coming-soon-cta { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; + margin-top: 2.5rem; +} diff --git a/css/footer.css b/css/footer.css new file mode 100644 index 0000000..6f0bc51 --- /dev/null +++ b/css/footer.css @@ -0,0 +1,107 @@ +/* + * Footer Styles + */ + +.footer { + padding: 5rem 0 2.5rem; + border-top: 1px solid var(--divider); +} + +.footer-inner { + display: grid; + grid-template-columns: 1fr auto auto; + gap: 4rem; + margin-bottom: 3.5rem; + align-items: start; +} + +.footer-logo { + font-size: 1.35rem; + font-weight: 800; + color: var(--text); + letter-spacing: -0.5px; + display: block; + margin-bottom: 0.6rem; + text-decoration: none; +} + +.footer-logo span { + color: var(--accent); +} + +.footer-brand p { + color: var(--text-muted); + font-size: 0.9rem; + max-width: 260px; + line-height: 1.7; +} + +.footer-links-col { + display: flex; + flex-direction: column; + gap: 0.5rem; + min-width: 140px; +} + +.footer-links-col h4 { + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--text-muted); + margin-bottom: 0.75rem; +} + +.footer-links-col a { + color: var(--text-2); + text-decoration: none; + font-size: 0.9rem; + font-weight: 500; + transition: color 0.2s; +} + +.footer-links-col a:hover { + color: var(--accent-light); +} + +.footer-bottom { + padding-top: 2rem; + border-top: 1px solid var(--divider); +} + +.footer-bottom p { + color: var(--text-muted); + font-size: 0.85rem; +} + +/* Footer community links */ +.footer-community { + display: flex; + gap: 0.75rem; + margin-top: 1rem; +} + +.footer-community a { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 8px; + color: var(--text-muted); + text-decoration: none; + transition: all 0.2s; +} + +.footer-community a:hover { + border-color: var(--accent-glow); + color: var(--accent-light); + background: var(--bg-card-hover); +} + +.footer-community svg { + width: 16px; + height: 16px; +} diff --git a/css/hero.css b/css/hero.css new file mode 100644 index 0000000..bd96176 --- /dev/null +++ b/css/hero.css @@ -0,0 +1,118 @@ +/* + * Hero Styles + */ + +.hero { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + position: relative; + padding: 8rem 2rem 6rem; + overflow: hidden; +} + +.hero-bg { + position: absolute; + inset: 0; + background: + radial-gradient(ellipse 90% 65% at 50% -5%, var(--hero-glow-1) 0%, transparent 55%), + radial-gradient(ellipse 50% 40% at 85% 85%, var(--hero-glow-2) 0%, transparent 55%), + radial-gradient(ellipse 40% 35% at 10% 80%, var(--hero-glow-2) 0%, transparent 55%), + var(--bg); + z-index: 0; +} + +.hero-grid { + position: absolute; + inset: 0; + background-image: radial-gradient(circle, var(--accent-glow-sm) 1px, transparent 1px); + background-size: 48px 48px; + opacity: 0; + animation: gridFadeIn 2s ease 0.4s forwards, gridDrift 40s ease-in-out 2.4s infinite; + pointer-events: none; + -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, black 20%, transparent 80%); + mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, black 20%, transparent 80%); +} + +.hero-content { + position: relative; + z-index: 1; + max-width: 820px; + animation: heroEntrance 0.9s cubic-bezier(0.22, 1, 0.36, 1) both; +} + +.hero-tag { + display: inline-block; + padding: 0.4rem 1.1rem; + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 100px; + font-size: 0.75rem; + font-weight: 600; + color: var(--text-muted); + letter-spacing: 0.08em; + text-transform: uppercase; + margin-bottom: 2rem; + backdrop-filter: blur(10px); +} + +.hero h1 { + font-size: 5.5rem; + font-weight: 900; + line-height: 1; + letter-spacing: -3px; + color: var(--text); + margin-bottom: 1.5rem; +} + +.hero h1 span { + color: var(--accent); + filter: drop-shadow(0 0 28px var(--accent-glow)); +} + +.hero-subtitle { + font-size: 1.2rem; + color: var(--text-muted); + max-width: 520px; + margin: 0 auto 2.75rem; + line-height: 1.75; +} + +.hero-cta { + display: flex; + gap: 1.25rem; + justify-content: center; + flex-wrap: wrap; + align-items: center; +} + +/* Hero animation keyframes */ +@keyframes gridFadeIn { + to { opacity: 0.35; } +} + +@keyframes gridDrift { + 0%, 100% { transform: translate(0, 0); } + 33% { transform: translate(6px, -8px); } + 66% { transform: translate(-6px, 4px); } +} + +@keyframes heroEntrance { + from { opacity: 0; transform: translateY(24px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Reduced motion - hero */ +@media (prefers-reduced-motion: reduce) { + .hero-grid { + animation: none; + opacity: 0.2; + } + .hero-content { + animation: none; + opacity: 1; + transform: none; + } +} diff --git a/css/index.css b/css/index.css new file mode 100644 index 0000000..7de5d6b --- /dev/null +++ b/css/index.css @@ -0,0 +1,46 @@ +/* + * ArcaneNeko Website Styles + * Import order matters - later files can override earlier ones + */ + +/* Theme variables (must come first) */ +@import url('./themes.css'); + +/* Base styles */ +@import url('./base.css'); + +/* Navbar */ +@import url('./navbar.css'); + +/* Hero */ +@import url('./hero.css'); + +/* Buttons */ +@import url('./buttons.css'); + +/* Stats */ +@import url('./stats.css'); + +/* About */ +@import url('./about.css'); + +/* Sections */ +@import url('./sections.css'); + +/* Cards */ +@import url('./cards.css'); + +/* Footer */ +@import url('./footer.css'); + +/* Legal pages */ +@import url('./legal.css'); + +/* Contact & Coming Soon */ +@import url('./contact.css'); + +/* Utilities */ +@import url('./utility.css'); + +/* Responsive (must come last) */ +@import url('./responsive.css'); diff --git a/css/legal.css b/css/legal.css new file mode 100644 index 0000000..d0af4df --- /dev/null +++ b/css/legal.css @@ -0,0 +1,432 @@ +/* + * Legal Page Styles + */ + +/* Hero */ +.legal-hero { + padding: 9rem 2rem 4rem; + background: + radial-gradient(ellipse 70% 50% at 50% -10%, var(--hero-glow-1) 0%, transparent 55%), + var(--bg); + border-bottom: 1px solid var(--divider); + text-align: center; +} + +.legal-hero .legal-tag { + display: inline-block; + padding: 0.35rem 1rem; + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 100px; + font-size: 0.75rem; + font-weight: 600; + color: var(--text-muted); + letter-spacing: 0.08em; + text-transform: uppercase; + margin-bottom: 1.25rem; +} + +.legal-hero h1 { + font-size: 2.75rem; + font-weight: 900; + letter-spacing: -1.5px; + margin-bottom: 0.75rem; + color: var(--text); +} + +.legal-hero h1 span { + color: var(--accent); +} + +.legal-hero .legal-meta { + color: var(--text-muted); + font-size: 0.9rem; + margin-bottom: 0; +} + +/* Layout */ +.legal-wrap { + display: grid; + grid-template-columns: 220px 1fr; + gap: 4rem; + max-width: 1100px; + margin: 0 auto; + padding: 4rem 2rem 6rem; + align-items: start; +} + +/* TOC */ +.legal-toc { + position: sticky; + top: 90px; +} + +.legal-toc h4 { + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--text-muted); + margin-bottom: 1rem; +} + +.legal-toc ul { + list-style: none; + display: flex; + flex-direction: column; + gap: 0.15rem; +} + +.legal-toc a { + display: block; + color: var(--text-muted); + text-decoration: none; + font-size: 0.85rem; + font-weight: 500; + padding: 0.45rem 0.75rem; + border-radius: 7px; + border-left: 2px solid transparent; + transition: all 0.2s; + line-height: 1.4; +} + +.legal-toc a:hover, +.legal-toc a.active { + color: var(--accent-light); + background: var(--bg-card); + border-left-color: var(--accent); +} + +/* Content */ +.legal-content { + min-width: 0; + scroll-margin-top: 90px; +} + +.legal-section { + margin-bottom: 3.5rem; + padding-bottom: 3.5rem; + border-bottom: 1px solid var(--divider); + scroll-margin-top: 92px; +} + +.legal-section:last-child { + border-bottom: none; + margin-bottom: 0; + padding-bottom: 0; +} + +.legal-section h2 { + font-size: 1.4rem; + font-weight: 700; + color: var(--text); + margin-bottom: 1.25rem; + letter-spacing: -0.3px; + display: flex; + align-items: center; + gap: 0.75rem; +} + +.legal-section h2 .section-num { + font-size: 0.75rem; + font-weight: 700; + color: var(--accent); + background: var(--accent-glow-sm); + border: 1px solid var(--accent-glow); + border-radius: 5px; + padding: 0.2rem 0.55rem; + letter-spacing: 0; + flex-shrink: 0; +} + +.legal-section h3 { + font-size: 1.05rem; + font-weight: 700; + color: var(--text); + margin: 1.75rem 0 0.6rem; +} + +.legal-section p { + color: var(--text-2); + font-size: 0.98rem; + line-height: 1.85; + margin-bottom: 1rem; +} + +.legal-section p:last-child { + margin-bottom: 0; +} + +.legal-section ul, +.legal-section ol { + color: var(--text-2); + font-size: 0.98rem; + line-height: 1.85; + padding-left: 1.5rem; + margin-bottom: 1rem; +} + +.legal-section ul li, +.legal-section ol li { + margin-bottom: 0.4rem; +} + +.legal-section a { + color: var(--accent); + text-decoration: none; +} + +.legal-section a:hover { + text-decoration: underline; + color: var(--accent-light); +} + +/* Callouts */ +.callout { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 12px; + padding: 1.25rem 1.5rem; + margin: 1.5rem 0; + backdrop-filter: blur(10px); +} + +.callout.callout--info { + border-left: 3px solid var(--accent); +} + +.callout.callout--lock { + border-left: 3px solid #22c55e; +} + +.callout .callout-title { + font-size: 0.8rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; + margin-bottom: 0.5rem; +} + +.callout.callout--info .callout-title { color: var(--accent); } +.callout.callout--lock .callout-title { color: #22c55e; } + +.callout p { + margin-bottom: 0 !important; + font-size: 0.9rem !important; +} + +/* Data table */ +.data-table { + width: 100%; + border-collapse: collapse; + margin: 1.25rem 0; + font-size: 0.875rem; +} + +.data-table th { + text-align: left; + padding: 0.75rem 1rem; + background: var(--bg-card); + color: var(--text-muted); + font-size: 0.72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; + border-bottom: 1px solid var(--divider); +} + +.data-table th:first-child { border-radius: 8px 0 0 0; } +.data-table th:last-child { border-radius: 0 8px 0 0; } + +.data-table td { + padding: 0.85rem 1rem; + color: var(--text-2); + border-bottom: 1px solid var(--divider); + vertical-align: top; + line-height: 1.6; +} + +.data-table tr:last-child td { border-bottom: none; } + +.data-table td:first-child { + font-weight: 600; + white-space: nowrap; +} + +/* Section kicker */ +.section-kicker { + display: inline-block; + margin-bottom: 0.75rem; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--accent); +} + +.legal-at-a-glance, +.legal-overview { + margin-bottom: 3.5rem; +} + +.legal-at-a-glance h2, +.legal-overview h2 { + font-size: 1.65rem; + letter-spacing: -0.4px; + margin-bottom: 1rem; +} + +/* Summary/Comparison grids */ +.summary-grid, +.comparison-grid, +.action-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1rem; +} + +.summary-card, +.comparison-card, +.action-card { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 16px; + padding: 1.15rem 1.1rem; + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: 0 8px 24px var(--shadow-deep), inset 0 1px 0 var(--inset-shine); +} + +.summary-card h3, +.comparison-card h3, +.action-card strong { + color: var(--text); + font-size: 1rem; + margin-bottom: 0.45rem; + display: block; +} + +.summary-card p, +.comparison-card p, +.action-card p { + color: var(--text-2); + font-size: 0.92rem; + line-height: 1.7; + margin: 0; +} + +.comparison-card h3, +.summary-card h3 { + margin-top: 0; +} + +.answer-strip { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.9rem; + margin: 1.1rem 0 0; +} + +.answer-strip > div { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 12px; + padding: 0.9rem 1rem; +} + +.answer-strip strong { + display: block; + color: var(--text); + font-size: 0.88rem; + margin-bottom: 0.25rem; +} + +.answer-strip span, +.answer-strip a { + color: var(--text-2); + font-size: 0.88rem; + line-height: 1.55; +} + +.mini-summary { + margin: 0 0 1rem; + padding: 0.95rem 1rem; + border-radius: 12px; + background: linear-gradient(180deg, var(--bg-card), transparent), var(--bg-card); + border: 1px solid var(--glass-border); + color: var(--text-2); + line-height: 1.7; +} + +.mini-summary strong { + color: var(--text); +} + +.action-card { + text-decoration: none; + transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease; +} + +.action-card:hover { + transform: translateY(-2px); + border-color: var(--glass-border-hover); + background: var(--bg-card-hover); +} + +.action-label { + display: inline-block; + margin-bottom: 0.5rem; + font-size: 0.74rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--accent); +} + +/* TOC toggle */ +.legal-toc-toggle { + display: none; + width: 100%; + align-items: center; + justify-content: space-between; + background: var(--bg-card); + border: 1px solid var(--glass-border); + color: var(--text); + border-radius: 12px; + padding: 0.95rem 1rem; + font: inherit; + font-weight: 700; + cursor: pointer; +} + +.legal-toc-panel { + display: block; +} + +.legal-toc-toggle::after { + content: '\25BE'; + color: var(--accent); + font-size: 0.95rem; + transition: transform 0.2s ease; +} + +.legal-toc-toggle[aria-expanded="true"]::after { + transform: rotate(180deg); +} + +/* Demo section */ +.demo { + padding: 8rem 0; + text-align: center; +} + +.demo-desc { + color: var(--text-muted); + margin-bottom: 2.5rem; + font-size: 1.1rem; +} + +.features { + padding: 8rem 0; + background: var(--bg-alt); +} diff --git a/css/navbar.css b/css/navbar.css new file mode 100644 index 0000000..b9904bf --- /dev/null +++ b/css/navbar.css @@ -0,0 +1,162 @@ +/* + * Navbar Styles + */ + +.navbar { + position: fixed; + top: 0; + left: 0; + right: 0; + background: var(--nav-bg); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border-bottom: 1px solid var(--nav-border); + z-index: 1000; +} + +.nav-container { + max-width: 1100px; + margin: 0 auto; + padding: 0.9rem 2rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.nav-logo { + font-size: 1.35rem; + font-weight: 800; + color: var(--text); + text-decoration: none; + letter-spacing: -0.5px; +} + +.nav-logo span { + color: var(--accent); +} + +.nav-links { + display: flex; + list-style: none; + gap: 2.25rem; +} + +.nav-links a { + color: var(--text-muted); + text-decoration: none; + font-weight: 500; + font-size: 0.9rem; + transition: color 0.2s; + position: relative; +} + +.nav-links a::after { + content: ''; + position: absolute; + bottom: -4px; + left: 0; + width: 0; + height: 2px; + background: var(--accent); + border-radius: 2px; + transition: width 0.25s ease; + box-shadow: 0 0 8px var(--accent-glow); +} + +.nav-links a:hover { + color: var(--text); +} + +.nav-links a:hover::after { + width: 100%; +} + +.nav-actions { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.theme-toggle { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 8px; + padding: 0; + cursor: pointer; + color: var(--text-muted); + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + width: 36px; + height: 36px; + flex-shrink: 0; +} + +.theme-toggle:hover { + color: var(--accent); + border-color: var(--accent-glow); + background: var(--bg-card-hover); + box-shadow: 0 0 12px var(--accent-glow-sm); +} + +.theme-toggle svg { + width: 16px; + height: 16px; +} + +.hamburger { + display: none; + flex-direction: column; + gap: 5px; + background: none; + border: none; + cursor: pointer; + padding: 4px; +} + +.hamburger span { + display: block; + width: 22px; + height: 2px; + background: var(--text-2); + border-radius: 2px; + transition: all 0.3s ease; +} + +.hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); } +.hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); } +.hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); } + +.mobile-menu { + display: none; + flex-direction: column; + border-top: 1px solid var(--nav-border); + background: var(--nav-bg); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); +} + +.mobile-menu.open { + display: flex; +} + +.mobile-menu a { + color: var(--text-2); + text-decoration: none; + font-size: 1rem; + font-weight: 500; + padding: 1rem 2rem; + border-bottom: 1px solid var(--divider); + transition: all 0.2s; +} + +.mobile-menu a:last-child { + border-bottom: none; +} + +.mobile-menu a:hover { + color: var(--accent); + background: var(--bg-card); + padding-left: 2.5rem; +} diff --git a/css/responsive.css b/css/responsive.css new file mode 100644 index 0000000..8b59bb8 --- /dev/null +++ b/css/responsive.css @@ -0,0 +1,146 @@ +/* + * Responsive Styles - Mobile/tablet breakpoints + */ + +@media (max-width: 768px) { + .nav-links { + display: none; + } + + .hamburger { + display: flex; + } + + .hero h1 { + font-size: 3.5rem; + letter-spacing: -2px; + } + + .hero-subtitle { + font-size: 1rem; + } + + .stats-grid { + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; + } + + .about h2, + .section-title { + font-size: 2rem; + } + + .card-grid { + grid-template-columns: 1fr; + } + + .footer-inner { + grid-template-columns: 1fr 1fr; + gap: 2rem; + } + + .footer-brand { + grid-column: 1 / -1; + } + + /* Legal pages */ + .legal-wrap { + grid-template-columns: 1fr; + } + + .legal-toc { + position: static; + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 12px; + padding: 1.25rem 1.5rem; + } + + .legal-toc ul { + flex-direction: row; + flex-wrap: wrap; + gap: 0.35rem; + } + + .legal-toc a { + border-left: none; + border-bottom: 2px solid transparent; + padding: 0.3rem 0.5rem; + font-size: 0.8rem; + } + + .legal-toc a:hover, + .legal-toc a.active { + border-left-color: transparent; + border-bottom-color: var(--accent); + } + + .data-table { + display: block; + overflow-x: auto; + } + + .summary-grid, + .comparison-grid, + .action-grid, + .answer-strip { + grid-template-columns: 1fr; + } + + .legal-toc { + padding: 0; + background: transparent; + border: none; + } + + .legal-toc-toggle { + display: flex; + } + + .legal-toc-panel { + display: none; + margin-top: 0.75rem; + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: 12px; + padding: 1rem; + } + + .legal-toc.open .legal-toc-panel { + display: block; + } + + .legal-toc ul { + flex-direction: column; + gap: 0.2rem; + } + + .legal-toc a { + border-bottom: none; + padding: 0.5rem 0.6rem; + font-size: 0.88rem; + } + + .legal-hero h1 { + font-size: 2rem; + letter-spacing: -1px; + } +} + +@media (max-width: 480px) { + .hero h1 { + font-size: 2.75rem; + letter-spacing: -1.5px; + } + + .hero-cta { + flex-direction: column; + align-items: center; + } + + .btn, + .btn-outline { + width: 100%; + justify-content: center; + } +} diff --git a/css/sections.css b/css/sections.css new file mode 100644 index 0000000..0952447 --- /dev/null +++ b/css/sections.css @@ -0,0 +1,53 @@ +/* + * Generic Section Styles + */ + +.section { + padding: 6rem 0; + position: relative; +} + +.alt-bg { + background: var(--bg-alt); +} + +.alt-bg::before, +.section::before { + content: ''; + position: absolute; + top: 0; + left: 5%; + right: 5%; + height: 1px; + background: linear-gradient(90deg, transparent, var(--divider), transparent); +} + +.section-label { + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--accent); + display: block; + margin-bottom: 0.75rem; +} + +.section-title { + font-size: 2.5rem; + font-weight: 800; + letter-spacing: -1px; + margin-bottom: 3rem; + color: var(--text); + position: relative; +} + +.section-title::after { + content: ''; + display: block; + width: 36px; + height: 3px; + background: var(--accent); + border-radius: 2px; + margin-top: 0.85rem; + box-shadow: 0 0 12px var(--accent-glow); +} diff --git a/css/stats.css b/css/stats.css new file mode 100644 index 0000000..da5adaf --- /dev/null +++ b/css/stats.css @@ -0,0 +1,59 @@ +/* + * Stats Bar Styles + */ + +.stats-bar { + background: var(--stats-bg); + border-top: 1px solid var(--stats-border); + border-bottom: 1px solid var(--stats-border); + padding: 1.25rem 0; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0.75rem; + text-align: center; +} + +.stat { + display: flex; + flex-direction: column; + gap: 0.15rem; +} + +.stat-value { + font-size: 1.6rem; + font-weight: 900; + color: var(--accent); + letter-spacing: -0.5px; + line-height: 1; +} + +.stat-label { + font-size: 0.75rem; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.1em; + margin-top: 0.25rem; +} + +.stat { + animation: statPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both; + animation-play-state: paused; +} + +.stat.animated { + animation-play-state: running; +} + +.stat:nth-child(1) { animation-delay: 0s; } +.stat:nth-child(2) { animation-delay: 0.1s; } +.stat:nth-child(3) { animation-delay: 0.2s; } +.stat:nth-child(4) { animation-delay: 0.3s; } + +@keyframes statPop { + from { opacity: 0; transform: translateY(12px) scale(0.9); } + to { opacity: 1; transform: translateY(0) scale(1); } +} diff --git a/css/themes.css b/css/themes.css new file mode 100644 index 0000000..6803ba3 --- /dev/null +++ b/css/themes.css @@ -0,0 +1,82 @@ +/* + * Theme Variables - Edit these to create new themes + */ + +:root, +[data-theme="crimson"] { + --bg: #07040a; + --bg-alt: #0d070c; + --bg-card: rgba(255, 255, 255, 0.04); + --bg-card-hover: rgba(255, 255, 255, 0.07); + --glass-border: rgba(255, 255, 255, 0.08); + --glass-border-hover: rgba(220, 20, 60, 0.45); + --accent: #dc143c; + --accent-light: #ff1744; + --accent-dark: #960f2c; + --accent-glow: rgba(220, 20, 60, 0.35); + --accent-glow-sm: rgba(220, 20, 60, 0.18); + --text: #ffffff; + --text-2: #ddd0d4; + --text-muted: #8c7a80; + --nav-bg: rgba(7, 4, 10, 0.85); + --nav-border: rgba(255, 255, 255, 0.06); + --stats-bg: rgba(220, 20, 60, 0.07); + --stats-border: rgba(220, 20, 60, 0.18); + --divider: rgba(255, 255, 255, 0.06); + --shadow-deep: rgba(0, 0, 0, 0.6); + --inset-shine: rgba(255, 255, 255, 0.04); + --hero-glow-1: rgba(220, 20, 60, 0.22); + --hero-glow-2: rgba(220, 20, 60, 0.1); +} + +[data-theme="dark"] { + --bg: #080808; + --bg-alt: #0f0f0f; + --bg-card: rgba(255, 255, 255, 0.04); + --bg-card-hover: rgba(255, 255, 255, 0.07); + --glass-border: rgba(255, 255, 255, 0.08); + --glass-border-hover: rgba(255, 255, 255, 0.22); + --accent: #dc143c; + --accent-light: #ff1744; + --accent-dark: #960f2c; + --accent-glow: rgba(220, 20, 60, 0.28); + --accent-glow-sm: rgba(220, 20, 60, 0.1); + --text: #ffffff; + --text-2: #c8c8c8; + --text-muted: #707070; + --nav-bg: rgba(8, 8, 8, 0.88); + --nav-border: rgba(255, 255, 255, 0.07); + --stats-bg: rgba(255, 255, 255, 0.03); + --stats-border: rgba(255, 255, 255, 0.08); + --divider: rgba(255, 255, 255, 0.07); + --shadow-deep: rgba(0, 0, 0, 0.7); + --inset-shine: rgba(255, 255, 255, 0.03); + --hero-glow-1: rgba(220, 20, 60, 0.1); + --hero-glow-2: rgba(220, 20, 60, 0.04); +} + +[data-theme="light"] { + --bg: #f5f4f6; + --bg-alt: #eeecef; + --bg-card: rgba(255, 255, 255, 0.72); + --bg-card-hover: rgba(255, 255, 255, 0.95); + --glass-border: rgba(0, 0, 0, 0.08); + --glass-border-hover: rgba(192, 18, 48, 0.35); + --accent: #c0122e; + --accent-light: #e0153a; + --accent-dark: #8b0020; + --accent-glow: rgba(192, 18, 48, 0.22); + --accent-glow-sm: rgba(192, 18, 48, 0.1); + --text: #0d0a0e; + --text-2: #2e2830; + --text-muted: #6a6068; + --nav-bg: rgba(245, 244, 246, 0.88); + --nav-border: rgba(0, 0, 0, 0.08); + --stats-bg: rgba(192, 18, 48, 0.06); + --stats-border: rgba(192, 18, 48, 0.16); + --divider: rgba(0, 0, 0, 0.07); + --shadow-deep: rgba(0, 0, 0, 0.1); + --inset-shine: rgba(255, 255, 255, 0.8); + --hero-glow-1: rgba(192, 18, 48, 0.12); + --hero-glow-2: rgba(192, 18, 48, 0.06); +} diff --git a/css/utility.css b/css/utility.css new file mode 100644 index 0000000..f60aa31 --- /dev/null +++ b/css/utility.css @@ -0,0 +1,92 @@ +/* + * Utility Styles - Back to top, scroll progress, focus states, etc. + */ + +/* Back to top button */ +.back-to-top { + position: fixed; + bottom: 2rem; + right: 2rem; + width: 44px; + height: 44px; + min-width: 44px; + min-height: 44px; + background: var(--accent); + border: none; + border-radius: 10px; + color: #fff; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transform: translateY(12px); + transition: opacity 0.3s ease, transform 0.3s ease, background 0.2s; + pointer-events: none; + box-shadow: 0 4px 20px var(--accent-glow); + z-index: 900; +} + +.back-to-top.visible { + opacity: 1; + transform: translateY(0); + pointer-events: auto; +} + +.back-to-top:hover { + background: var(--accent-light); + transform: translateY(-3px); + box-shadow: 0 8px 28px var(--accent-glow); +} + +.back-to-top:focus-visible { + outline: 2px solid var(--accent-light); + outline-offset: 3px; +} + +/* Scroll progress bar */ +.scroll-progress { + position: fixed; + top: 0; + left: 0; + height: 3px; + width: 0%; + background: linear-gradient(90deg, var(--accent-dark), var(--accent), var(--accent-light)); + z-index: 1100; + box-shadow: 0 0 10px var(--accent-glow); + transition: width 0.08s linear; + pointer-events: none; +} + +/* Touch targets */ +.theme-toggle, +.hamburger { + min-width: 44px; + min-height: 44px; + width: 44px; + height: 44px; +} + +.theme-toggle { + border-radius: 10px; +} + +/* Reduced motion */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .stat { + animation: none; + opacity: 1; + } + + .back-to-top { + transition: opacity 0.01ms; + } +} diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 0000000..490ae45 --- /dev/null +++ b/favicon.svg @@ -0,0 +1,12 @@ + + + A + diff --git a/index.html b/index.html new file mode 100644 index 0000000..e6cc234 --- /dev/null +++ b/index.html @@ -0,0 +1,223 @@ + + + + + + ArcaneNeko | Open Source Software & Services + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

ArcaneNeko

+

Building free, open source tools for developers and creators, no strings attached.

+ +
+
+ + +
+
+
+
+ 100% + Free +
+
+ Open + Source +
+
+ MIT + Licensed +
+
+ 0 + Paywalls* +
+
+
+

* Neovoxis hosted instance may include paid features. Self-hosted instances include all features free.

+
+ + +
+
+
+ Who we are +

Software for everyone

+

ArcaneNeko is a small team building free, open source software for developers and the broader tech community. We believe software should be accessible to everyone.

+

From git hosting to status pages and a modern communication platform, every project we ship is open for anyone to use, contribute to, or self-host.

+
+
+
+ + +
+
+ +

What we offer

+
+ +
+ +

Git Hosting

+

Free and open git hosting powered by Gitea at git.arcaneneko.com. Open to everyone - create repos, collaborate, and host your code with no limits.

+ Visit Git Instance → +
+ +
+ +

Arcane Status

+

Free status page software under MIT License. Monitor your services and keep users informed with a clean, minimal status page you can self-host.

+ Learn More → +
+ +
+
+
+ + +
+
+ +

What we're building

+
+ +
+ Early Preview + +

Neovoxis

+

A modern Discord-like chat platform with text channels, forums, and a clean interface. Currently in early preview with active development ongoing.

+ Visit Neovoxis +
+ +
+ MIT License + +

Arcane Status

+

Free and open source status page software. Minimal setup, easy to customize, and ready to deploy. Keep your users informed about service health.

+ View Details +
+ +
+
+
+ + + + + + + + + + + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..0ffa96b --- /dev/null +++ b/js/main.js @@ -0,0 +1,230 @@ +/** + * ArcaneNeko Website - Main Initialization + * + * Handles: mobile menu, scroll reveal, stat counters, + * back-to-top, scroll progress, smooth scroll + */ + +// ---------------------- +// Mobile Hamburger Menu +// ---------------------- +function initMobileMenu() { + const hamburger = document.getElementById('hamburger'); + const mobileMenu = document.getElementById('mobileMenu'); + if (!hamburger || !mobileMenu) return; + + hamburger.addEventListener('click', () => { + const open = hamburger.classList.toggle('open'); + mobileMenu.classList.toggle('open', open); + hamburger.setAttribute('aria-expanded', String(open)); + }); + + mobileMenu.querySelectorAll('a').forEach(link => { + link.addEventListener('click', () => { + hamburger.classList.remove('open'); + mobileMenu.classList.remove('open'); + hamburger.setAttribute('aria-expanded', 'false'); + }); + }); +} + +// ---------------------- +// Scroll Reveal (cards) +// ---------------------- +function initScrollReveal() { + const observer = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + observer.unobserve(entry.target); + } + }); + }, { threshold: 0.1 }); + + document.querySelectorAll('.reveal').forEach(el => observer.observe(el)); +} + +// ---------------------- +// Stat Counter Animation +// ---------------------- +function animateCount(el, target, suffix, duration) { + const start = performance.now(); + const from = 0; + + function step(now) { + const elapsed = now - start; + const progress = Math.min(elapsed / duration, 1); + const eased = 1 - Math.pow(1 - progress, 3); + const current = Math.round(from + (target - from) * eased); + el.textContent = current + suffix; + if (progress < 1) requestAnimationFrame(step); + } + requestAnimationFrame(step); +} + +function initStatCounters() { + const statsBar = document.querySelector('.stats-bar'); + if (!statsBar) return; + + const observer = new IntersectionObserver(entries => { + if (!entries[0].isIntersecting) return; + observer.disconnect(); + + document.querySelectorAll('.stat').forEach(el => el.classList.add('animated')); + + document.querySelectorAll('.stat-value[data-count]').forEach(el => { + const target = parseFloat(el.dataset.count); + const suffix = el.dataset.suffix || ''; + const duration = 1400; + animateCount(el, target, suffix, duration); + }); + + }, { threshold: 0.5 }); + + observer.observe(statsBar); +} + +// ---------------------- +// Back to Top Button +// ---------------------- +function initBackToTop() { + const btn = document.getElementById('backToTop'); + if (!btn) return; + + window.addEventListener('scroll', () => { + btn.classList.toggle('visible', window.scrollY > 450); + }, { passive: true }); + + btn.addEventListener('click', () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }); +} + +// ---------------------- +// Scroll Progress Bar (legal pages) +// ---------------------- +function initScrollProgress() { + const bar = document.getElementById('scrollProgress'); + if (!bar) return; + + const updateProgress = () => { + const total = document.documentElement.scrollHeight - window.innerHeight; + const progress = total > 0 ? (window.scrollY / total) * 100 : 0; + const rounded = Math.round(progress); + bar.style.width = progress + '%'; + bar.setAttribute('aria-valuenow', String(rounded)); + }; + + updateProgress(); + window.addEventListener('scroll', updateProgress, { passive: true }); + window.addEventListener('resize', updateProgress); +} + +// ---------------------- +// Navbar scroll shadow +// ---------------------- +function initNavShadow() { + const navbar = document.querySelector('.navbar'); + if (!navbar) return; + window.addEventListener('scroll', () => { + navbar.style.boxShadow = window.scrollY > 10 + ? '0 4px 24px rgba(0,0,0,0.3)' + : 'none'; + }, { passive: true }); +} + +// ---------------------- +// Smooth scroll (hash links) +// ---------------------- +function initSmoothScroll() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', e => { + const href = anchor.getAttribute('href'); + if (href === '#') return; + const target = document.querySelector(href); + if (target) { + e.preventDefault(); + const offset = 80; + window.scrollTo({ + top: target.getBoundingClientRect().top + window.scrollY - offset, + behavior: 'smooth' + }); + } + }); + }); +} + +// ---------------------- +// Legal page TOC highlight +// ---------------------- +function initTocHighlight() { + const sections = document.querySelectorAll('.legal-section'); + const tocLinks = document.querySelectorAll('.legal-toc a'); + if (!sections.length || !tocLinks.length) return; + + const observer = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + tocLinks.forEach(l => l.classList.remove('active')); + const active = document.querySelector(`.legal-toc a[href="#${entry.target.id}"]`); + if (active) active.classList.add('active'); + } + }); + }, { rootMargin: '-20% 0px -70% 0px' }); + + sections.forEach(s => observer.observe(s)); +} + +// ---------------------- +// Legal page mobile TOC +// ---------------------- +function initLegalTocToggle() { + document.querySelectorAll('.legal-toc').forEach(toc => { + const button = toc.querySelector('.legal-toc-toggle'); + const panel = toc.querySelector('.legal-toc-panel'); + if (!button || !panel) return; + + button.addEventListener('click', () => { + const open = toc.classList.toggle('open'); + button.setAttribute('aria-expanded', String(open)); + }); + + panel.querySelectorAll('a').forEach(link => { + link.addEventListener('click', () => { + if (window.innerWidth <= 768) { + toc.classList.remove('open'); + button.setAttribute('aria-expanded', 'false'); + } + }); + }); + }); +} + +// ---------------------- +// Init on DOM ready +// ---------------------- +document.addEventListener('DOMContentLoaded', () => { + // Apply saved theme before anything renders + if (window.ThemeUtils) { + window.ThemeUtils.applyTheme(window.ThemeUtils.getCurrentTheme()); + } + + // Theme toggle + document.querySelectorAll('.theme-toggle').forEach(btn => { + btn.addEventListener('click', () => { + if (window.ThemeUtils) { + window.ThemeUtils.applyTheme(window.ThemeUtils.nextTheme()); + } + }); + }); + + initMobileMenu(); + initScrollReveal(); + initStatCounters(); + initBackToTop(); + initScrollProgress(); + initNavShadow(); + initSmoothScroll(); + initTocHighlight(); + initLegalTocToggle(); +}); diff --git a/js/theme.js b/js/theme.js new file mode 100644 index 0000000..3e65868 --- /dev/null +++ b/js/theme.js @@ -0,0 +1,44 @@ +/** + * Theme Switcher Utility + */ + +// Theme configuration +const THEMES = ['crimson', 'dark', 'light']; + +const THEME_ICONS = { + crimson: ``, + dark: ``, + light: ``, +}; + +const THEME_LABELS = { + crimson: 'Switch to dark mode', + dark: 'Switch to light mode', + light: 'Switch to crimson theme', +}; + +let currentTheme = localStorage.getItem('an-theme') || 'crimson'; + +function applyTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + document.querySelectorAll('.theme-toggle').forEach(btn => { + btn.innerHTML = THEME_ICONS[theme]; + btn.setAttribute('title', THEME_LABELS[theme]); + btn.setAttribute('aria-label', THEME_LABELS[theme]); + }); + localStorage.setItem('an-theme', theme); + currentTheme = theme; +} + +function nextTheme() { + const idx = THEMES.indexOf(currentTheme); + return THEMES[(idx + 1) % THEMES.length]; +} + +// Export for use in other files +window.ThemeUtils = { + THEMES, + applyTheme, + nextTheme, + getCurrentTheme: () => currentTheme, +}; diff --git a/privacy.html b/privacy.html new file mode 100644 index 0000000..1cd0eea --- /dev/null +++ b/privacy.html @@ -0,0 +1,519 @@ + + + + + + +Privacy Policy | ArcaneNeko + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..77f179f --- /dev/null +++ b/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://arcaneneko.com/sitemap.xml \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..b84af2b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,73 @@ + + + + https://arcaneneko.com/ + weekly + 1.0 + + + https://arcaneneko.com/index + weekly + 1.0 + + + https://arcaneneko.com/status + monthly + 0.8 + + + https://arcaneneko.com/privacy + yearly + 0.3 + + + https://arcaneneko.com/terms + yearly + 0.3 + + + https://arcaneneko.com/contact + monthly + 0.5 + + + https://arcaneneko.com/coming-soon + weekly + 0.5 + + + https://arcaneneko.com/400 + yearly + 0.1 + + + https://arcaneneko.com/403 + yearly + 0.1 + + + https://arcaneneko.com/404 + yearly + 0.1 + + + https://arcaneneko.com/422 + yearly + 0.1 + + + https://arcaneneko.com/500 + yearly + 0.1 + + + https://arcaneneko.com/502 + yearly + 0.1 + + + https://arcaneneko.com/503 + yearly + 0.1 + + \ No newline at end of file diff --git a/status.html b/status.html new file mode 100644 index 0000000..4415285 --- /dev/null +++ b/status.html @@ -0,0 +1,173 @@ + + + + + + Arcane Status | Free Open Source Status Pages + + + + "> + + + + + + + + + + + + + + + + + + +
+ + +
+ +

ArcaneStatus

+

Free and open source status page software. Monitor your services and keep your users informed, self-hosted, no subscriptions.

+ +
+
+ + +
+
+ +

Everything you need

+
+
+

Real-time Monitoring

+

Monitor HTTP/HTTPS endpoints, TCP ports, and ICMP ping with configurable check intervals from 10 seconds to 1 hour.

+
+
+

Live Updates

+

WebSocket-powered real-time updates pushed to both the public status page and admin dashboard.

+
+
+

Incident Management

+

Create, update, and resolve incidents with severity levels. Link incidents to affected endpoints and write post-mortems.

+
+
+

Scheduled Maintenance

+

Schedule maintenance windows to pause monitoring and display notices to visitors.

+
+
+

Email Notifications

+

SMTP-based notifications with per-user preferences. Subscribe to all endpoints or specific categories.

+
+
+

API Access

+

Generate API keys for programmatic access. Rate-limited public API with status.json endpoint for integration.

+
+
+

Uptime Analytics

+

Automatic uptime calculation with SLA tracking, heatmaps, response time charts, and jitter/packet loss metrics.

+
+
+

Zero Dependencies

+

SQLite database only - no Redis or Postgres required. Just Node.js and you're ready to go.

+
+
+
+
+ + +
+
+ +

See it in action

+

Visit our live instance or grab the source code and host your own.

+ +
+
+ + + + + + + + + + diff --git a/terms.html b/terms.html new file mode 100644 index 0000000..c7cccd7 --- /dev/null +++ b/terms.html @@ -0,0 +1,334 @@ + + + + + + +Terms of Service | ArcaneNeko + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +