Add levkin.ca design concepts (Spec, Slab, Relay, Vault).
Four static landing-page options with Vite build, cal booking, and links to sibling sites. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
commit
b9a601894d
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.DS_Store
|
||||||
35
README.md
Normal file
35
README.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# levkin.ca
|
||||||
|
|
||||||
|
Four design concepts for the Levkin software development company homepage.
|
||||||
|
|
||||||
|
| Option | Path | Vibe |
|
||||||
|
|--------|------|------|
|
||||||
|
| **Spec** | `/spec/` | RFC documentation, endpoints, required properties |
|
||||||
|
| **Slab** | `/slab/` | Brutalist poster, massive typography |
|
||||||
|
| **Relay** | `/relay/` | Telegraph, signal chain, decoded messages |
|
||||||
|
| **Vault** | `/vault/` | Institutional trust, enterprise gravitas |
|
||||||
|
|
||||||
|
Open `/` to compare all four.
|
||||||
|
|
||||||
|
## Develop
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Documents/code/levkin.ca
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
# output in dist/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related sites
|
||||||
|
|
||||||
|
- [auto.levkin.ca](https://auto.levkin.ca) — automation
|
||||||
|
- [caseware.levkin.ca](https://caseware.levkin.ca) — CaseWare consulting
|
||||||
|
- [jobs.levkin.ca](https://jobs.levkin.ca) — job orchestration
|
||||||
|
- [git.levkin.ca](https://git.levkin.ca) — source control
|
||||||
|
- [iliadobkin.com](https://iliadobkin.com) — SDET portfolio · quality engineering
|
||||||
191
index.html
Normal file
191
index.html
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>levkin.ca — design options</title>
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #08080a;
|
||||||
|
--fg: #eceae6;
|
||||||
|
--muted: #6e6c68;
|
||||||
|
--accent: #c4a574;
|
||||||
|
--border: #1c1b19;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: 'DM Sans', system-ui, sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
min-height: 100vh;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.wrap { max-width: 1100px; margin: 0 auto; padding: 4rem 1.5rem 6rem; }
|
||||||
|
header { margin-bottom: 3rem; }
|
||||||
|
.eyebrow {
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--accent);
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(2rem, 5vw, 2.75rem);
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
.lead { color: var(--muted); font-size: 1.05rem; max-width: 48ch; }
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
}
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.grid { grid-template-columns: repeat(4, 1fr); }
|
||||||
|
}
|
||||||
|
a.card {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: border-color 0.2s, transform 0.2s;
|
||||||
|
}
|
||||||
|
a.card:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
.preview {
|
||||||
|
height: 130px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
.preview--spec {
|
||||||
|
background: #f4f1ec;
|
||||||
|
color: #1a1a18;
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
.preview--slab {
|
||||||
|
background: #f5f5f0;
|
||||||
|
color: #0a0a0a;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 2rem;
|
||||||
|
letter-spacing: -0.06em;
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
.preview--relay {
|
||||||
|
background: #1a1814;
|
||||||
|
color: #d4a574;
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
}
|
||||||
|
.preview--relay::after {
|
||||||
|
content: '· · · ─ ─ ·';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1rem;
|
||||||
|
font-size: 0.55rem;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.preview--vault {
|
||||||
|
background: linear-gradient(160deg, #0c1410 0%, #1a2820 100%);
|
||||||
|
color: #c9b896;
|
||||||
|
font-family: 'DM Sans', sans-serif;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
letter-spacing: 0.25em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.card-body { padding: 1.15rem 1.25rem 1.35rem; }
|
||||||
|
.card-body h2 { font-size: 1.05rem; font-weight: 600; margin-bottom: 0.3rem; }
|
||||||
|
.card-body p { font-size: 0.82rem; color: var(--muted); line-height: 1.4; }
|
||||||
|
.tag {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 0.65rem;
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
font-size: 0.62rem;
|
||||||
|
color: var(--accent);
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
.kept {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: 'DM Mono', monospace;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-left: 0.35rem;
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
margin-top: 3.5rem;
|
||||||
|
padding-top: 2rem;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
footer a { color: var(--accent); text-decoration: none; }
|
||||||
|
footer code { font-family: 'DM Mono', monospace; font-size: 0.75rem; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrap">
|
||||||
|
<header>
|
||||||
|
<p class="eyebrow">levkin.ca · round 3</p>
|
||||||
|
<h1>Four directions.</h1>
|
||||||
|
<p class="lead">Spec is back. Plus Slab, Relay, and Vault — three new concepts. Company-first throughout.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<a class="card" href="/spec/">
|
||||||
|
<div class="preview preview--spec">GET /company → 200</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h2>Spec <span class="kept">kept</span></h2>
|
||||||
|
<p>Levkin as an RFC. Endpoints, schemas, required properties. Precise and documentation-native.</p>
|
||||||
|
<span class="tag">paper · RFC · precise</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="card" href="/slab/">
|
||||||
|
<div class="preview preview--slab">LEV</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h2>Slab</h2>
|
||||||
|
<p>Brutalist poster. Massive type, hard edges, zero decoration. Confidence without explaining itself.</p>
|
||||||
|
<span class="tag">brutalist · bold · minimal</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="card" href="/relay/">
|
||||||
|
<div class="preview preview--relay">RELAY</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h2>Relay</h2>
|
||||||
|
<p>Telegraph and signal chain. Messages arrive, get decoded. Communication as craft.</p>
|
||||||
|
<span class="tag">vintage · interactive · warm</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="card" href="/vault/">
|
||||||
|
<div class="preview preview--vault">Secured</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h2>Vault</h2>
|
||||||
|
<p>Institutional trust. Deep green, brass accents. For enterprise clients who need gravitas.</p>
|
||||||
|
<span class="tag">trust · enterprise · calm</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p><a href="https://git.levkin.ca">git.levkin.ca</a> · <code>cd ~/Documents/code/levkin.ca && npm run dev</code></p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1143
package-lock.json
generated
Normal file
1143
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
package.json
Normal file
14
package.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "levkin.ca",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.3.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^6.3.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
4
public/favicon.svg
Normal file
4
public/favicon.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
||||||
|
<rect width="32" height="32" rx="6" fill="#0a0a0b"/>
|
||||||
|
<path d="M8 22V10h4.2c3.1 0 5 1.6 5 4.2 0 2.4-1.7 3.8-4.5 3.8H12v4H8zm4-7.2h1.8c1.4 0 2.2-.7 2.2-1.8S15.2 11 13.8 11H12v3.8zM20 22V10h6.5v3.2H24v2.2h2.2v3.2H24v3.6H20z" fill="#c4a574"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
87
relay/index.html
Normal file
87
relay/index.html
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Levkin — Relay</title>
|
||||||
|
<meta name="description" content="Levkin — software development. Signals in, production out." />
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime:wght@400;700&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="./relay.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="grain" aria-hidden="true"></div>
|
||||||
|
|
||||||
|
<nav class="nav">
|
||||||
|
<a href="/">← options</a>
|
||||||
|
<span class="station">STN · LEV-01</span>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<header class="header">
|
||||||
|
<h1>Levkin Relay</h1>
|
||||||
|
<p class="sub">Software development · signal in · production out</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="tape" aria-label="Incoming transmissions">
|
||||||
|
<div class="tape-head">
|
||||||
|
<span>INCOMING</span>
|
||||||
|
<button type="button" id="decode-btn" class="decode-btn">Decode ↵</button>
|
||||||
|
</div>
|
||||||
|
<pre class="morse" id="morse" aria-live="polite"></pre>
|
||||||
|
<p class="decoded hidden" id="decoded"></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="channels">
|
||||||
|
<h2>Active lines</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="line-id">L-1</span>
|
||||||
|
<span class="line-name">Custom software</span>
|
||||||
|
<span class="line-status">open</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="line-id">L-2</span>
|
||||||
|
<span class="line-name">Automation</span>
|
||||||
|
<a href="https://auto.levkin.ca" class="line-link">auto.levkin.ca</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="line-id">L-3</span>
|
||||||
|
<span class="line-name">CaseWare</span>
|
||||||
|
<a href="https://caseware.levkin.ca" class="line-link">caseware.levkin.ca</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="line-id">L-4</span>
|
||||||
|
<span class="line-name">Operations</span>
|
||||||
|
<a href="https://jobs.levkin.ca" class="line-link">jobs.levkin.ca</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="line-id">L-5</span>
|
||||||
|
<span class="line-name">Quality engineering</span>
|
||||||
|
<a href="https://iliadobkin.com" class="line-link">iliadobkin.com</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="principles">
|
||||||
|
<p>Every transmission handled with retries, documentation, and tests before it reaches production. Canadian. Remote.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="send">
|
||||||
|
<p class="send-label">Schedule transmission:</p>
|
||||||
|
<a href="https://cal.levkin.ca/ilia/consult" class="send-addr send-cal">15 min consultation →</a>
|
||||||
|
<p class="send-label">Or reply to:</p>
|
||||||
|
<a href="mailto:hello@levkine.ca?subject=Relay%20enquiry" class="send-addr">hello@levkine.ca</a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<a href="https://git.levkin.ca">git.levkin.ca</a>
|
||||||
|
<span>levkin.ca</span>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="./relay.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
205
relay/relay.css
Normal file
205
relay/relay.css
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
:root {
|
||||||
|
--bg: #1a1814;
|
||||||
|
--paper: #e8e0d4;
|
||||||
|
--amber: #d4a574;
|
||||||
|
--dim: #6b6358;
|
||||||
|
--mono: 'Courier Prime', 'Courier New', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--mono);
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--paper);
|
||||||
|
min-height: 100vh;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grain {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.04;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1.25rem 2rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav a {
|
||||||
|
color: var(--dim);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav a:hover { color: var(--amber); }
|
||||||
|
|
||||||
|
.station { color: var(--amber); }
|
||||||
|
|
||||||
|
main {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 560px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem 2rem 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
border-bottom: 1px solid rgba(212, 165, 116, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.15em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--amber);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--dim);
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape {
|
||||||
|
background: rgba(0, 0, 0, 0.35);
|
||||||
|
border: 1px solid rgba(212, 165, 116, 0.2);
|
||||||
|
padding: 1.25rem;
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tape-head {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
color: var(--amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
.decode-btn {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--amber);
|
||||||
|
color: var(--amber);
|
||||||
|
padding: 0.35rem 0.65rem;
|
||||||
|
cursor: pointer;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.decode-btn:hover {
|
||||||
|
background: rgba(212, 165, 116, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.morse {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--dim);
|
||||||
|
word-break: break-all;
|
||||||
|
line-height: 1.8;
|
||||||
|
min-height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.decoded {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px dashed rgba(212, 165, 116, 0.3);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--paper);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.decoded.hidden { display: none; }
|
||||||
|
|
||||||
|
.channels { margin-bottom: 2rem; }
|
||||||
|
|
||||||
|
.channels h2 {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
letter-spacing: 0.25em;
|
||||||
|
color: var(--dim);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channels ul { list-style: none; }
|
||||||
|
|
||||||
|
.channels li {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2.5rem 1fr auto;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.65rem 0;
|
||||||
|
border-bottom: 1px solid rgba(212, 165, 116, 0.1);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-id { color: var(--dim); font-size: 0.75rem; }
|
||||||
|
.line-status { color: var(--amber); font-size: 0.7rem; letter-spacing: 0.1em; }
|
||||||
|
.line-link {
|
||||||
|
color: var(--amber);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-link:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
.principles {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--dim);
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send {
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
border-top: 1px solid rgba(212, 165, 116, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-label {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
color: var(--dim);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-label:first-child { margin-top: 0; }
|
||||||
|
|
||||||
|
.send-addr {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--amber);
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-addr:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
footer {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1.5rem 2rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--dim);
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--dim);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover { color: var(--amber); }
|
||||||
58
relay/relay.js
Normal file
58
relay/relay.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
const MESSAGES = [
|
||||||
|
{
|
||||||
|
morse: '·−·−− · ·−·−− ·−· · ·−·−− −−− · ·−·−− ·−· · ·−·−− ·−−−',
|
||||||
|
text: 'Levkin builds production software for teams under pressure. Custom systems, automation, enterprise tooling.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
morse: '−−− ·−·−− · ·−·−− ·−· · ·−·−− ·−−− · ·−·−− ·−· · ·−·−− −−− · ·−·−− ·−· · ·−·−− ·−−−',
|
||||||
|
text: 'Error handling required. Documentation required. Tests before live data. Scope creep rejected.',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const morseEl = document.getElementById('morse');
|
||||||
|
const decodedEl = document.getElementById('decoded');
|
||||||
|
const btn = document.getElementById('decode-btn');
|
||||||
|
let idx = 0;
|
||||||
|
let typing = false;
|
||||||
|
|
||||||
|
function typeMorse(text, cb) {
|
||||||
|
typing = true;
|
||||||
|
morseEl.textContent = '';
|
||||||
|
let i = 0;
|
||||||
|
const tick = () => {
|
||||||
|
if (i < text.length) {
|
||||||
|
morseEl.textContent += text[i];
|
||||||
|
i++;
|
||||||
|
setTimeout(tick, 35 + Math.random() * 40);
|
||||||
|
} else {
|
||||||
|
typing = false;
|
||||||
|
cb?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMessage() {
|
||||||
|
const msg = MESSAGES[idx % MESSAGES.length];
|
||||||
|
decodedEl.classList.add('hidden');
|
||||||
|
typeMorse(msg.morse, () => {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = 'Decode ↵';
|
||||||
|
});
|
||||||
|
btn._pending = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
if (typing) return;
|
||||||
|
if (btn._pending && decodedEl.classList.contains('hidden')) {
|
||||||
|
decodedEl.textContent = btn._pending.text;
|
||||||
|
decodedEl.classList.remove('hidden');
|
||||||
|
btn.textContent = 'Next signal →';
|
||||||
|
btn._pending = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
showMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
showMessage();
|
||||||
73
slab/index.html
Normal file
73
slab/index.html
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Levkin</title>
|
||||||
|
<meta name="description" content="Levkin — software development." />
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Archivo:wght@400;500&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="./slab.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="/" class="back">←</a>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<header class="mast">
|
||||||
|
<span class="year">EST · CA</span>
|
||||||
|
<h1>LEV<br />KIN</h1>
|
||||||
|
<p class="role">SOFTWARE DEVELOPMENT</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="strip strip-red">
|
||||||
|
<p>WE BUILD WHAT RUNS.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="blocks">
|
||||||
|
<div class="block">
|
||||||
|
<span class="num">01</span>
|
||||||
|
<h2>CUSTOM</h2>
|
||||||
|
<p>Apps · APIs · tools</p>
|
||||||
|
</div>
|
||||||
|
<div class="block block-inv">
|
||||||
|
<span class="num">02</span>
|
||||||
|
<h2>AUTO</h2>
|
||||||
|
<p><a href="https://auto.levkin.ca">auto.levkin.ca</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<span class="num">03</span>
|
||||||
|
<h2>CASE</h2>
|
||||||
|
<p><a href="https://caseware.levkin.ca">caseware.levkin.ca</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="block block-inv">
|
||||||
|
<span class="num">04</span>
|
||||||
|
<h2>OPS</h2>
|
||||||
|
<p><a href="https://jobs.levkin.ca">jobs.levkin.ca</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="block block-wide">
|
||||||
|
<span class="num">05</span>
|
||||||
|
<h2>QE</h2>
|
||||||
|
<p><a href="https://iliadobkin.com">iliadobkin.com</a></p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="strip">
|
||||||
|
<ul class="rules">
|
||||||
|
<li>PRODUCTION READY</li>
|
||||||
|
<li>DOCUMENTED</li>
|
||||||
|
<li>TESTED FIRST</li>
|
||||||
|
<li>NO SCOPE CREEP</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="cta-block">
|
||||||
|
<a href="https://cal.levkin.ca/ilia/consult" class="cta cta-primary">BOOK 15 MIN →</a>
|
||||||
|
<a href="mailto:hello@levkine.ca?subject=Project%20enquiry" class="cta">HELLO@LEVGINE.CA →</a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>LEVKIN.CA · <a href="https://git.levkin.ca">GIT</a></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
191
slab/slab.css
Normal file
191
slab/slab.css
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
:root {
|
||||||
|
--white: #f5f5f0;
|
||||||
|
--black: #0a0a0a;
|
||||||
|
--red: #e63946;
|
||||||
|
--font-display: 'Archivo Black', system-ui, sans-serif;
|
||||||
|
--font: 'Archivo', system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font);
|
||||||
|
background: var(--white);
|
||||||
|
color: var(--black);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
position: fixed;
|
||||||
|
top: 1.25rem;
|
||||||
|
left: 1.25rem;
|
||||||
|
z-index: 10;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--black);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
main { max-width: 100%; }
|
||||||
|
|
||||||
|
.mast {
|
||||||
|
padding: 4rem 1.5rem 3rem;
|
||||||
|
border-bottom: 6px solid var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.year {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
letter-spacing: 0.25em;
|
||||||
|
font-weight: 500;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mast h1 {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: clamp(4rem, 18vw, 11rem);
|
||||||
|
line-height: 0.85;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
letter-spacing: 0.35em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.strip {
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
border-bottom: 4px solid var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.strip-red {
|
||||||
|
background: var(--red);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.strip-red p {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: clamp(1.25rem, 4vw, 2rem);
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blocks {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.blocks { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
border-bottom: 4px solid var(--black);
|
||||||
|
border-right: 4px solid var(--black);
|
||||||
|
min-height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block:nth-child(2n) { border-right: none; }
|
||||||
|
|
||||||
|
.block-wide {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-inv {
|
||||||
|
background: var(--black);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.num {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
opacity: 0.5;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block h2 {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 2rem;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
margin-bottom: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block p {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rules {
|
||||||
|
list-style: none;
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rules li {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: clamp(0.9rem, 2.5vw, 1.1rem);
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-block {
|
||||||
|
padding: 3rem 1.5rem;
|
||||||
|
border-bottom: 6px solid var(--black);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: clamp(1rem, 3vw, 1.5rem);
|
||||||
|
color: var(--black);
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
border-bottom: 4px solid var(--red);
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
transition: color 0.15s, border-color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta:hover {
|
||||||
|
color: var(--red);
|
||||||
|
border-color: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-primary {
|
||||||
|
background: var(--black);
|
||||||
|
color: var(--white);
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
border-bottom-color: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-primary:hover {
|
||||||
|
color: var(--red);
|
||||||
|
background: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--black);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover { text-decoration: underline; }
|
||||||
153
spec/index.html
Normal file
153
spec/index.html
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Levkin — Company Specification</title>
|
||||||
|
<meta name="description" content="Levkin: software development company. Specification v1.0." />
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Literata:opsz,wght@7..72,400;7..72,600&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="./spec.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<aside class="toc" aria-label="Table of contents">
|
||||||
|
<a href="/" class="back">← all options</a>
|
||||||
|
<nav>
|
||||||
|
<a href="#abstract">Abstract</a>
|
||||||
|
<a href="#scope">1. Scope</a>
|
||||||
|
<a href="#services">2. Services</a>
|
||||||
|
<a href="#properties">3. Properties</a>
|
||||||
|
<a href="#subsidiaries">4. Subdomains</a>
|
||||||
|
<a href="#contact">5. Contact</a>
|
||||||
|
</nav>
|
||||||
|
<p class="meta">Levkin-Company-Spec<br />Version 1.0<br />May 2026</p>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<article class="rfc">
|
||||||
|
<header class="rfc-header">
|
||||||
|
<p class="category">Request for Comments</p>
|
||||||
|
<h1>Levkin Software Development Company</h1>
|
||||||
|
<table class="rfc-meta">
|
||||||
|
<tr><th>Status</th><td><span class="badge">ACTIVE</span></td></tr>
|
||||||
|
<tr><th>Entity</th><td>Levkin</td></tr>
|
||||||
|
<tr><th>Domain</th><td>levkin.ca</td></tr>
|
||||||
|
<tr><th>Updated</th><td>2026-05-20</td></tr>
|
||||||
|
</table>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section id="abstract">
|
||||||
|
<h2>Abstract</h2>
|
||||||
|
<p>This document describes <strong>Levkin</strong>, a Canadian software development practice specializing in production systems, business automation, and enterprise tooling. Levkin ships software that must work when nobody is watching — with error handling, documentation, and tests as non-optional requirements.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="scope">
|
||||||
|
<h2><span class="sec-num">1.</span> Scope</h2>
|
||||||
|
<p>Levkin operates as a boutique engineering practice, not a body shop. Engagements are scoped, shipped, and handed off with the expectation that the client (or their next hire) can maintain what was built.</p>
|
||||||
|
<pre class="code-block"><code>interface Engagement {
|
||||||
|
discovery: "15min call, no obligation"; // cal.levkin.ca/ilia/consult
|
||||||
|
delivery: "production-ready, documented";
|
||||||
|
maintenance: "optional, not mandatory lock-in";
|
||||||
|
}</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="services">
|
||||||
|
<h2><span class="sec-num">2.</span> Services</h2>
|
||||||
|
<p>The following endpoints represent primary service offerings. Each maps to a deployable capability.</p>
|
||||||
|
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="endpoint-head">
|
||||||
|
<span class="method">BUILD</span>
|
||||||
|
<span class="path">/custom-software</span>
|
||||||
|
</div>
|
||||||
|
<p>Web applications, APIs, internal tools. Stack-agnostic; preference for boring, proven technology.</p>
|
||||||
|
<ul>
|
||||||
|
<li>TypeScript / Node · Python · C# / .NET</li>
|
||||||
|
<li>PostgreSQL · SQL Server · SQLite</li>
|
||||||
|
<li>React · Vue · server-rendered where appropriate</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="endpoint-head">
|
||||||
|
<span class="method">BUILD</span>
|
||||||
|
<span class="path">/automation</span>
|
||||||
|
<span class="ext"><a href="https://auto.levkin.ca">auto.levkin.ca</a></span>
|
||||||
|
</div>
|
||||||
|
<p>n8n, Zapier, Make, GitHub Actions, webhooks, LLM integrations. Scripts that save hours; pipelines that run operations.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="endpoint-head">
|
||||||
|
<span class="method">BUILD</span>
|
||||||
|
<span class="path">/caseware</span>
|
||||||
|
<span class="ext"><a href="https://caseware.levkin.ca">caseware.levkin.ca</a></span>
|
||||||
|
</div>
|
||||||
|
<p>CaseWare & CaseView development, templates, release automation. 15+ years inside the ecosystem.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="endpoint-head">
|
||||||
|
<span class="method">BUILD</span>
|
||||||
|
<span class="path">/quality-engineering</span>
|
||||||
|
<span class="ext"><a href="https://iliadobkin.com">iliadobkin.com</a></span>
|
||||||
|
</div>
|
||||||
|
<p>Test automation, CI/CD, trace-driven debugging. Contract SDET services available.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="properties">
|
||||||
|
<h2><span class="sec-num">3.</span> Required Properties</h2>
|
||||||
|
<p>All Levkin deliverables MUST satisfy the following constraints unless explicitly waived in writing.</p>
|
||||||
|
<table class="spec-table">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Property</th><th>Requirement</th><th>Rationale</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td><code>reliability</code></td><td>Retries, alerts, graceful degradation</td><td>Production ≠ demo</td></tr>
|
||||||
|
<tr><td><code>documentation</code></td><td>Runbook or README sufficient for handoff</td><td>Bus factor > 1</td></tr>
|
||||||
|
<tr><td><code>testability</code></td><td>Automated tests before live data</td><td>Regressions are expensive</td></tr>
|
||||||
|
<tr><td><code>pragmatism</code></td><td>Smallest solution that solves the problem</td><td>20-line script > 200-node workflow</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="subsidiaries">
|
||||||
|
<h2><span class="sec-num">4.</span> Registered Subdomains</h2>
|
||||||
|
<table class="spec-table subdomains">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Host</th><th>Purpose</th><th>Status</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td><a href="https://auto.levkin.ca">auto.levkin.ca</a></td><td>Business automation</td><td><span class="badge">live</span></td></tr>
|
||||||
|
<tr><td><a href="https://caseware.levkin.ca">caseware.levkin.ca</a></td><td>CaseWare consulting</td><td><span class="badge">live</span></td></tr>
|
||||||
|
<tr><td><a href="https://jobs.levkin.ca">jobs.levkin.ca</a></td><td>Job orchestration (internal)</td><td><span class="badge muted">auth</span></td></tr>
|
||||||
|
<tr><td><a href="https://git.levkin.ca">git.levkin.ca</a></td><td>Source control</td><td><span class="badge">live</span></td></tr>
|
||||||
|
<tr><td><a href="https://iliadobkin.com">iliadobkin.com</a></td><td>SDET portfolio · quality engineering</td><td><span class="badge">live</span></td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="contact" class="contact">
|
||||||
|
<h2><span class="sec-num">5.</span> Contact</h2>
|
||||||
|
<p>To initiate an engagement, send a <code>POST</code> to the following channel:</p>
|
||||||
|
<div class="contact-grid">
|
||||||
|
<a class="contact-card" href="https://cal.levkin.ca/ilia/consult">
|
||||||
|
<span class="method post">POST</span>
|
||||||
|
<span>/consult</span>
|
||||||
|
<span class="desc">15-minute discovery call</span>
|
||||||
|
</a>
|
||||||
|
<a class="contact-card" href="mailto:hello@levkine.ca?subject=Project%20enquiry">
|
||||||
|
<span class="method post">POST</span>
|
||||||
|
<span>/email</span>
|
||||||
|
<span class="desc">hello@levkine.ca</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<p class="copyright">© Levkin · Canadian software development</p>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<script src="./spec.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
287
spec/spec.css
Normal file
287
spec/spec.css
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
:root {
|
||||||
|
--paper: #f4f1ec;
|
||||||
|
--ink: #1a1a18;
|
||||||
|
--muted: #5c5a56;
|
||||||
|
--rule: #d4cfc6;
|
||||||
|
--accent: #2a4a6b;
|
||||||
|
--accent-bg: #e8eef4;
|
||||||
|
--mono: 'IBM Plex Mono', ui-monospace, monospace;
|
||||||
|
--serif: 'Literata', Georgia, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 200px 1fr;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--paper);
|
||||||
|
color: var(--ink);
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 1.05rem;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
body { grid-template-columns: 1fr; }
|
||||||
|
.toc {
|
||||||
|
position: static !important;
|
||||||
|
border-bottom: 1px solid var(--rule);
|
||||||
|
padding: 1rem 1.5rem !important;
|
||||||
|
}
|
||||||
|
.toc nav { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; }
|
||||||
|
.toc .meta { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 2rem 1.25rem;
|
||||||
|
border-right: 1px solid var(--rule);
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
display: block;
|
||||||
|
color: var(--muted);
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back:hover { color: var(--accent); }
|
||||||
|
|
||||||
|
.toc nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc nav a {
|
||||||
|
color: var(--ink);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc nav a:hover { color: var(--accent); }
|
||||||
|
|
||||||
|
.meta {
|
||||||
|
margin-top: 2rem;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rfc {
|
||||||
|
max-width: 42rem;
|
||||||
|
padding: 3rem 2.5rem 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.rfc { padding: 2rem 1.25rem 4rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.rfc-header {
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
border-bottom: 2px solid var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rfc-header h1 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.25;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rfc-meta {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rfc-meta th {
|
||||||
|
text-align: left;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--muted);
|
||||||
|
padding: 0.25rem 1rem 0.25rem 0;
|
||||||
|
width: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.65rem;
|
||||||
|
padding: 0.15rem 0.45rem;
|
||||||
|
background: #d4edda;
|
||||||
|
color: #1e5631;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.muted {
|
||||||
|
background: var(--rule);
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
scroll-margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section h2 {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-num { font-family: var(--mono); font-weight: 500; color: var(--muted); }
|
||||||
|
|
||||||
|
section p { margin-bottom: 0.75rem; color: var(--ink); }
|
||||||
|
|
||||||
|
.code-block {
|
||||||
|
background: var(--accent-bg);
|
||||||
|
border: 1px solid var(--rule);
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block code {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint {
|
||||||
|
border: 1px solid var(--rule);
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem 0.75rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: var(--accent-bg);
|
||||||
|
border-bottom: 1px solid var(--rule);
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1e5631;
|
||||||
|
background: #d4edda;
|
||||||
|
padding: 0.15rem 0.4rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path { color: var(--accent); font-weight: 500; }
|
||||||
|
|
||||||
|
.ext { margin-left: auto; font-size: 0.75rem; }
|
||||||
|
.ext a { color: var(--muted); }
|
||||||
|
|
||||||
|
.endpoint > p,
|
||||||
|
.endpoint > ul {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint ul {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-left: 2rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-table th,
|
||||||
|
.spec-table td {
|
||||||
|
border: 1px solid var(--rule);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-table th {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
background: var(--accent-bg);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-table code {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-table a { color: var(--accent); }
|
||||||
|
|
||||||
|
.contact-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.contact-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 1rem;
|
||||||
|
border: 2px solid var(--ink);
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--ink);
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-card:hover {
|
||||||
|
background: var(--accent-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.method.post {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #8b4513;
|
||||||
|
background: #fde8d8;
|
||||||
|
align-self: flex-start;
|
||||||
|
padding: 0.1rem 0.35rem;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-card .desc {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
17
spec/spec.js
Normal file
17
spec/spec.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const sections = document.querySelectorAll('section[id]');
|
||||||
|
const links = document.querySelectorAll('.toc nav a');
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (!entry.isIntersecting) return;
|
||||||
|
links.forEach((a) => {
|
||||||
|
a.style.fontWeight = a.getAttribute('href') === `#${entry.target.id}` ? '600' : '';
|
||||||
|
a.style.color = a.getAttribute('href') === `#${entry.target.id}` ? 'var(--accent)' : '';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ rootMargin: '-30% 0px -60% 0px' }
|
||||||
|
);
|
||||||
|
|
||||||
|
sections.forEach((s) => observer.observe(s));
|
||||||
88
vault/index.html
Normal file
88
vault/index.html
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Levkin — Software Development</title>
|
||||||
|
<meta name="description" content="Levkin — trusted software development for enterprise teams." />
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,500;0,600;1,400&family=Source+Sans+3:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="./vault.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="frame">
|
||||||
|
<nav class="nav">
|
||||||
|
<a href="/" class="nav-back">All options</a>
|
||||||
|
<span class="seal">Levkin</span>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<header class="hero">
|
||||||
|
<p class="charter">Chartered software practice · Canada</p>
|
||||||
|
<h1>Built to hold.<br /><em>Built to hand off.</em></h1>
|
||||||
|
<p class="lead">Levkin develops production systems, automation, and enterprise software for organizations that cannot afford failure in the field.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="holdings">
|
||||||
|
<h2 class="section-label">Holdings</h2>
|
||||||
|
<div class="holding-grid">
|
||||||
|
<article class="holding">
|
||||||
|
<h3>Custom software</h3>
|
||||||
|
<p>Applications, APIs, and internal platforms engineered for longevity and auditability.</p>
|
||||||
|
</article>
|
||||||
|
<article class="holding">
|
||||||
|
<h3>Automation</h3>
|
||||||
|
<p>Operational pipelines and integrations. <a href="https://auto.levkin.ca">auto.levkin.ca</a></p>
|
||||||
|
</article>
|
||||||
|
<article class="holding">
|
||||||
|
<h3>CaseWare practice</h3>
|
||||||
|
<p>Fifteen years in audit and accounting systems. <a href="https://caseware.levkin.ca">caseware.levkin.ca</a></p>
|
||||||
|
</article>
|
||||||
|
<article class="holding">
|
||||||
|
<h3>Internal operations</h3>
|
||||||
|
<p>Restricted orchestration systems. <a href="https://jobs.levkin.ca">jobs.levkin.ca</a></p>
|
||||||
|
</article>
|
||||||
|
<article class="holding">
|
||||||
|
<h3>Quality engineering</h3>
|
||||||
|
<p>SDET portfolio — test automation, CI/CD, trace-driven QA. <a href="https://iliadobkin.com">iliadobkin.com</a></p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="covenant">
|
||||||
|
<h2 class="section-label">Covenant</h2>
|
||||||
|
<ul>
|
||||||
|
<li><span class="mark">§</span> Reliability is documented, not assumed</li>
|
||||||
|
<li><span class="mark">§</span> Every deliverable includes a handoff path</li>
|
||||||
|
<li><span class="mark">§</span> Tests precede production data</li>
|
||||||
|
<li><span class="mark">§</span> Scope changes require explicit amendment</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="process">
|
||||||
|
<h2 class="section-label">Engagement</h2>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Discovery</strong> — Understand constraints and stakeholders</li>
|
||||||
|
<li><strong>Proposal</strong> — Fixed scope, timeline, and cost</li>
|
||||||
|
<li><strong>Delivery</strong> — Production-ready, tested, documented</li>
|
||||||
|
<li><strong>Transition</strong> — Optional stewardship or clean exit</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="contact">
|
||||||
|
<div class="contact-panel">
|
||||||
|
<p class="contact-title">Open an enquiry</p>
|
||||||
|
<a href="https://cal.levkin.ca/ilia/consult" class="contact-email">Book 15 min consultation</a>
|
||||||
|
<a href="mailto:hello@levkine.ca?subject=Vault%20enquiry" class="contact-email contact-email-secondary">hello@levkine.ca</a>
|
||||||
|
<p class="contact-note">Remote · North America & Europe</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<span>levkin.ca</span>
|
||||||
|
<a href="https://git.levkin.ca">Source repository</a>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
242
vault/vault.css
Normal file
242
vault/vault.css
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
:root {
|
||||||
|
--forest: #0c1410;
|
||||||
|
--forest-mid: #142820;
|
||||||
|
--brass: #c9b896;
|
||||||
|
--brass-dim: rgba(201, 184, 150, 0.5);
|
||||||
|
--cream: #f0ebe3;
|
||||||
|
--muted: #7a8f82;
|
||||||
|
--serif: 'Cormorant Garamond', Georgia, serif;
|
||||||
|
--sans: 'Source Sans 3', system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--sans);
|
||||||
|
background: var(--forest);
|
||||||
|
color: var(--cream);
|
||||||
|
min-height: 100vh;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
max-width: 680px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 2rem 4rem;
|
||||||
|
border-left: 1px solid var(--brass-dim);
|
||||||
|
border-right: 1px solid var(--brass-dim);
|
||||||
|
min-height: 100vh;
|
||||||
|
background: linear-gradient(180deg, var(--forest-mid) 0%, var(--forest) 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
border-bottom: 1px solid var(--brass-dim);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back {
|
||||||
|
color: var(--muted);
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back:hover { color: var(--brass); }
|
||||||
|
|
||||||
|
.seal {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--brass);
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
padding: 3.5rem 0 3rem;
|
||||||
|
border-bottom: 1px solid var(--brass-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.charter {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: clamp(2rem, 6vw, 2.75rem);
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
color: var(--cream);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 em {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--brass);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
font-size: 1.05rem;
|
||||||
|
color: var(--muted);
|
||||||
|
max-width: 40ch;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.25em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--brass);
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
padding-top: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.holdings { padding-bottom: 1rem; }
|
||||||
|
|
||||||
|
.holding-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 1px;
|
||||||
|
background: var(--brass-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.holding {
|
||||||
|
background: var(--forest);
|
||||||
|
padding: 1.35rem 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.holding h3 {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--brass);
|
||||||
|
margin-bottom: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.holding p {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.holding a {
|
||||||
|
color: var(--brass);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.holding a:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
.covenant ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.covenant li {
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
border-bottom: 1px solid rgba(201, 184, 150, 0.12);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--muted);
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mark {
|
||||||
|
color: var(--brass);
|
||||||
|
font-family: var(--serif);
|
||||||
|
}
|
||||||
|
|
||||||
|
.process ol {
|
||||||
|
list-style: none;
|
||||||
|
counter-reset: step;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process li {
|
||||||
|
counter-increment: step;
|
||||||
|
padding: 0.75rem 0;
|
||||||
|
border-bottom: 1px solid rgba(201, 184, 150, 0.12);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--muted);
|
||||||
|
padding-left: 2rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process li::before {
|
||||||
|
content: counter(step, decimal-leading-zero);
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
font-family: var(--serif);
|
||||||
|
color: var(--brass);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process strong {
|
||||||
|
color: var(--cream);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact {
|
||||||
|
padding: 3rem 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-panel {
|
||||||
|
border: 1px solid var(--brass);
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
background: rgba(201, 184, 150, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-title {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
letter-spacing: 0.15em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--brass);
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-email {
|
||||||
|
font-family: var(--serif);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--cream);
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-email:hover { color: var(--brass); }
|
||||||
|
|
||||||
|
.contact-email-secondary {
|
||||||
|
display: block;
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-email-secondary:hover { color: var(--brass); }
|
||||||
|
|
||||||
|
.contact-note {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 2rem;
|
||||||
|
border-top: 1px solid var(--brass-dim);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted);
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--muted);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover { color: var(--brass); }
|
||||||
16
vite.config.js
Normal file
16
vite.config.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { resolve } from 'path';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
input: {
|
||||||
|
main: resolve(__dirname, 'index.html'),
|
||||||
|
spec: resolve(__dirname, 'spec/index.html'),
|
||||||
|
slab: resolve(__dirname, 'slab/index.html'),
|
||||||
|
relay: resolve(__dirname, 'relay/index.html'),
|
||||||
|
vault: resolve(__dirname, 'vault/index.html'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user