docs(specs): 009 work page, CV first, with its plan and mockup rounds

Six rounds of mockups with the owner on 2026-11-12; K v2 picked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-11-12 10:03:26 +01:00
1 parent 5ba0be8c74
commit 1041c8e5b8
10 files changed
+2687

No files matched your search

+23
View File
@@ -220,6 +220,29 @@ dated "Lately" list across both sides (`mockups/simple-side-a.html`, `simple-sid
gacha-event-tracker for work and Saltlakridserne for off-the-clock, and then have the app fill in the rest by newest."
That is `docs/specs/008-simple-side-index.md` (approved, not built yet on his request).
## Work page, CV first (2026-11-12)
His feedback on `/work/`: everything had the same weight; he wanted a grid with the impressive projects accentuated,
and room for courses, certificates, competitions and other accolades. He named the six that matter: Event Tracker for
Gacha Games, Config, Bachelor Report, Student Dashboard, Mixed-Reality Rowing Game, VR-Classroom. Courses come from
his own spreadsheet; competitions from his CV; Art Bubble and Lystrup Genbrugser are volunteer IT/website work
("not just my project"), so they belong with recognition, not with the projects. Rounds (all in `mockups/work-*.html`):
- **r1** A one grid three sizes, B picked six + tight grid, C hero + uneven grid: "none are completely what I imagine".
Liked: course counts ("8 courses · 3 labs") and time spent; wants certificates shown clearly, and certificates found
when searching the work page. Orange for the most impressive accolades.
- **r2** D woven grid, E packed by size: "too chaotic". **r3** F alternating bands, G picked + index column, H two
sizes even grid: F and H closest, "still a bit too chaotic and unfocused". **r4** equal blocks with greyscale
screenshots: no. **Colour on hover is nice, but full desaturation makes the page look boring and not interactable.**
- Then the picture in his words: the first thing seen is the **CV in ten seconds**; writing matters less (few posts);
then the most impressive projects first, the weaker ones viewable but less focused "so the ones of more questionable
quality isn't clicked too much on"; certificates and the main accolades near the top, full detail at the bottom.
- **r5** K CV hero, L CV sidebar, M at-a-glance band: **K closest.** "Projects I'm proudest of" should get more detail;
"also made" should keep today's list view. Remove Bluesky from the work side (keep /simple, GitHub, LinkedIn, email).
- **K v2** (`mockups/work-k2.html`): K's header + the featured panels of the approved `tech-r3-c` ("Look at the
featured section here. This is really good.") + today's list + the record. **Picked**: "This looks like a good
improvement. Lets make it work!" → `docs/specs/009-work-page-cv-first.md`.
## Decisions so far (summary, 2026-11-09)
- **Start page:** `mockups/nav-d.html`, with two gates (work on the left, off the clock on the right) and a small "wander through everything at once" link to the garden (`nav-c.html` idea).
+88
View File
@@ -0,0 +1,88 @@
---
status: approved
---
# Plan 009 — `/work/`: CV first, six proud projects, record of competitions and courses
Spec: `docs/specs/009-work-page-cv-first.md`. Mockup: `mockups/work-k2.html`, `mockups/shots/work-k2-1440.png`
(built from `mockups/tech-r3-c.html`, whose featured panels are already the site's `Featured.astro`).
Branch: `feat/work-page-cv-first`. Commands: `bun run typecheck`, `bun test`, `bunx playwright test` (`--workers=2`
if pages crash).
**Commit rule.** Tasks 1–2 (data and pure logic) are committed as they finish. Tasks 3–9 change what visitors see:
build and test them, but leave them **uncommitted** until the owner has looked at the rendered preview (his standing
rule: visual changes are shown before they are committed). Task 10 is the preview.
TDD for every task: write the failing test, run it and see it fail, write the code, see it pass.
Test imports use explicit `.ts` extensions. `src/core` stays pure (no imports from other `src/` folders, no I/O).
## 1. Content: `recognition.yml` and `courses.yml` (commit)
- [ ] `test/library/load.test.ts`: both files load (order kept for recognition); missing files → empty lists; one error
per problem with file and field: missing required field, wrong `kind`, bad `completed` date (incl. 2025-02-30),
non-positive or non-integer `minutes`, non-boolean `certificate`/`highlight`, bad `url`, `status` on a
competition or not `ongoing|retired`, `keywords` not a list of text, unknown key, file not a list, entry not a map.
- [ ] `src/library/types.ts`: `Recognition` (`title, kind: 'competition'|'volunteering', result, highlight, detail?,
year?, url?, status?`) and `Course` (`title, provider, kind: 'course'|'lab', topic, completed, minutes,
certificate, url?, keywords: string[]`); `Content.recognition`, `Content.courses`.
- [ ] `src/library/load.ts`: read both optional files (a missing file is not an error); validate as above.
- [ ] `fixtures/content/recognition.yml`, `fixtures/content/courses.yml`: synthetic, enough to exercise every branch
(≥ 4 highlighted entries so the "+N more" shows; both kinds; one with `url`, one `retired`; ≥ 3 topics, labs and
courses, some without certificate). `fixtures/sparse/` gets neither file.
- [ ] `docs/CONTENT-CONTRACT.md`: both files, as in the spec; `intro` no longer shown on `/work/`.
- [ ] Commit `feat(library): recognition.yml and courses.yml`.
## 2. Pure course logic in `src/core/courses.ts` (commit)
- [ ] `test/core/courses.test.ts`: `courseSummary(courses)` → `{ count, certificates, minutes, since (YYYY-MM), topics:
[{ topic, courses, labs, certificates, minutes }] }` with topics ordered by minutes desc then name;
`courseMatches(course, query)` (case-insensitive over title, provider, topic, keywords; empty query → false);
`formatHours(minutes)` ("9.4h"; "~27 h" form for the totals is the caller's); `monthYear('2025-02')` → "Feb 2025".
- [ ] `src/core/courses.ts` (takes a plain course shape, not the library type). Commit `feat(core): course summary and search`.
## 3. Six featured panels and muted screenshots (do not commit)
- [ ] Test for the pure part in `sections.ts`: `featuredOf` returns up to 6; `featLayout(n)` is
`['wide','','','wide rev','','']` sliced to n, with a trailing lone half made `wide`:
n=1 → wide; n=2 → wide, wide; n=3 → wide, half, half; n=4 → … wide rev; n=5 → … wide rev, wide; n=6 → as listed.
- [ ] `Featured.astro` uses it; heading "Projects I'm proudest of", hint, AI legend line at the right (moved from intro).
- [ ] CSS: `.feat` image stages and `.row` thumbnails muted (`saturate(.5) brightness(.8)`), full colour on
`:hover`/`:focus-within`; transition 300 ms, none under `prefers-reduced-motion`. Drawn showcases untouched.
- [ ] Fixtures: six featured fixture projects (add `featured` to existing synthetic ones / add synthetic ones).
## 4. CV header (do not commit)
- [ ] `src/site/components/work/WorkHeader.astro` replaces the intro block and `NowStrip.astro` (delete it if unused).
Content and fallbacks exactly as spec §1. Uses `courseSummary`.
- [ ] `test/site/build-pages.test.ts`: header rows, highlights (max 3, "+N more"), keeping-up count/line/chips,
blocks left out on the sparse fixture, `site.now` list.
## 5. Also made + certificate search (do not commit)
- [ ] `ProjectList.tsx`: heading "Also made"; new prop `courses` (minimal fields); when the query is non-empty show the
matching-courses strip (max 5, "+ N more on the learning page →" to `/work/learning/?q=`), and the count text
"<p> project(s) · <c> course(s) match" (spec: courses, labs included; a seal marks the ones with a certificate).
- [ ] Tests: unit test for the strip's data (pure helper) + Playwright check in `e2e/work.spec.ts`.
## 6. Record section (do not commit)
- [ ] `src/site/components/work/Record.astro` (`#record`) as spec §4; `workSections` gains `record`.
- [ ] Build test: both cards, groups, accent on highlights, status words, years only when present, topic table.
## 7. `/work/learning/` (do not commit)
- [ ] `src/site/pages/work/learning.astro` (only when courses exist) + `src/site/scripts/learning-filter.ts` (plain
script: search, topic buttons, `?q=`, "No course matches").
- [ ] Add to the sitemap page list (`src/site/feeds.ts`), not to feeds.
- [ ] Tests: build test (rows newest first, no page without courses), sitemap test, Playwright (filter, `?q=`,
no-JS shows all rows in `e2e/nojs.spec.ts`).
## 8. Top bar and footer (do not commit)
- [ ] `TopBar.astro`: Projects (`#featured`), Record (`#record`), Writing, CV — only existing sections; on
`/work/learning/` the links point to `/work/#…`.
- [ ] `Work.astro`: no Bluesky link. Personal footer and `/simple` unchanged. Tests for both footers.
## 9. Checks and docs (do not commit)
- [ ] `bun run typecheck`, `bun test`, `bunx playwright test` all pass; update existing tests that asserted the old
intro, "All projects"/"Everything else" headings, the Now strip or a four-panel cap.
- [ ] Axe checks in `e2e/a11y.spec.ts` cover `/work/` and `/work/learning/`.
- [ ] `docs/ARCHITECTURE.md` (new files, `src/core/courses.ts`, learning page), `docs/DECISIONS.md` (the [call]s),
`DESIGN.md` work section, `docs/TODO.md` (anything noticed and left), spec status → `implemented` after review.
## 10. Preview for the owner (main session)
- [ ] Build a temporary copy of the real content with the proposed `recognition.yml`, `courses.yml`, featured ranks
and showcases (scratchpad `content-proposal/`); serve on port 4392; screenshots at 1440 and 390 in `~/`.
- [ ] Wait for his look; then commit tasks 3–9 in small Conventional Commits; remove this plan before merging.
+178
View File
@@ -0,0 +1,178 @@
---
status: approved
---
# 009 — `/work/`: CV first, six proud projects, a record of competitions and courses
Designed with the owner on 2026-11-12 over six rounds of rendered mockups (log in `docs/inspiration.md`,
"Work page, CV first"). He picked **K** and then its refinement, built on the approved `mockups/tech-r3-c.html`:
"This looks like a good improvement. Lets make it work!" Design truth: `mockups/work-k2.html` (screenshot
`mockups/shots/work-k2-1440.png`). Extends `docs/specs/001-site.md` §8 (the work space). Choices marked **[call]**
were made while writing the spec, not by the owner.
## Why
The owner has made many projects of uneven quality, and the page gave them all the same weight; there was no place for
his courses, certificates, competitions or volunteer work. In his words, a visitor should first see the CV in ten
seconds, then "the most impressive projects I've made first, with the other less important ones still viewable … but
less focused", and near the top "the certificates/courses and most important accolades, with fuller information near
the bottom". Courses should show that he keeps up to date and "actively works to keep himself knowledgeable", with a
searchable list "somewhere, but it doesn't need to be front and center".
## What
### Page order on `/work/` (top to bottom)
1. **CV header** (replaces today's intro block and the Now / Latest writing / CV strip).
2. **Projects I'm proudest of**: the featured projects as large panels (today's `Featured`, extended to six).
3. **Also made**: today's project list (tabs, search, thumbnails, side sheet) with the remaining projects.
4. **Record**: recognition & volunteering next to keeping up (courses), the full versions.
5. **Writing** and **Where I've worked**, as today.
6. Footer.
Every section that has no content is left out, and the top bar links only to sections that exist (as today).
### 1. CV header
One card, two columns (stacked on narrow screens):
- **Left, "CV in ten seconds"**: `site.name` as the heading, `site.tagline` under it; rows *now* (`cv.now`), *before*
(`cv.before`, one per line), *degree*, *contact* (email); if `site.now` has lines they are shown as a short list
under the rows **[call]** (today's "Now" cell has no other home). Buttons: CV PDF (only when `links.cv`), "full
history ↓" (to `#cv`), GitHub, LinkedIn.
- **Right, two blocks**:
- **Highlights**: recognition entries marked `highlight: true`, in file order, at most **3** **[call]**; each title
and result in the accent colour. A link "+ N more in the record ↓" when the record holds more entries than shown.
No highlighted entries: the block is left out.
- **Keeping up**: a large certificate count with the seal mark ("18 certificates"), then one mono line:
"<n> courses & hands-on labs · ~<h> h since <Mon YYYY of the earliest completion>"; then up to **5** topic chips,
"<topic> <certificates>", topics ordered by total time, largest first **[call]**; topics are short names
(one field serves chips, table and filters, so content keeps them short, e.g. "Ansible", "RAG & LLMs"); link "all courses ↓" (to the
record). No courses: the block is left out. No certificates but courses: the count line leads instead.
- Both blocks missing: the card is one column.
- The page's AI explanation moves to the right of the "Projects I'm proudest of" heading: one short line plus the
legend marks. **[call]** `site.intro` is no longer shown on `/work/`; `docs/CONTENT-CONTRACT.md` says so.
### 2. Projects I'm proudest of
- Heading "Projects I'm proudest of", count, hint "hover the drawings · open a panel for the full story".
- Up to **6** featured projects (today: 4), by `featured` rank. Layout by position, repeating:
`1 wide · 2–3 halves · 4 wide reversed · 5–6 halves`. With fewer than six the pattern stops where they end; an odd
last half takes the full row width as a wide panel **[call]**.
- Panels are today's: showcase (or image) + number, group and where, title, summary, the *why* / *interesting*
facts from the body (`panelFacts`, unchanged: rows with no matching section are left out, never placeholders),
stack chips, "Read the full story" / "Read more", AI mark, filter note when hidden.
- **Screenshots are muted**: an `image` in a panel (and a thumbnail in the list) is shown desaturated and slightly
darker (about half saturation, 80% brightness) and comes to full colour when the pointer is over its panel or row, or
the panel has keyboard focus within. Drawn showcases are not muted. Owner: full greyscale "makes the page look boring
and not interactable"; the colour on hover "is nice". Under `prefers-reduced-motion` the change is instant.
### 3. Also made
Today's `ProjectList` with the non-featured projects, heading "Also made" (was "All projects" / "Everything else").
Behaviour unchanged (tabs, search, thumbnails, side sheet, AI filter), plus:
- **Search finds certificates too.** When the search box has text, the courses whose title, provider, topic or
keywords match are listed under the search, above the project rows, as a compact strip: seal mark when there is a
certificate, title, "lab" tag for labs, provider · month year · duration. At most **5** shown, then
"+ N more on the learning page →" linking to `/work/learning/?q=<text>`. The count next to the heading reads e.g.
"1 project · 5 courses match" (labs count as courses here; the seal marks which carry a certificate) **[call]**. **[call]** Courses never appear when the search is empty, and they are not
affected by the AI preference (courses carry no AI level).
### 4. Record (`#record`)
Two cards side by side (stacked on narrow screens). Either card is left out without content; with neither, the
section is left out.
- **Recognition & volunteering**: two groups, "Competitions" and "Volunteering" (a group with no entries is left
out), entries in file order. Each row: title (a link when `url` is given, with its host and ↗), an optional small
detail after it, and at the right the result; for volunteering, the role and then "ongoing" or "site retired" when
`status` says so. `highlight: true` entries show title and result in the accent colour. Years appear only when given.
- **Keeping up**: summary line (seal, "<n> certificates", "from <n> courses and hands-on labs", "~<h> hours of course
time since <Mon YYYY>"), then a table by topic, ordered by total time: topic · "<a> courses · <b> labs" (a part
that is zero is left out) · seal + certificate count · hours (one decimal, "h"). Then a link
"All courses and certificates, searchable →" to `/work/learning/`.
- Hours are course time only (from `minutes`); the page says "course time", never more.
### 5. `/work/learning/` (new page)
A quiet page in the work frame: heading "Courses & certificates", the same summary line, a search field and topic
filter buttons ("All <n>", then each topic with its count), and a table, newest first: completed (date), course (title,
a link when `url` is given; "lab" tag for labs), topic, provider, certificate (seal or —), time.
- Complete without JavaScript: the full table is in the HTML. A small plain page script (no React) filters rows by the
search text (title, provider, topic, keywords) and the topic button, and reads `?q=` on load. Rows not matching are
`hidden`; a "No course matches" line appears when none do.
- In the sitemap; not in the feeds. Linked from the record, from the search strip, and in the top bar of this page.
- Without any courses the page is not built and nothing links to it.
### 6. Top bar and footer (work space)
- Top bar links on `/work/`: Projects (`#featured`), Record (`#record`), Writing, CV, each only when its section exists.
"All projects" goes; the list is reached by scrolling or from Projects. **[call]**
- Work footer: back to the gate, `/simple`, GitHub, LinkedIn, email. **The Bluesky link is removed from the work
footer** (owner, 2026-11-12). The off-the-clock footer and `/simple` keep it.
### Content: two new optional files (content repo root)
`docs/CONTENT-CONTRACT.md` documents both. Both are optional; a missing file means no entries. **[call]** No
`contract` bump: an older app ignores unknown files and a newer app reads content without them (the same reasoning as
spec 008's `pins`).
`recognition.yml`, a list, file order = display order:
```yaml
- title: AUHackathon 2019 # required
kind: competition # required: competition | volunteering
result: winner · best AUHack # required for competitions; for volunteering the role, e.g. "IT & website"
highlight: true # optional, default false; candidates for the header (first 3)
detail: four years # optional short text after the title
year: 2019 # optional text ("2019", "2016–2019"); shown only when present
url: https://example.invalid # optional http(s)
status: ongoing # optional, volunteering only: ongoing | retired
```
`courses.yml`, a list (any order; the site sorts):
```yaml
- title: Ansible Fundamentals # required
provider: Pluralsight # required
kind: course # required: course | lab
topic: Ansible # required, a short name; courses with the same text group together
completed: 2025-04-18 # required, a real calendar date
minutes: 224 # required, positive integer (course time only)
certificate: true # optional, default false
url: https://example.invalid # optional http(s)
keywords: [ansible, automation] # optional list of text, used by search only
```
Validation follows the existing loader: every problem is listed with its file and field; unknown keys are errors
**[call]** (catches typos like `certifcate`), as for projects.
### Content changes the owner makes (not in this repo)
For the real site, in `portfolio-next-content`: `featured` ranks for the six (Gacha 1, Config 2, Bachelor Report 3,
Mixed-Reality Rowing Game 4, Student Dashboard 5, VR-Classroom 6), `showcase: config-editor` on Config,
`peer-network` on Bachelor Report, `rowing-stroke` on the Rowing game; `## Why` and `## What's interesting` sections
in project bodies where he wants the facts rows; `recognition.yml` from his CV lines; `courses.yml` from his
spreadsheet "Courses and Learning.xlsx" (the WordPress course has no completion date and stays out until it has one).
The implementation prepares these as a folder outside both repos (the session scratchpad, `content-proposal/`),
uses it only through a temporary copy of the real content for the preview, and hands it to the owner; it never writes
to the `portfolio-next-content` clone. Rules for that set:
- Only facts he gave: the four CV lines and the two volunteer roles as he wrote them; unknown years are left out
(no placeholders on the real site). No `## Why` / `## What's interesting` text is written for him; panels without
those sections simply show no facts rows.
- Spreadsheet mapping **[call]**: one row per completed course (rows without a completion date are left out);
`kind: lab` when "Course Type" contains "Lab"; `minutes` from "Course Hours"; `certificate: true` when
"Certificate Available?" is "Yes" (he asked for the page to "show that I got certificates from them"; Pluralsight
issues a certificate for every completed course that offers one); `keywords` from "Keywords"; `url` from "Link".
`topic` is a hand grouping of "Bottom Category" into short names, the same text in chips, table and filter:
Serverless → "Serverless / AWS", Ansible → "Ansible", Machine Learning and LLMs/RAG → "RAG & LLMs",
Linux & System Administration → "Linux", Security → "Security", Metrics/logging → "Observability".
## Non-goals
- No new drawn showcases (Gacha, Student Dashboard, VR-Classroom use their screenshots).
- No Skill IQ percentiles (left out on purpose during design).
- No change to the side sheet, project pages, writing pages, the off-the-clock side or `/simple` (beyond what is
named above).
- No certificate PDFs or images.
## Anti-goals (owner's hard lines)
Nothing moves unless the visitor acts; no trophy icons, badges walls or anything that sells; no uneven "bento"
mosaic (tried in rounds 2–4 and rejected as "too chaotic and unfocused"); no greyscale screenshots.
## Acceptance
- `/work/` on the fixtures shows, in order: CV header (with highlights and keeping up), Projects I'm proudest of,
Also made, Record, Writing, Where I've worked; each section disappears when its content is missing.
- Six featured fixture projects lay out as wide, half, half, wide reversed, half, half at ≥ 1100 px; one column on a
phone; five featured ends with a wide panel.
- Screenshot panels and list thumbnails are muted until hovered; drawings are not.
- Searching the list for a fixture keyword shows matching courses with the right count and the learning-page link.
- `/work/learning/` lists every fixture course newest first; search and topic filter hide rows; `?q=` pre-filters;
without JavaScript every row is visible.
- The work footer has no Bluesky link; the off-the-clock footer still does.
- `validate` reports each malformed field of `recognition.yml` and `courses.yml`, by file and field.
- Typecheck, `bun test` and Playwright pass; the page is checked at 1440 px and 390 px.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+1060
View File
File diff suppressed because it is too large. Load diff
+269
View File
@@ -0,0 +1,269 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Work page: three directions</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{--bg:#131210;--panel:#1b1916;--panel2:#221f1b;--line:#2b2824;--ink:#ede7dd;--mute:#8e877c;--acc:#ea7444;--ok:#a8b48f;
--sans:'Geist',system-ui,sans-serif;--mono:'Geist Mono',ui-monospace,monospace;--e:cubic-bezier(.2,.8,.2,1)}
*{box-sizing:border-box}html,body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 var(--sans)}
a{color:inherit;text-decoration:none}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.opt-head{border-top:1px dashed #3a352f;margin-top:80px;padding:28px 0 8px;display:flex;gap:18px;align-items:baseline}
.opt-head:first-of-type{margin-top:24px;border-top:0}
.opt-head .L{font:600 13px var(--mono);color:var(--bg);background:var(--acc);border-radius:4px;padding:2px 8px}
.opt-head h1{font-size:22px;margin:0;font-weight:600}
.opt-head p{margin:0;color:var(--mute);max-width:640px}
.note{font:12px/1.5 var(--mono);color:var(--mute);border-left:2px solid var(--acc);padding:2px 0 2px 12px;margin:10px 0 24px;max-width:820px}
.sh{display:flex;align-items:baseline;gap:12px;margin:40px 0 16px}
.sh h2{font-size:22px;margin:0;font-weight:600}.sh .n{font:12px var(--mono);color:var(--mute)}
.sh .r{margin-left:auto;font:12px var(--mono);color:var(--mute)}
.mk{display:inline-flex;align-items:center;gap:6px;font:11px var(--mono);border:1px solid var(--line);border-radius:99px;padding:2px 8px;white-space:nowrap;color:var(--ink)}
.mk i{width:8px;height:8px;border-radius:50%;border:1.5px solid currentColor;display:inline-block}
.mk.ai{color:var(--acc);border-color:#6b3a26}.mk.ai i{background:var(--acc);border-color:var(--acc)}
.meta{font:11px var(--mono);color:var(--mute);letter-spacing:.02em}
.chips{display:flex;gap:6px;flex-wrap:wrap}.chip{font:11px var(--mono);color:var(--mute);border:1px solid var(--line);border-radius:4px;padding:1px 6px}
.shot{background:#0e0d0c center/cover no-repeat;border-bottom:1px solid var(--line)}
.card{background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;transition:border-color .2s var(--e),transform .2s var(--e)}
.card:hover{border-color:#4a433b}
.card .txt{padding:16px 18px}
.card h3{margin:6px 0 4px;font-size:18px;font-weight:600}
.card p{margin:0 0 12px;color:#c9c2b6;font-size:14px}
.ft{display:flex;align-items:center;justify-content:space-between;margin-top:12px}
.ft .open{font:12px var(--mono);color:var(--acc)}
/* drawn showcase stand-ins */
.draw{position:relative;background:var(--panel2);border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:center}
.draw .tag{position:absolute;top:10px;left:12px;font:10px var(--mono);color:var(--mute)}
.code{font:11px/1.7 var(--mono);color:#b9b2a6;padding:26px 22px;width:100%}
.code b{color:var(--acc);font-weight:400}.code u{color:var(--ok);text-decoration:none}
/* small tiles */
.mini{display:flex;gap:12px;align-items:center;padding:10px 12px;background:var(--panel);border:1px solid var(--line);border-radius:8px}
.mini .th{width:56px;height:38px;border-radius:4px;background:#0e0d0c center/cover;flex:none;border:1px solid var(--line)}
.mini h4{margin:0;font-size:14px;font-weight:500}.mini .meta{font-size:10.5px}
.mini .mk{margin-left:auto;font-size:10px;padding:1px 6px}
/* ---------- A ---------- */
.gA{display:grid;grid-template-columns:repeat(12,1fr);gap:14px}
.gA .big{grid-column:span 6}.gA .mid{grid-column:span 4}.gA .sm{grid-column:span 3}
.gA .big .shot,.gA .big .draw{height:230px}.gA .mid .shot,.gA .mid .draw{height:170px}
/* recognition strip */
.rec{display:grid;grid-template-columns:1.1fr 1fr;gap:14px;margin-top:14px}
.box{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.box h3{margin:0 0 12px;font:500 11px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
.led{display:grid;grid-template-columns:52px 1fr auto;gap:4px 14px;font-size:14px}
.led>div{padding:8px 0;border-top:1px solid var(--line)}
.led .y{font:12px var(--mono);color:var(--mute)}
.led .res{font:12px var(--mono);color:var(--mute);text-align:right}
.led .res.win{color:var(--acc)}
.cl{display:grid;grid-template-columns:1fr auto;gap:0 14px;font-size:14px}
.cl>div{padding:7px 0;border-top:1px solid var(--line)}.cl .c{font:12px var(--mono);color:var(--mute);text-align:right}
.more{display:inline-block;margin-top:12px;font:12px var(--mono);color:var(--acc)}
/* ---------- B ---------- */
.gB{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.gB .shot,.gB .draw{height:180px}
.gBs{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:10px}
.cvs{display:grid;grid-template-columns:1fr 1fr;background:var(--panel);border:1px solid var(--line);border-radius:10px;margin-top:24px}
.cvs>div{padding:18px 20px}.cvs>div+div{border-left:1px solid var(--line)}
.cvs h3{margin:0 0 10px;font:500 11px var(--mono);letter-spacing:.08em;color:var(--mute)}
.kv{display:grid;grid-template-columns:72px 1fr;gap:6px 14px;font-size:14px}.kv .k{font:11px var(--mono);color:var(--mute);padding-top:2px}
.kv .acc{color:var(--acc)}
.lower{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:40px}
.log>div{display:grid;grid-template-columns:70px 1fr auto;gap:12px;padding:8px 0;border-top:1px solid var(--line);font-size:14px}
.log .d{font:11px var(--mono);color:var(--mute);padding-top:3px}.log .k{font:10.5px var(--mono);color:var(--ok);border:1px solid #3d4433;border-radius:4px;padding:0 5px;height:18px;align-self:center}
.topics{display:flex;gap:6px;flex-wrap:wrap;margin:14px 0 2px}
/* ---------- C ---------- */
.gC{display:grid;grid-template-columns:repeat(6,1fr);grid-auto-rows:118px;gap:14px}
.gC .card{display:flex;flex-direction:column}
.gC .card .shot,.gC .card .draw{flex:1;min-height:0}
.gC .card .txt{padding:12px 16px}
.gC .card h3{font-size:16px;margin:2px 0 0}
.gC .card p{display:none}
.gC .hero{grid-column:span 4;grid-row:span 4}.gC .hero p{display:block;margin:6px 0 0}
.gC .hero h3{font-size:22px}
.gC .tall{grid-column:span 2;grid-row:span 2}
.gC .wide{grid-column:span 2;grid-row:span 2}
.gC .mini{grid-column:span 2;align-self:stretch}
.track{margin-top:44px;display:grid;grid-template-columns:260px 1fr;gap:0;border-top:1px solid var(--line)}
.track .lab{padding:20px 0;font:500 11px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;border-bottom:1px solid var(--line)}
.track .lab span{display:block;font:13px var(--sans);text-transform:none;letter-spacing:0;color:var(--mute);margin-top:6px;max-width:220px}
.track .row{padding:20px 0;border-bottom:1px solid var(--line)}
.medals{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
.medal .y{font:12px var(--mono);color:var(--mute)}.medal .t{font-weight:500;margin:4px 0}.medal .r{font:12px var(--mono);color:var(--mute)}
.medal .r.win{color:var(--acc)}
.bars{display:grid;grid-template-columns:150px 1fr 70px;gap:8px 14px;align-items:center;font-size:14px}
.bar{height:8px;background:var(--panel2);border-radius:99px;overflow:hidden}.bar i{display:block;height:100%;background:#8e877c;border-radius:99px}
.bars .c{font:11px var(--mono);color:var(--mute)}
/* learning page */
.lp{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:20px 22px;margin-top:14px}
.lp .top{display:flex;gap:10px;align-items:center;margin-bottom:12px}
.search{flex:1;max-width:380px;background:var(--bg);border:1px solid var(--line);border-radius:6px;padding:7px 10px;font:13px var(--sans);color:var(--mute)}
.seg{display:flex;gap:4px}.seg span{font:12px var(--sans);color:var(--mute);padding:4px 9px;border-radius:5px}.seg span.on{background:var(--panel2);color:var(--ink)}
table{width:100%;border-collapse:collapse;font-size:13.5px}td,th{text-align:left;padding:8px 10px 8px 0;border-top:1px solid var(--line);vertical-align:top}
th{font:500 10.5px var(--mono);letter-spacing:.06em;color:var(--mute);text-transform:uppercase;border-top:0}
td.m{font:12px var(--mono);color:var(--mute);white-space:nowrap}
.pick{display:flex;gap:10px;margin:22px 0 60px}
.pick button{font:13px var(--mono);background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:8px 14px;cursor:pointer}
.pick button.selected,.pick button:hover{border-color:var(--acc);color:var(--acc)}
</style>
</head>
<body>
<div class="wrap">
<p class="meta" style="margin-top:28px">Mockups · work page · everything uses your real titles, screenshots, CV lines and spreadsheet. The top bar, intro and CV strip are unchanged and left out.</p>
<!-- ================= A ================= -->
<div class="opt-head"><span class="L">A</span><div><h1>One grid, three sizes</h1><p>All 13 projects in one grid. The six are big or medium tiles, and the rest are compact cards. Under it, a single "Record" band: competitions on the left, learning by topic on the right.</p></div></div>
<div class="note">Risk: this is the closest to the "generic bento" look your DESIGN.md rules out. It's saved by the drawn showcases and the plain tiles, but it's the most template-like of the three.</div>
<div class="sh"><h2>Projects</h2><span class="n">13 · 6 picked</span><span class="r">All · Own · School · search</span></div>
<div class="gA">
<article class="card big"><div class="shot" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="txt"><div class="meta">01 · Own · personal project</div><h3>Event Tracker for Gacha Games</h3><p>Used to easily figure out which live service games events to prioritize.</p><div class="chips"><span class="chip">scraping</span><span class="chip">webapp</span><span class="chip">javascript</span></div><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="card big"><div class="draw"><span class="tag">drawn showcase · config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin:<br>&nbsp;&nbsp;&nbsp;&nbsp;image: <u>lscr.io/linuxserver/jellyfin</u><br>&nbsp;&nbsp;&nbsp;&nbsp;volumes: [ /srv/media:/data ]<br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="txt"><div class="meta">02 · Own · personal project</div><h3>Config</h3><p>A repository to store, sync and manage docker-compose based deployment on servers.</p><div class="chips"><span class="chip">ansible</span><span class="chip">configuration management</span></div><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="card mid"><div class="shot" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="txt"><div class="meta">03 · School</div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card mid"><div class="shot" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="txt"><div class="meta">04 · School</div><h3>Student Dashboard</h3><p>A concept dashboard, built upon conducted user studies.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card mid"><div class="draw"><span class="tag">drawn showcase · rowing-stroke · hover</span><svg width="86%" height="110" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/><path d="M0 95 C45 95 55 35 95 35 S145 95 185 95 S235 40 265 40" fill="none" stroke="#8e877c" stroke-width="1.5" stroke-dasharray="4 4"/></svg></div><div class="txt"><div class="meta">05 · Own</div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card big" style="grid-column:span 12;display:grid;grid-template-columns:1fr 1fr"><div class="shot" style="background-image:url(/files/vr-classroom.jpg);height:auto;min-height:180px;border-bottom:0;border-right:1px solid var(--line)"></div><div class="txt"><div class="meta">06 · School</div><h3>VR-Classroom</h3><p>A prototype website where you can register yourself, and then create + sign up for classes.</p><div class="chips"><span class="chip">javascript</span><span class="chip">node.js</span></div><div class="ft"><span class="open">Read the full story →</span><span class="mk"><i></i>by hand</span></div></div></article>
<div class="mini sm"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="mini sm"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses</h4><div class="meta">Own · javascript</div></div><span class="mk"><i></i></span></div>
<div class="mini sm"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Bot</h4><div class="meta">Own · node.js</div></div><span class="mk"><i></i></span></div>
<div class="mini sm"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="meta">School · unity, VR</div></div><span class="mk"><i></i></span></div>
<div class="mini sm"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="meta">School · python</div></div><span class="mk"><i></i></span></div>
<div class="mini sm"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Borlaugh</h4><div class="meta">Own · html, css</div></div><span class="mk"><i></i></span></div>
<div class="mini sm"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
</div>
<div class="sh"><h2>Record</h2><span class="n">competitions and learning</span></div>
<div class="rec">
<div class="box"><h3>Competitions &amp; recognition</h3>
<div class="led">
<div class="y">2024</div><div>De Danske Cybermesterskaber</div><div class="res">regional participant</div>
<div class="y">2021</div><div>Google Hash Code</div><div class="res">top 12%</div>
<div class="y">2019</div><div>AUHackathon</div><div class="res win">winner · best AUHack</div>
<div class="y">—</div><div>First Lego League <span class="meta">· four years</span></div><div class="res win">won round 1, twice</div>
</div>
</div>
<div class="box"><h3>Keeping up · 24 courses and labs since Feb 2025</h3>
<div class="cl">
<div>Serverless on AWS</div><div class="c">8 · 3 labs</div>
<div>Ansible &amp; configuration</div><div class="c">5 · 3 labs</div>
<div>RAG &amp; LLM systems</div><div class="c">5 · 1 lab</div>
<div>Security <span class="meta">· JWT, ISO 27001, honeypots</span></div><div class="c">3 · 1 lab</div>
<div>Linux admin, Grafana, WordPress</div><div class="c">3</div>
</div>
<a class="more" href="#lp">All courses, searchable →</a>
</div>
</div>
<!-- ================= B ================= -->
<div class="opt-head"><span class="L">B</span><div><h1>Picked six, then a tight grid</h1><p>The six get an even 3×2 grid of real cards. Everything else becomes a dense four-across grid of small cards, the same size as today's list rows but tiled. Accomplishments join the "CV in ten seconds" strip. Learning gets its own card next to Writing.</p></div></div>
<div class="note">The calmest option and closest to today's structure. Accomplishments read as CV facts, which suits four entries. The learning card shows the latest few courses, so it looks alive as you keep going.</div>
<div class="cvs">
<div><h3>LATEST WRITING</h3><div style="font-size:14px">A synthetic work post <span class="meta">03/14</span></div></div>
<div><h3>CV IN TEN SECONDS</h3>
<div class="kv"><span class="k">now</span><span>IT-medarbejder, IT Research Tech, Aarhus University (2025–now)</span>
<span class="k">degree</span><span>Bachelor in Computer Science</span>
<span class="k">won</span><span><span class="acc">AUHackathon 2019</span>, best AUHack · First Lego League, round 1 twice</span>
<span class="k">placed</span><span>Google Hash Code 2021, top 12% · DDC 2024, regional</span></div>
</div>
</div>
<div class="sh"><h2>Picked</h2><span class="n">6 projects</span><span class="r">hover the drawings</span></div>
<div class="gB">
<article class="card"><div class="shot" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="txt"><div class="meta">Own</div><h3>Event Tracker for Gacha Games</h3><p>Which live service game events to prioritize.</p><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="card"><div class="draw"><span class="tag">config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin: <u>✓</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ up to date</u></div></div><div class="txt"><div class="meta">Own</div><h3>Config</h3><p>Store, sync and manage docker-compose deployments.</p><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="card"><div class="shot" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="txt"><div class="meta">School</div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card"><div class="shot" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="txt"><div class="meta">School</div><h3>Student Dashboard</h3><p>A concept dashboard built on user studies.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card"><div class="draw"><span class="tag">rowing-stroke · hover</span><svg width="86%" height="100" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/></svg></div><div class="txt"><div class="meta">Own</div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card"><div class="shot" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="txt"><div class="meta">School</div><h3>VR-Classroom</h3><p>Register, then create and sign up for classes.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
</div>
<div class="sh" style="margin-top:28px"><h2 style="font-size:17px">Everything else</h2><span class="n">7</span><span class="r">All · Own · School · search</span></div>
<div class="gBs">
<div class="mini"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses</h4><div class="meta">Own · javascript</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Bot</h4><div class="meta">Own · node.js</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="meta">School · unity, VR</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="meta">School · python</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Borlaugh</h4><div class="meta">Own · html, css</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
</div>
<div class="lower">
<div class="box"><h3>Writing</h3><div style="font-size:14px;color:var(--mute)">(unchanged)</div></div>
<div class="box"><h3>Learning · 24 since Feb 2025</h3>
<div class="log">
<div><span class="d">Oct 2025</span><span>Active Defense: Honeypots</span><span class="k">lab</span></div>
<div><span class="d">Sep 2025</span><span>Grafana Concepts and Basic Configuration</span><span></span></div>
<div><span class="d">Aug 2025</span><span>Vector Space Models and Embeddings in RAGs</span><span></span></div>
<div><span class="d">Aug 2025</span><span>Learning the Essentials of CentOS 7 Administration</span><span class="meta">6h 43m</span></div>
</div>
<div class="topics"><span class="chip">serverless 8</span><span class="chip">ansible 5</span><span class="chip">rag 5</span><span class="chip">security 3</span><span class="chip">linux 1</span></div>
<a class="more" href="#lp">All 24, searchable →</a>
</div>
</div>
<!-- ================= C ================= -->
<div class="opt-head"><span class="L">C</span><div><h1>One hero, uneven grid</h1><p>An editorial grid that varies on purpose. The top pick is large with its drawing. The other five come in two shapes around it. The seven small projects fill the bottom as compact tiles. Below, a "Track record" section with the four accomplishments side by side and learning shown as topic bars.</p></div></div>
<div class="note">The most character, and the "varied ways of showing information" principle at work, since the bars are a small graph. Downside: it needs a clear #1, and you'd choose the order of the six (I've put Config first because it has a live drawing).</div>
<div class="sh"><h2>Projects</h2><span class="n">13</span><span class="r">All · Own · School · search</span></div>
<div class="gC">
<article class="card hero"><div class="draw"><span class="tag">drawn showcase · config-editor · hover</span><div class="code" style="font-size:13px"><b>services:</b><br>&nbsp;&nbsp;jellyfin:<br>&nbsp;&nbsp;&nbsp;&nbsp;image: <u>lscr.io/linuxserver/jellyfin</u><br>&nbsp;&nbsp;&nbsp;&nbsp;volumes: [ /srv/media:/data ]<br>&nbsp;&nbsp;immich:<br>&nbsp;&nbsp;&nbsp;&nbsp;image: <u>ghcr.io/immich-app/server</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="txt"><div class="meta">01 · Own · personal project</div><h3>Config</h3><p>A repository to store, sync and manage docker-compose based deployment on servers.</p><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="card tall"><div class="shot" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="txt"><h3>Gacha Event Tracker</h3><div class="ft" style="margin-top:6px"><span class="meta">Own</span><span class="mk ai"><i></i>AI</span></div></div></article>
<article class="card tall"><div class="draw"><span class="tag">rowing-stroke</span><svg width="80%" height="70" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/></svg></div><div class="txt"><h3>Mixed-Reality Rowing</h3><div class="ft" style="margin-top:6px"><span class="meta">Own</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="card wide"><div class="shot" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="txt"><h3>Bachelor Report</h3></div></article>
<article class="card wide"><div class="shot" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="txt"><h3>Student Dashboard</h3></div></article>
<article class="card wide"><div class="shot" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="txt"><h3>VR-Classroom</h3></div></article>
<div class="mini"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses</h4><div class="meta">Own · javascript</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Bot</h4><div class="meta">Own · node.js</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="meta">School · unity, VR</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="meta">School · python</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Borlaugh</h4><div class="meta">Own · html, css</div></div><span class="mk"><i></i></span></div>
<div class="mini"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
</div>
<div class="track">
<div class="lab">Competitions<span>Things I entered, and how it went.</span></div>
<div class="row"><div class="medals">
<div class="medal"><div class="y">2019</div><div class="t">AUHackathon</div><div class="r win">winner · best AUHack</div></div>
<div class="medal"><div class="y">four years</div><div class="t">First Lego League</div><div class="r win">won round 1, twice</div></div>
<div class="medal"><div class="y">2021</div><div class="t">Google Hash Code</div><div class="r">top 12%</div></div>
<div class="medal"><div class="y">2024</div><div class="t">De Danske Cybermesterskaber</div><div class="r">regional participant</div></div>
</div></div>
<div class="lab">Keeping up<span>24 courses and hands-on labs since February 2025. Course time only, not the digging after.</span></div>
<div class="row"><div class="bars">
<span>Ansible</span><div class="bar"><i style="width:100%"></i></div><span class="c">5 · ~10h</span>
<span>Linux admin</span><div class="bar"><i style="width:67%"></i></div><span class="c">1 · 6.7h</span>
<span>Security</span><div class="bar"><i style="width:50%"></i></div><span class="c">3 · ~5h</span>
<span>Serverless on AWS</span><div class="bar"><i style="width:40%"></i></div><span class="c">8 · ~4h</span>
<span>RAG &amp; LLMs</span><div class="bar"><i style="width:18%"></i></div><span class="c">5 · ~2h</span>
</div><a class="more" href="#lp">All courses, searchable →</a></div>
</div>
<!-- ================= Learning page (shared) ================= -->
<div class="opt-head" id="lp"><span class="L" style="background:var(--mute)">+</span><div><h1>/work/learning/: the searchable list (any option)</h1><p>Its own quiet page, linked from whichever section you pick. Search plus topic filter, newest first. It's built from a content file you add a line to after each course.</p></div></div>
<div class="lp">
<div class="top"><div class="search">Search course, provider, keyword…</div><div class="seg"><span class="on">All 24</span><span>Serverless</span><span>Ansible</span><span>RAG</span><span>Security</span><span>Linux</span><span>Other</span></div></div>
<table>
<tr><th>Completed</th><th>Course</th><th>Topic</th><th>Provider</th><th>Type</th><th>Time</th></tr>
<tr><td class="m">2025-10-08</td><td>Active Defense: Honeypots</td><td class="m">security</td><td class="m">Pluralsight</td><td class="m">lab</td><td class="m">1h 30m</td></tr>
<tr><td class="m">2025-09-07</td><td>Grafana Concepts and Basic Configuration</td><td class="m">observability</td><td class="m">Pluralsight</td><td class="m">video</td><td class="m">25m</td></tr>
<tr><td class="m">2025-08-16</td><td>Security Compliance: ISO 27001</td><td class="m">security</td><td class="m">Pluralsight</td><td class="m">video</td><td class="m">56m</td></tr>
<tr><td class="m">2025-08-08</td><td>Learning the Essentials of CentOS Enterprise Linux 7 Administration</td><td class="m">linux</td><td class="m">Pluralsight</td><td class="m">video · quiz ✓</td><td class="m">6h 43m</td></tr>
<tr><td class="m">2025-05-29</td><td>JWT Fundamentals</td><td class="m">security</td><td class="m">Pluralsight</td><td class="m">video</td><td class="m">2h 29m</td></tr>
<tr><td class="m" colspan="6" style="color:var(--mute)">… 19 more</td></tr>
</table>
</div>
<div class="pick">
<button data-choice="a" onclick="pick(this)">A · one grid, three sizes</button>
<button data-choice="b" onclick="pick(this)">B · picked six + tight grid</button>
<button data-choice="c" onclick="pick(this)">C · hero + uneven grid</button>
</div>
</div>
<script>function pick(b){document.querySelectorAll('.pick button').forEach(x=>x.classList.remove('selected'));b.classList.add('selected');if(window.brainstorm&&brainstorm.send)brainstorm.send({type:'click',choice:b.dataset.choice,text:b.textContent});else if(window.toggleSelect)toggleSelect(b);}</script>
</body>
</html>
+210
View File
@@ -0,0 +1,210 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Work page: round 2</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{--bg:#131210;--panel:#1b1916;--panel2:#221f1b;--line:#2b2824;--ink:#ede7dd;--mute:#8e877c;--acc:#ea7444;--ok:#a8b48f;
--sans:'Geist',system-ui,sans-serif;--mono:'Geist Mono',ui-monospace,monospace;--e:cubic-bezier(.2,.8,.2,1)}
*{box-sizing:border-box}html,body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 var(--sans)}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.opt-head{border-top:1px dashed #3a352f;margin-top:80px;padding:28px 0 8px;display:flex;gap:18px;align-items:baseline}
.opt-head.first{margin-top:24px;border-top:0}
.opt-head .L{font:600 13px var(--mono);color:var(--bg);background:var(--acc);border-radius:4px;padding:2px 8px}
.opt-head .L.g{background:var(--mute)}
.opt-head h1{font-size:22px;margin:0;font-weight:600}.opt-head p{margin:4px 0 0;color:var(--mute);max-width:720px}
.note{font:12px/1.55 var(--mono);color:var(--mute);border-left:2px solid var(--acc);padding:2px 0 2px 12px;margin:12px 0 22px;max-width:860px}
.sh{display:flex;align-items:baseline;gap:12px;margin:34px 0 16px}
.sh h2{font-size:22px;margin:0;font-weight:600}.sh .n{font:12px var(--mono);color:var(--mute)}
.sh .r{margin-left:auto;display:flex;gap:10px;align-items:center;font:12px var(--mono);color:var(--mute)}
.seg{display:flex;gap:2px}.seg span{font:12.5px var(--sans);color:var(--mute);padding:4px 9px;border-radius:5px}.seg span.on{background:var(--panel2);color:var(--ink);border:1px solid var(--line)}
.search{background:var(--bg);border:1px solid var(--line);border-radius:6px;padding:6px 10px;font:13px var(--sans);color:var(--mute);min-width:240px}
.search b{color:var(--ink);font-weight:400}
.meta{font:11px var(--mono);color:var(--mute);letter-spacing:.02em}
.ph{border-bottom:1px dotted var(--mute);cursor:help}
.mk{display:inline-flex;align-items:center;gap:6px;font:11px var(--mono);border:1px solid var(--line);border-radius:99px;padding:2px 8px;white-space:nowrap}
.mk i{width:8px;height:8px;border-radius:50%;border:1.5px solid currentColor;display:inline-block}
.mk.ai{color:var(--acc);border-color:#6b3a26}.mk.ai i{background:var(--acc);border-color:var(--acc)}
.mk.un i{border-style:dashed}
.chip{font:11px var(--mono);color:var(--mute);border:1px solid var(--line);border-radius:4px;padding:1px 6px}
/* tiles */
.t{background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;min-height:0;transition:border-color .2s var(--e)}
.t:hover{border-color:#4a433b}
.t .vis{flex:1;min-height:0;background:#0e0d0c center top/cover no-repeat;border-bottom:1px solid var(--line);position:relative}
.t .tx{padding:12px 16px 14px}
.t h3{margin:3px 0 2px;font-size:17px;font-weight:600;line-height:1.25}
.t p{margin:4px 0 0;color:#c9c2b6;font-size:13.5px;line-height:1.45}
.t .ft{display:flex;justify-content:space-between;align-items:center;margin-top:10px}
.t .open{font:12px var(--mono);color:var(--acc)}
.t.L h3{font-size:22px}
.tag{position:absolute;top:10px;left:12px;font:10px var(--mono);color:var(--mute)}
.draw{background:var(--panel2)!important;display:flex;align-items:center;justify-content:center}
.code{font:12px/1.7 var(--mono);color:#b9b2a6;padding:30px 24px;width:100%}.code b{color:var(--acc);font-weight:400}.code u{color:var(--ok);text-decoration:none}
/* small tile: same footprint as today's list row */
.s{flex-direction:row;align-items:center;gap:12px;padding:0 12px}
.s .th{width:60px;height:40px;border-radius:4px;background:#0e0d0c center/cover;flex:none;border:1px solid var(--line)}
.s h4{margin:0;font-size:14px;font-weight:500;line-height:1.3}
.s .mk{margin-left:auto;padding:1px 6px}
/* other-work tiles */
.ow .vis{background:repeating-linear-gradient(135deg,#1d1b18 0 10px,#1a1815 10px 20px)!important;display:flex;align-items:center;justify-content:center}
.site{font:500 15px var(--mono);color:var(--ink);border:1px solid var(--line);background:var(--bg);border-radius:6px;padding:8px 14px}
.site small{display:block;font:10px var(--mono);color:var(--mute);margin-top:2px}
.badge{font:10px var(--mono);color:var(--ok);border:1px solid #3d4433;border-radius:4px;padding:0 5px}
.badge.gone{color:var(--mute);border-color:var(--line)}
/* ---------- D : woven pattern ---------- */
.gD{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px}
/* ---------- E : dense auto-pack ---------- */
.gE{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px;grid-auto-flow:row dense}
.gE .L{grid-column:span 7;grid-row:span 6}
.gE .M{grid-column:span 5;grid-row:span 5}
.gE .T{grid-column:span 4;grid-row:span 6}
.gE .W{grid-column:span 5;grid-row:span 4}
.gE .ow{grid-column:span 3;grid-row:span 3}
.gE .s{grid-column:span 3;grid-row:span 1}
/* ---------- record ---------- */
.rec{display:grid;grid-template-columns:1fr 1.25fr;gap:14px}
.box{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.box h3{margin:0 0 4px;font:500 11px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
.box .sum{font-size:14px;color:#c9c2b6;margin:0 0 12px}
.box .sum b{color:var(--ink);font-weight:500}
.led{display:grid;grid-template-columns:44px 1fr auto;gap:0 14px;font-size:14px}
.led>div{padding:8px 0;border-top:1px solid var(--line)}
.led .y{font:12px var(--mono);color:var(--mute)}.led .res{font:12px var(--mono);color:var(--mute);text-align:right}
.led .hi{color:var(--acc)}
.ku{display:grid;grid-template-columns:1fr auto auto auto;gap:0 18px;font-size:14px;align-items:center}
.ku>div{padding:9px 0;border-top:1px solid var(--line)}
.ku .h{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;border-top:0;padding-top:0}
.ku .c{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.cert{display:inline-flex;align-items:center;gap:5px;font:12px var(--mono);color:var(--ink);white-space:nowrap}
.cert svg{flex:none}
.ku .c.cer{color:var(--ink)}
.more{display:inline-block;margin-top:14px;font:12px var(--mono);color:var(--acc)}
/* search results */
.res-wrap{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.rgrid{display:grid;grid-template-columns:1.1fr 1fr;gap:18px}
.rh{font:500 10.5px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;margin:0 0 8px}
.rl>div{display:grid;grid-template-columns:1fr auto;gap:10px;padding:8px 0;border-top:1px solid var(--line);font-size:14px}
.rl .m{font:11.5px var(--mono);color:var(--mute);white-space:nowrap}
mark{background:none;color:var(--acc)}
/* other work in history */
.hist{display:grid;grid-template-columns:90px 1fr auto;gap:0 16px;font-size:14px}
.hist>div{padding:10px 0;border-top:1px solid var(--line)}.hist .k{font:11px var(--mono);color:var(--mute);padding-top:12px}
.pick{display:flex;gap:10px;margin:26px 0 70px}
.pick button{font:13px var(--mono);background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:8px 14px;cursor:pointer}
.pick button.selected,.pick button:hover{border-color:var(--acc);color:var(--acc)}
</style>
</head>
<body>
<div class="wrap">
<svg width="0" height="0" style="position:absolute"><defs><symbol id="seal" viewBox="0 0 16 16"><circle cx="8" cy="6.5" r="4.6" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M5.2 10.2 4.4 15l3.6-1.8 3.6 1.8-.8-4.8" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/></symbol></defs></svg>
<p class="meta" style="margin-top:28px">Round 2 · uneven grids with the small projects woven in · other work as its own kind of tile · certificates up front · search that also finds certificates. Dotted underline = a fact I don't have yet.</p>
<!-- ================= D ================= -->
<div class="opt-head first"><span class="L">D</span><div><h1>Woven grid</h1><p>Each big tile has a column of small tiles beside or under it, so the small projects fill gaps between the big ones instead of collecting at the bottom. Sizes vary on purpose: one large, some tall, some wide.</p></div></div>
<div class="note">How it scales: the page repeats a fixed rhythm of slots (large + 2 small, tall + medium + small stack, …). New picked projects take the next big slot; everything else fills small slots in date order. You control which ones are big, not where they land.</div>
<div class="sh"><h2>Projects</h2><span class="n">15 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span><span>For others</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="gD">
<article class="t L" style="grid-column:1/8;grid-row:1/7"><div class="vis draw"><span class="tag">drawn showcase · config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin:<br>&nbsp;&nbsp;&nbsp;&nbsp;image: <u>lscr.io/linuxserver/jellyfin</u><br>&nbsp;&nbsp;&nbsp;&nbsp;volumes: [ /srv/media:/data ]<br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="tx"><div class="meta">Own · personal project</div><h3>Config</h3><p>A repository to store, sync and manage docker-compose based deployment on servers.</p><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t M" style="grid-column:8/13;grid-row:1/5"><div class="vis" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="meta">Own</div><h3>Event Tracker for Gacha Games</h3><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<div class="t s" style="grid-column:8/13;grid-row:5/6"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="t s" style="grid-column:8/13;grid-row:6/7"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses Tracker</h4><div class="meta">Own · javascript</div></div><span class="mk"><i></i></span></div>
<article class="t T" style="grid-column:1/5;grid-row:7/13"><div class="vis draw"><span class="tag">rowing-stroke · hover</span><svg width="84%" height="120" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/><path d="M0 95 C45 95 55 35 95 35 S145 95 185 95 S235 40 265 40" fill="none" stroke="#8e877c" stroke-width="1.5" stroke-dasharray="4 4"/></svg></div><div class="tx"><div class="meta">Own</div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t M" style="grid-column:5/9;grid-row:7/11"><div class="vis" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="meta">School · thesis</div><h3>Bachelor Report</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t ow" style="grid-column:9/13;grid-row:7/10"><div class="vis"><div class="site">art-bubble.dk<small>IT &amp; website</small></div></div><div class="tx" style="padding-top:10px"><div class="meta">For others · <span class="ph" title="placeholder">years?</span></div><h3>Art Bubble</h3><div class="ft" style="margin-top:4px"><span class="badge">ongoing</span><span class="mk un"><i></i>not recorded</span></div></div></article>
<div class="t s ow" style="grid-column:9/13;grid-row:10/11"><div class="th" style="background:repeating-linear-gradient(135deg,#1d1b18 0 6px,#1a1815 6px 12px)"></div><div><h4>Lystrup Genbrugser</h4><div class="meta">For others · site retired</div></div><span class="mk un"><i></i></span></div>
<div class="t s" style="grid-column:5/9;grid-row:11/12"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Discord Bot</h4><div class="meta">Own · node.js</div></div><span class="mk"><i></i></span></div>
<div class="t s" style="grid-column:9/13;grid-row:11/12"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="meta">School · unity, VR</div></div><span class="mk"><i></i></span></div>
<div class="t s" style="grid-column:5/9;grid-row:12/13"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="meta">School · python</div></div><span class="mk"><i></i></span></div>
<div class="t s" style="grid-column:9/13;grid-row:12/13"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Norman Borlaugh</h4><div class="meta">Own · html, css</div></div><span class="mk"><i></i></span></div>
<article class="t W" style="grid-column:1/7;grid-row:13/18"><div class="vis" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="meta">School</div><h3>Student Dashboard</h3><p>A concept student dashboard web-app, built upon conducted user studies.</p></div></article>
<article class="t W" style="grid-column:7/13;grid-row:13/17"><div class="vis" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="meta">School</div><h3>VR-Classroom</h3></div></article>
<div class="t s" style="grid-column:7/13;grid-row:17/18"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
</div>
<!-- ================= E ================= -->
<div class="opt-head"><span class="L">E</span><div><h1>Packed by size</h1><p>Every project has a size (large, tall, wide, medium, small) and the grid packs them tightly in your order, letting small tiles slip into whatever gaps the big ones leave. Less hand-tuned than D, more organic, and it never needs re-laying out when you add things.</p></div></div>
<div class="note">Trade-off: D's rhythm is predictable and tidy; E is more uneven and "found", but exactly where a small tile lands depends on what's around it. Same tiles, same order, as D.</div>
<div class="sh"><h2>Projects</h2><span class="n">15 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span><span>For others</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="gE">
<article class="t L"><div class="vis draw"><span class="tag">config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin: <u>✓</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="tx"><div class="meta">Own</div><h3>Config</h3><p>Store, sync and manage docker-compose based deployment on servers.</p><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t M"><div class="vis" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="meta">Own</div><h3>Event Tracker for Gacha Games</h3><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t W"><div class="vis" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="meta">School · thesis</div><h3>Bachelor Report</h3></div></article>
<article class="t T"><div class="vis draw"><span class="tag">rowing-stroke</span><svg width="80%" height="100" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/></svg></div><div class="tx"><div class="meta">Own</div><h3>Mixed-Reality Rowing Game</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t M"><div class="vis" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="meta">School</div><h3>Student Dashboard</h3></div></article>
<article class="t ow"><div class="vis"><div class="site">art-bubble.dk<small>IT &amp; website</small></div></div><div class="tx" style="padding-top:10px"><div class="meta">For others</div><h3>Art Bubble</h3></div></article>
<article class="t W"><div class="vis" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="meta">School</div><h3>VR-Classroom</h3></div></article>
<div class="t s ow"><div class="th" style="background:repeating-linear-gradient(135deg,#1d1b18 0 6px,#1a1815 6px 12px)"></div><div><h4>Lystrup Genbrugser</h4><div class="meta">For others · site retired</div></div><span class="mk un"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses Tracker</h4><div class="meta">Own · javascript</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Discord Bot</h4><div class="meta">Own · node.js</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="meta">School · unity, VR</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="meta">School · python</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Norman Borlaugh</h4><div class="meta">Own · html, css</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
</div>
<!-- ================= Record ================= -->
<div class="opt-head"><span class="L g">+</span><div><h1>Record: competitions and keeping up (either grid)</h1><p>Certificates are now the headline number and get their own column, marked with a small seal. Orange = what you flag as most impressive; the list just grows downward.</p></div></div>
<div class="rec">
<div class="box"><h3>Competitions &amp; recognition</h3><p class="sum">4 entries · <span style="color:var(--acc)">orange</span> = flagged as a highlight</p>
<div class="led">
<div class="y">2024</div><div>De Danske Cybermesterskaber</div><div class="res">regional participant</div>
<div class="y">2021</div><div>Google Hash Code</div><div class="res hi">top 12%</div>
<div class="y">2019</div><div class="hi">AUHackathon</div><div class="res hi">winner · best AUHack</div>
<div class="y"><span class="ph" title="placeholder">yrs?</span></div><div>First Lego League <span class="meta">· four years</span></div><div class="res hi">won round 1, two years running</div>
</div>
</div>
<div class="box"><h3>Keeping up</h3><p class="sum"><span class="cert" style="font:500 14px var(--sans)"><svg width="15" height="15" style="color:var(--acc)"><use href="#seal"/></svg><b>18 certificates</b></span> from 23 courses and hands-on labs · <b>~27 hours</b> of course time since Feb 2025</p>
<div class="ku">
<div class="h">topic</div><div class="h" style="text-align:right">done</div><div class="h" style="text-align:right">certificates</div><div class="h" style="text-align:right">time</div>
<div>Ansible &amp; configuration</div><div class="c">2 courses · 3 labs</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>5</span></div><div class="c">9.4h</div>
<div>Linux administration</div><div class="c">1 course</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>1</span></div><div class="c">6.7h</div>
<div>Security <span class="meta">· JWT, ISO 27001, honeypots</span></div><div class="c">2 courses · 1 lab</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>2</span></div><div class="c">4.9h</div>
<div>Serverless on AWS</div><div class="c">5 courses · 3 labs</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>5</span></div><div class="c">3.9h</div>
<div>RAG &amp; LLM systems</div><div class="c">4 courses · 1 lab</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>4</span></div><div class="c">1.8h</div>
<div>Observability <span class="meta">· Grafana</span></div><div class="c">1 course</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>1</span></div><div class="c">0.4h</div>
</div>
<a class="more">All courses and certificates, searchable →</a>
</div>
</div>
<!-- ================= Search ================= -->
<div class="opt-head"><span class="L g">+</span><div><h1>Searching the work page finds certificates too</h1><p>The same search box over the grid. Projects that match stay in the grid (others dim); matching certificates appear in a strip right under the search, linking to /work/learning/.</p></div></div>
<div class="sh" style="margin-top:10px"><h2>Projects</h2><span class="n">1 project · 5 certificates match</span><span class="r"><span class="search"><b>ansible</b></span></span></div>
<div class="res-wrap">
<div class="rgrid">
<div><p class="rh">Projects</p><div class="rl"><div><span><b>Config</b> · stores, syncs and manages docker-compose deployments <span class="chip"><mark>ansible</mark></span></span><span class="mk ai"><i></i>AI</span></div></div></div>
<div><p class="rh">Certificates &amp; labs</p><div class="rl">
<div><span><span class="cert"><svg width="13" height="13" style="color:var(--acc)"><use href="#seal"/></svg></span> <mark>Ansible</mark> Fundamentals</span><span class="m">Pluralsight · Apr 2025 · 3.7h</span></div>
<div><span><span class="cert"><svg width="13" height="13" style="color:var(--acc)"><use href="#seal"/></svg></span> Troubleshoot <mark>Ansible</mark> Connectivity <span class="meta">lab</span></span><span class="m">Mar 2025 · 1.2h</span></div>
<div><span><span class="cert"><svg width="13" height="13" style="color:var(--acc)"><use href="#seal"/></svg></span> Build a Production Ready <mark>Ansible</mark> Playbook <span class="meta">lab</span></span><span class="m">Mar 2025 · 1h</span></div>
<div><span class="meta">+ 2 more →</span><span></span></div>
</div></div>
</div>
</div>
<!-- ================= Other work in history ================= -->
<div class="opt-head"><span class="L g">+</span><div><h1>Other work also in "Where I've worked"</h1><p>Besides the tile, the work history gets an "on the side" line, so the CV reads complete. Retired sites keep their line, just not the link (or link an archived copy).</p></div></div>
<div class="box" style="max-width:640px"><h3>Where I've worked</h3>
<div class="hist">
<div class="k">now</div><div>IT-medarbejder, IT Research Tech, Aarhus University (2025–now)</div><div></div>
<div class="k">on the side</div><div>IT and website, <u style="text-decoration-color:var(--acc)">Art Bubble</u> (<span class="ph" title="placeholder">years?</span>)</div><div class="badge" style="align-self:center">ongoing</div>
<div class="k"></div><div>IT and website, Lystrup Genbrugser (<span class="ph" title="placeholder">years?</span>)</div><div class="badge gone" style="align-self:center">site retired</div>
<div class="k">before</div><div>Intern, ScienceAtHome (2019)</div><div></div>
</div>
</div>
<div class="pick">
<button data-choice="d" onclick="pick(this)">D · woven grid</button>
<button data-choice="e" onclick="pick(this)">E · packed by size</button>
</div>
</div>
<script>function pick(b){document.querySelectorAll('.pick button').forEach(x=>x.classList.remove('selected'));b.classList.add('selected');if(window.brainstorm&&brainstorm.send)brainstorm.send({type:'click',choice:b.dataset.choice,text:b.textContent});}</script>
</body>
</html>
+256
View File
@@ -0,0 +1,256 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Work page: round 3</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{--bg:#131210;--panel:#1b1916;--panel2:#221f1b;--line:#2b2824;--ink:#ede7dd;--mute:#8e877c;--acc:#ea7444;--ok:#a8b48f;
--sans:'Geist',system-ui,sans-serif;--mono:'Geist Mono',ui-monospace,monospace;--e:cubic-bezier(.2,.8,.2,1)}
*{box-sizing:border-box}html,body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 var(--sans)}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.opt-head{border-top:1px dashed #3a352f;margin-top:80px;padding:28px 0 8px;display:flex;gap:18px;align-items:baseline}
.opt-head.first{margin-top:24px;border-top:0}
.opt-head .L{font:600 13px var(--mono);color:var(--bg);background:var(--acc);border-radius:4px;padding:2px 8px}
.opt-head .L.g{background:var(--mute)}
.opt-head h1{font-size:22px;margin:0;font-weight:600}.opt-head p{margin:4px 0 0;color:var(--mute);max-width:720px}
.note{font:12px/1.55 var(--mono);color:var(--mute);border-left:2px solid var(--acc);padding:2px 0 2px 12px;margin:12px 0 22px;max-width:860px}
.sh{display:flex;align-items:baseline;gap:12px;margin:34px 0 16px}
.sh h2{font-size:22px;margin:0;font-weight:600}.sh .n{font:12px var(--mono);color:var(--mute)}
.sh .r{margin-left:auto;display:flex;gap:10px;align-items:center;font:12px var(--mono);color:var(--mute)}
.seg{display:flex;gap:2px}.seg span{font:12.5px var(--sans);color:var(--mute);padding:4px 9px;border-radius:5px}.seg span.on{background:var(--panel2);color:var(--ink);border:1px solid var(--line)}
.search{background:var(--bg);border:1px solid var(--line);border-radius:6px;padding:6px 10px;font:13px var(--sans);color:var(--mute);min-width:240px}
.search b{color:var(--ink);font-weight:400}
.meta{font:11px var(--mono);color:var(--mute);letter-spacing:.02em}
.ph{border-bottom:1px dotted var(--mute);cursor:help}
.mk{display:inline-flex;align-items:center;gap:6px;font:11px var(--mono);border:1px solid var(--line);border-radius:99px;padding:2px 8px;white-space:nowrap}
.mk i{width:8px;height:8px;border-radius:50%;border:1.5px solid currentColor;display:inline-block}
.mk.ai{color:var(--acc);border-color:#6b3a26}.mk.ai i{background:var(--acc);border-color:var(--acc)}
.mk.un i{border-style:dashed}
.chip{font:11px var(--mono);color:var(--mute);border:1px solid var(--line);border-radius:4px;padding:1px 6px}
/* tiles */
.t{background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;min-height:0;transition:border-color .2s var(--e)}
.t:hover{border-color:#4a433b}
.t .vis{flex:1;min-height:0;background:#0e0d0c center top/cover no-repeat;border-bottom:1px solid var(--line);position:relative}
.t .tx{padding:12px 16px 14px}
.t h3{margin:3px 0 2px;font-size:17px;font-weight:600;line-height:1.25}
.t p{margin:4px 0 0;color:#c9c2b6;font-size:13.5px;line-height:1.45}
.t .ft{display:flex;justify-content:space-between;align-items:center;margin-top:10px}
.t .open{font:12px var(--mono);color:var(--acc)}
.t.L h3{font-size:22px}
.tag{position:absolute;top:10px;left:12px;font:10px var(--mono);color:var(--mute)}
.draw{background:var(--panel2)!important;display:flex;align-items:center;justify-content:center}
.code{font:12px/1.7 var(--mono);color:#b9b2a6;padding:30px 24px;width:100%}.code b{color:var(--acc);font-weight:400}.code u{color:var(--ok);text-decoration:none}
/* small tile: same footprint as today's list row */
.s{flex-direction:row;align-items:center;gap:12px;padding:0 12px}
.s .th{width:60px;height:40px;border-radius:4px;background:#0e0d0c center/cover;flex:none;border:1px solid var(--line)}
.s h4{margin:0;font-size:14px;font-weight:500;line-height:1.3}
.s .mk{margin-left:auto;padding:1px 6px}
/* other-work tiles */
.ow .vis{background:repeating-linear-gradient(135deg,#1d1b18 0 10px,#1a1815 10px 20px)!important;display:flex;align-items:center;justify-content:center}
.site{font:500 15px var(--mono);color:var(--ink);border:1px solid var(--line);background:var(--bg);border-radius:6px;padding:8px 14px}
.site small{display:block;font:10px var(--mono);color:var(--mute);margin-top:2px}
.badge{font:10px var(--mono);color:var(--ok);border:1px solid #3d4433;border-radius:4px;padding:0 5px}
.badge.gone{color:var(--mute);border-color:var(--line)}
/* ---------- D : woven pattern ---------- */
.gD{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px}
/* ---------- E : dense auto-pack ---------- */
.gE{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px;grid-auto-flow:row dense}
.gE .L{grid-column:span 7;grid-row:span 6}
.gE .M{grid-column:span 5;grid-row:span 5}
.gE .T{grid-column:span 4;grid-row:span 6}
.gE .W{grid-column:span 5;grid-row:span 4}
.gE .ow{grid-column:span 3;grid-row:span 3}
.gE .s{grid-column:span 3;grid-row:span 1}
/* ---------- record ---------- */
.rec{display:grid;grid-template-columns:1fr 1.25fr;gap:14px}
.box{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.box h3{margin:0 0 4px;font:500 11px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
.box .sum{font-size:14px;color:#c9c2b6;margin:0 0 12px}
.box .sum b{color:var(--ink);font-weight:500}
.led{display:grid;grid-template-columns:44px 1fr auto;gap:0 14px;font-size:14px}
.led>div{padding:8px 0;border-top:1px solid var(--line)}
.led .y{font:12px var(--mono);color:var(--mute)}.led .res{font:12px var(--mono);color:var(--mute);text-align:right}
.led .hi{color:var(--acc)}
.ku{display:grid;grid-template-columns:1fr auto auto auto;gap:0 18px;font-size:14px;align-items:center}
.ku>div{padding:9px 0;border-top:1px solid var(--line)}
.ku .h{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;border-top:0;padding-top:0}
.ku .c{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.cert{display:inline-flex;align-items:center;gap:5px;font:12px var(--mono);color:var(--ink);white-space:nowrap}
.cert svg{flex:none}
.ku .c.cer{color:var(--ink)}
.more{display:inline-block;margin-top:14px;font:12px var(--mono);color:var(--acc)}
/* search results */
.res-wrap{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.rgrid{display:grid;grid-template-columns:1.1fr 1fr;gap:18px}
.rh{font:500 10.5px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;margin:0 0 8px}
.rl>div{display:grid;grid-template-columns:1fr auto;gap:10px;padding:8px 0;border-top:1px solid var(--line);font-size:14px}
.rl .m{font:11.5px var(--mono);color:var(--mute);white-space:nowrap}
mark{background:none;color:var(--acc)}
/* other work in history */
.hist{display:grid;grid-template-columns:90px 1fr auto;gap:0 16px;font-size:14px}
.hist>div{padding:10px 0;border-top:1px solid var(--line)}.hist .k{font:11px var(--mono);color:var(--mute);padding-top:12px}
.pick{display:flex;gap:10px;margin:26px 0 70px}
.pick button{font:13px var(--mono);background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:8px 14px;cursor:pointer}
.pick button.selected,.pick button:hover{border-color:var(--acc);color:var(--acc)}
/* F: alternating bands */
.band{display:grid;grid-template-columns:repeat(12,1fr);gap:12px;margin-bottom:12px}
.band .big{grid-column:span 8;height:340px}
.band .side{grid-column:span 4;display:grid;grid-template-rows:repeat(4,1fr);gap:12px;height:340px}
.band .half{grid-column:span 6;height:300px}
.band .side .s{height:auto}
.slot{border:1px dashed var(--line);border-radius:10px;display:flex;align-items:center;justify-content:center;font:11px var(--mono);color:#4d4740}
/* G: features + index column */
.gG{display:grid;grid-template-columns:1fr 340px;gap:28px;align-items:start}
.fl{display:flex;flex-direction:column;gap:12px}
.fr{display:grid;grid-template-columns:260px 1fr;min-height:190px}
.fr .vis{border-bottom:0;border-right:1px solid var(--line)}
.fr .tx{padding:16px 18px;display:flex;flex-direction:column}
.fr .ft{margin-top:auto}
.idx{position:sticky;top:16px;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px 16px}
.idx h3{margin:0 0 6px;font:500 11px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;display:flex;justify-content:space-between}
.idx .it{display:grid;grid-template-columns:44px 1fr auto;gap:10px;align-items:center;padding:8px 0;border-top:1px solid var(--line)}
.idx .th{width:44px;height:30px;border-radius:3px;background:#0e0d0c center/cover;border:1px solid var(--line)}
.idx h4{margin:0;font-size:13.5px;font-weight:500;line-height:1.25}
.idx .yr{font:11px var(--mono);color:var(--mute)}
.idx .grp{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;padding:12px 0 2px}
/* H: two sizes, even grid */
.gH{display:grid;grid-template-columns:repeat(4,1fr);grid-auto-rows:150px;gap:12px;grid-auto-flow:row dense}
.gH .P{grid-column:span 2;grid-row:span 2}
.gH .c{grid-column:span 1;grid-row:span 1}
.gH .c .vis{flex:1}.gH .c .tx{padding:8px 12px 10px}.gH .c h3{font-size:14px;font-weight:500;margin:0}
.gH .c .ft{margin-top:2px}
/* recognition v3 */
.rec3{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.vl{display:grid;grid-template-columns:1fr auto;gap:0 14px;font-size:14px}
.vl>div{padding:10px 0;border-top:1px solid var(--line)}
.vl .r{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.vl .sub{display:block;font:12px var(--mono);color:var(--mute);margin-top:2px}
.vl a{color:var(--ink);text-decoration:underline;text-decoration-color:var(--acc);text-underline-offset:3px}
.k3{display:grid;grid-template-columns:1fr;gap:0}
</style>
</head>
<body>
<div class="wrap">
<svg width="0" height="0" style="position:absolute"><defs><symbol id="seal" viewBox="0 0 16 16"><circle cx="8" cy="6.5" r="4.6" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M5.2 10.2 4.4 15l3.6-1.8 3.6 1.8-.8-4.8" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/></symbol></defs></svg>
<p class="meta" style="margin-top:28px">Round 3 · calmer structures than D/E · Art Bubble and Lystrup Genbrugser moved out of the projects into a "Recognition &amp; volunteering" box · Keeping up unchanged from round 2.</p>
<!-- ================= F ================= -->
<div class="opt-head first"><span class="L">F</span><div><h1>Alternating bands</h1><p>A strict, repeating rhythm instead of a mosaic: <b>one big + a stack of four small</b>, then <b>two big side by side</b>, then the first band mirrored. Only two band shapes, always aligned, so it reads as ordered while still mixing small projects in between the big ones.</p></div></div>
<div class="note">Scales: each new picked project fills the next big slot; small projects fill the side stacks in date order. When the stacks are full, extra small ones form a last band of four across. Empty stack slots (dashed here) simply collapse.</div>
<div class="sh"><h2>Projects</h2><span class="n">13 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="band">
<article class="t big"><div class="vis draw"><span class="tag">drawn showcase · config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin:<br>&nbsp;&nbsp;&nbsp;&nbsp;image: <u>lscr.io/linuxserver/jellyfin</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="tx"><div class="meta">Own · personal project</div><h3>Config</h3><p>A repository to store, sync and manage docker-compose based deployment on servers.</p><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<div class="side">
<div class="t s"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses Tracker</h4><div class="meta">Own · javascript</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Discord Bot</h4><div class="meta">Own · node.js</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="meta">School · unity, VR</div></div><span class="mk"><i></i></span></div>
</div>
</div>
<div class="band">
<article class="t half"><div class="vis" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="meta">Own</div><h3>Event Tracker for Gacha Games</h3><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t half"><div class="vis draw"><span class="tag">rowing-stroke · hover</span><svg width="80%" height="110" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/><path d="M0 95 C45 95 55 35 95 35 S145 95 185 95 S235 40 265 40" fill="none" stroke="#8e877c" stroke-width="1.5" stroke-dasharray="4 4"/></svg></div><div class="tx"><div class="meta">Own</div><h3>Mixed-Reality Rowing Game</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
</div>
<div class="band">
<div class="side">
<div class="t s"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="meta">School · python</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Norman Borlaugh</h4><div class="meta">Own · html, css</div></div><span class="mk"><i></i></span></div>
<div class="t s"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="meta">Own · react</div></div><span class="mk"><i></i></span></div>
<div class="slot">next small project</div>
</div>
<article class="t big"><div class="vis" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="meta">School · thesis</div><h3>Bachelor Report</h3><p>My bachelor thesis on using reputation systems in peer-to-peer archival.</p><div class="ft"><span class="open">Read the full story →</span><span class="mk"><i></i>by hand</span></div></div></article>
</div>
<div class="band">
<article class="t half"><div class="vis" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="meta">School</div><h3>Student Dashboard</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t half"><div class="vis" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="meta">School</div><h3>VR-Classroom</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
</div>
<!-- ================= G ================= -->
<div class="opt-head"><span class="L">G</span><div><h1>Picked down the left, index on the right</h1><p>The six picked projects as roomy horizontal cards in one column. Beside them, from the very top, a compact index of everything else that stays in view while you scroll. The small projects are always on screen, never "the rest at the bottom".</p></div></div>
<div class="note">The calmest and most editorial. Scales the easiest: the index just gets longer (and could fold by group). On phones the index drops under the six.</div>
<div class="sh"><h2>Projects</h2><span class="n">13 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="gG">
<div class="fl">
<article class="t fr"><div class="vis draw"><span class="tag">config-editor · hover</span><div class="code" style="padding:30px 16px;font-size:11px"><b>services:</b><br>&nbsp;&nbsp;jellyfin: <u>✓</u><br><b>hosts:</b> [ lucwin-01 ]<br><b>sync:</b> <u>✓ up to date</u></div></div><div class="tx"><div class="meta">01 · Own · personal project</div><h3>Config</h3><p>A repository to store, sync and manage docker-compose based deployment on servers.</p><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t fr"><div class="vis" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="meta">02 · Own</div><h3>Event Tracker for Gacha Games</h3><p>Used to easily figure out which live service games events to prioritize.</p><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t fr"><div class="vis" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="meta">03 · School · thesis</div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t fr"><div class="vis draw"><span class="tag">rowing-stroke</span><svg width="80%" height="80" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/></svg></div><div class="tx"><div class="meta">04 · Own</div><h3>Mixed-Reality Rowing Game</h3><p>A fun rowing game for two people, that uses an arduino and two real oars to be played.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t fr"><div class="vis" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="meta">05 · School</div><h3>Student Dashboard</h3><p>A concept student dashboard web-app, built upon conducted user studies.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t fr"><div class="vis" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="meta">06 · School</div><h3>VR-Classroom</h3><p>Register yourself, then create and sign up for classes.</p><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
</div>
<aside class="idx"><h3><span>More projects</span><span>7</span></h3>
<div class="grp">Own</div>
<div class="it"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="yr">react</div></div><span class="mk"><i></i></span></div>
<div class="it"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses Tracker</h4><div class="yr">javascript</div></div><span class="mk"><i></i></span></div>
<div class="it"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Discord Bot</h4><div class="yr">node.js</div></div><span class="mk"><i></i></span></div>
<div class="it"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Norman Borlaugh</h4><div class="yr">html, css</div></div><span class="mk"><i></i></span></div>
<div class="it"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="yr">react</div></div><span class="mk"><i></i></span></div>
<div class="grp">School</div>
<div class="it"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="yr">unity, VR</div></div><span class="mk"><i></i></span></div>
<div class="it"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="yr">python</div></div><span class="mk"><i></i></span></div>
</aside>
</div>
<!-- ================= H ================= -->
<div class="opt-head"><span class="L">H</span><div><h1>Two sizes, one even grid</h1><p>Only two tile sizes on a regular four-column grid: picked projects take a 2×2 block, everything else a single cell. Same rhythm everywhere, so nothing feels random, and small projects sit right next to big ones.</p></div></div>
<div class="note">Calm and classic. The catch: small projects become small cards with a picture (a bit larger than today's list rows), and the look edges toward a standard portfolio grid.</div>
<div class="sh"><h2>Projects</h2><span class="n">13 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="gH">
<article class="t P"><div class="vis draw"><span class="tag">config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin: <u>✓</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="tx"><div class="meta">Own</div><h3>Config</h3><div class="ft"><span class="open">Read the full story →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t P"><div class="vis" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="meta">Own</div><h3>Event Tracker for Gacha Games</h3><div class="ft"><span class="open">Read more →</span><span class="mk ai"><i></i>made with AI</span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/chess-swap.jpg)"></div><div class="tx"><h3>Chessswap</h3><div class="ft"><span class="meta">Own</span><span class="mk"><i></i></span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/budget.jpg)"></div><div class="tx"><h3>Monthly Expenses</h3><div class="ft"><span class="meta">Own</span><span class="mk"><i></i></span></div></div></article>
<article class="t P"><div class="vis" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="meta">School · thesis</div><h3>Bachelor Report</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div class="tx"><h3>LoL Winrate Bot</h3><div class="ft"><span class="meta">Own</span><span class="mk"><i></i></span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/censor-simulator.jpg)"></div><div class="tx"><h3>Censor Simulator</h3><div class="ft"><span class="meta">School</span><span class="mk"><i></i></span></div></div></article>
<article class="t P"><div class="vis draw"><span class="tag">rowing-stroke</span><svg width="80%" height="100" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/></svg></div><div class="tx"><div class="meta">Own</div><h3>Mixed-Reality Rowing Game</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t P"><div class="vis" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="meta">School</div><h3>Student Dashboard</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/breakout-python.jpg)"></div><div class="tx"><h3>BreakoutPython</h3><div class="ft"><span class="meta">School</span><span class="mk"><i></i></span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div class="tx"><h3>Tribute to Borlaugh</h3><div class="ft"><span class="meta">Own</span><span class="mk"><i></i></span></div></div></article>
<article class="t P"><div class="vis" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="meta">School</div><h3>VR-Classroom</h3><div class="ft"><span class="open">Read more →</span><span class="mk"><i></i>by hand</span></div></div></article>
<article class="t c"><div class="vis" style="background-image:url(/files/portfolio.jpg)"></div><div class="tx"><h3>Portfolio (2021)</h3><div class="ft"><span class="meta">Own</span><span class="mk"><i></i></span></div></div></article>
</div>
<!-- ================= Recognition & volunteering ================= -->
<div class="opt-head"><span class="L g">+</span><div><h1>Recognition &amp; volunteering (any grid)</h1><p>One box, two kinds of entry: things you competed in, and things you gave time to. Volunteer work isn't framed as your project, just as what you did there. Orange still marks what you flag as a highlight. Next to it, Keeping up from round 2, unchanged.</p></div></div>
<div class="rec3">
<div class="box"><h3>Recognition &amp; volunteering</h3>
<div class="vl" style="margin-top:12px">
<div style="border-top:0;padding-top:0;font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase">Competitions</div><div style="border-top:0"></div>
<div><span style="color:var(--acc)">AUHackathon 2019</span></div><div class="r" style="color:var(--acc)">winner · best AUHack</div>
<div>First Lego League<span class="sub">four years running</span></div><div class="r" style="color:var(--acc)">won round 1, twice</div>
<div>Google Hash Code 2021</div><div class="r" style="color:var(--acc)">top 12%</div>
<div>De Danske Cybermesterskaber 2024</div><div class="r">regional participant</div>
<div style="font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;padding-top:18px">Volunteering</div><div></div>
<div><a>Art Bubble</a> <span class="meta">art-bubble.dk ↗</span><span class="sub">IT and website, as a volunteer</span></div><div class="r"><span class="ph" title="placeholder">since ?</span> · ongoing</div>
<div>Lystrup Genbrugser<span class="sub">IT and website, as a volunteer · site since retired</span></div><div class="r"><span class="ph" title="placeholder">years?</span></div>
</div>
</div>
<div class="box"><h3>Keeping up</h3><p class="sum"><span class="cert" style="font:500 14px var(--sans)"><svg width="15" height="15" style="color:var(--acc)"><use href="#seal"/></svg><b>18 certificates</b></span> from 23 courses and hands-on labs · <b>~27 hours</b> since Feb 2025</p>
<div class="ku">
<div class="h">topic</div><div class="h" style="text-align:right">done</div><div class="h" style="text-align:right">cert.</div><div class="h" style="text-align:right">time</div>
<div>Ansible &amp; configuration</div><div class="c">2 courses · 3 labs</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>5</span></div><div class="c">9.4h</div>
<div>Linux administration</div><div class="c">1 course</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>1</span></div><div class="c">6.7h</div>
<div>Security</div><div class="c">2 courses · 1 lab</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>2</span></div><div class="c">4.9h</div>
<div>Serverless on AWS</div><div class="c">5 courses · 3 labs</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>5</span></div><div class="c">3.9h</div>
<div>RAG &amp; LLM systems</div><div class="c">4 courses · 1 lab</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>4</span></div><div class="c">1.8h</div>
<div>Observability</div><div class="c">1 course</div><div class="c cer"><span class="cert"><svg width="13" height="13"><use href="#seal"/></svg>1</span></div><div class="c">0.4h</div>
</div>
<a class="more">All courses and certificates, searchable →</a>
</div>
</div>
<div class="pick">
<button data-choice="f" onclick="pick(this)">F · alternating bands</button>
<button data-choice="g" onclick="pick(this)">G · picked + index column</button>
<button data-choice="h" onclick="pick(this)">H · two sizes, even grid</button>
</div>
</div>
<script>function pick(b){document.querySelectorAll('.pick button').forEach(x=>x.classList.remove('selected'));b.classList.add('selected');if(window.brainstorm&&brainstorm.send)brainstorm.send({type:'click',choice:b.dataset.choice,text:b.textContent});}</script>
</body>
</html>
+199
View File
@@ -0,0 +1,199 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Work page: round 4</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{--bg:#131210;--panel:#1b1916;--panel2:#221f1b;--line:#2b2824;--ink:#ede7dd;--mute:#8e877c;--acc:#ea7444;--ok:#a8b48f;
--sans:'Geist',system-ui,sans-serif;--mono:'Geist Mono',ui-monospace,monospace;--e:cubic-bezier(.2,.8,.2,1)}
*{box-sizing:border-box}html,body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 var(--sans)}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.opt-head{border-top:1px dashed #3a352f;margin-top:80px;padding:28px 0 8px;display:flex;gap:18px;align-items:baseline}
.opt-head.first{margin-top:24px;border-top:0}
.opt-head .L{font:600 13px var(--mono);color:var(--bg);background:var(--acc);border-radius:4px;padding:2px 8px}
.opt-head .L.g{background:var(--mute)}
.opt-head h1{font-size:22px;margin:0;font-weight:600}.opt-head p{margin:4px 0 0;color:var(--mute);max-width:720px}
.note{font:12px/1.55 var(--mono);color:var(--mute);border-left:2px solid var(--acc);padding:2px 0 2px 12px;margin:12px 0 22px;max-width:860px}
.sh{display:flex;align-items:baseline;gap:12px;margin:34px 0 16px}
.sh h2{font-size:22px;margin:0;font-weight:600}.sh .n{font:12px var(--mono);color:var(--mute)}
.sh .r{margin-left:auto;display:flex;gap:10px;align-items:center;font:12px var(--mono);color:var(--mute)}
.seg{display:flex;gap:2px}.seg span{font:12.5px var(--sans);color:var(--mute);padding:4px 9px;border-radius:5px}.seg span.on{background:var(--panel2);color:var(--ink);border:1px solid var(--line)}
.search{background:var(--bg);border:1px solid var(--line);border-radius:6px;padding:6px 10px;font:13px var(--sans);color:var(--mute);min-width:240px}
.search b{color:var(--ink);font-weight:400}
.meta{font:11px var(--mono);color:var(--mute);letter-spacing:.02em}
.ph{border-bottom:1px dotted var(--mute);cursor:help}
.mk{display:inline-flex;align-items:center;gap:6px;font:11px var(--mono);border:1px solid var(--line);border-radius:99px;padding:2px 8px;white-space:nowrap}
.mk i{width:8px;height:8px;border-radius:50%;border:1.5px solid currentColor;display:inline-block}
.mk.ai{color:var(--acc);border-color:#6b3a26}.mk.ai i{background:var(--acc);border-color:var(--acc)}
.mk.un i{border-style:dashed}
.chip{font:11px var(--mono);color:var(--mute);border:1px solid var(--line);border-radius:4px;padding:1px 6px}
/* tiles */
.t{background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;min-height:0;transition:border-color .2s var(--e)}
.t:hover{border-color:#4a433b}
.t .vis{flex:1;min-height:0;background:#0e0d0c center top/cover no-repeat;border-bottom:1px solid var(--line);position:relative}
.t .tx{padding:12px 16px 14px}
.t h3{margin:3px 0 2px;font-size:17px;font-weight:600;line-height:1.25}
.t p{margin:4px 0 0;color:#c9c2b6;font-size:13.5px;line-height:1.45}
.t .ft{display:flex;justify-content:space-between;align-items:center;margin-top:10px}
.t .open{font:12px var(--mono);color:var(--acc)}
.t.L h3{font-size:22px}
.tag{position:absolute;top:10px;left:12px;font:10px var(--mono);color:var(--mute)}
.draw{background:var(--panel2)!important;display:flex;align-items:center;justify-content:center}
.code{font:12px/1.7 var(--mono);color:#b9b2a6;padding:30px 24px;width:100%}.code b{color:var(--acc);font-weight:400}.code u{color:var(--ok);text-decoration:none}
/* small tile: same footprint as today's list row */
.s{flex-direction:row;align-items:center;gap:12px;padding:0 12px}
.s .th{width:60px;height:40px;border-radius:4px;background:#0e0d0c center/cover;flex:none;border:1px solid var(--line)}
.s h4{margin:0;font-size:14px;font-weight:500;line-height:1.3}
.s .mk{margin-left:auto;padding:1px 6px}
/* other-work tiles */
.ow .vis{background:repeating-linear-gradient(135deg,#1d1b18 0 10px,#1a1815 10px 20px)!important;display:flex;align-items:center;justify-content:center}
.site{font:500 15px var(--mono);color:var(--ink);border:1px solid var(--line);background:var(--bg);border-radius:6px;padding:8px 14px}
.site small{display:block;font:10px var(--mono);color:var(--mute);margin-top:2px}
.badge{font:10px var(--mono);color:var(--ok);border:1px solid #3d4433;border-radius:4px;padding:0 5px}
.badge.gone{color:var(--mute);border-color:var(--line)}
/* ---------- D : woven pattern ---------- */
.gD{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px}
/* ---------- E : dense auto-pack ---------- */
.gE{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px;grid-auto-flow:row dense}
.gE .L{grid-column:span 7;grid-row:span 6}
.gE .M{grid-column:span 5;grid-row:span 5}
.gE .T{grid-column:span 4;grid-row:span 6}
.gE .W{grid-column:span 5;grid-row:span 4}
.gE .ow{grid-column:span 3;grid-row:span 3}
.gE .s{grid-column:span 3;grid-row:span 1}
/* ---------- record ---------- */
.rec{display:grid;grid-template-columns:1fr 1.25fr;gap:14px}
.box{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.box h3{margin:0 0 4px;font:500 11px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
.box .sum{font-size:14px;color:#c9c2b6;margin:0 0 12px}
.box .sum b{color:var(--ink);font-weight:500}
.led{display:grid;grid-template-columns:44px 1fr auto;gap:0 14px;font-size:14px}
.led>div{padding:8px 0;border-top:1px solid var(--line)}
.led .y{font:12px var(--mono);color:var(--mute)}.led .res{font:12px var(--mono);color:var(--mute);text-align:right}
.led .hi{color:var(--acc)}
.ku{display:grid;grid-template-columns:1fr auto auto auto;gap:0 18px;font-size:14px;align-items:center}
.ku>div{padding:9px 0;border-top:1px solid var(--line)}
.ku .h{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;border-top:0;padding-top:0}
.ku .c{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.cert{display:inline-flex;align-items:center;gap:5px;font:12px var(--mono);color:var(--ink);white-space:nowrap}
.cert svg{flex:none}
.ku .c.cer{color:var(--ink)}
.more{display:inline-block;margin-top:14px;font:12px var(--mono);color:var(--acc)}
/* search results */
.res-wrap{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.rgrid{display:grid;grid-template-columns:1.1fr 1fr;gap:18px}
.rh{font:500 10.5px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;margin:0 0 8px}
.rl>div{display:grid;grid-template-columns:1fr auto;gap:10px;padding:8px 0;border-top:1px solid var(--line);font-size:14px}
.rl .m{font:11.5px var(--mono);color:var(--mute);white-space:nowrap}
mark{background:none;color:var(--acc)}
/* other work in history */
.hist{display:grid;grid-template-columns:90px 1fr auto;gap:0 16px;font-size:14px}
.hist>div{padding:10px 0;border-top:1px solid var(--line)}.hist .k{font:11px var(--mono);color:var(--mute);padding-top:12px}
.pick{display:flex;gap:10px;margin:26px 0 70px}
.pick button{font:13px var(--mono);background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:8px 14px;cursor:pointer}
.pick button.selected,.pick button:hover{border-color:var(--acc);color:var(--acc)}
.blocks{display:grid;gap:14px}
.b2{grid-template-columns:repeat(2,1fr)}
.b3{grid-template-columns:repeat(3,1fr)}
/* every block is the same size */
.blk{background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;transition:border-color .2s var(--e)}
.b2 .blk{height:372px}.b3 .blk{height:318px}
.blk:hover{border-color:#4a433b}
.blk .vis{flex:1;min-height:0;background:#0e0d0c center top/cover no-repeat;border-bottom:1px solid var(--line);position:relative}
/* one image treatment: screenshots toned to the page until you point at them */
.tone .vis.img{filter:grayscale(.85) sepia(.25) brightness(.62) contrast(1.05);transition:filter .3s var(--e)}
.tone .blk:hover .vis.img{filter:none}
.blk .tx{padding:14px 18px 16px}
.blk .row1{display:flex;justify-content:space-between;align-items:center}
.blk h3{margin:6px 0 2px;font-size:18px;font-weight:600}
.b3 .blk h3{font-size:16px}
.blk p{margin:0;color:#b9b2a6;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.num{font:11px var(--mono);color:var(--acc)}
/* a block holding small projects at today's row size */
.smalls{padding:6px 16px 8px;justify-content:flex-start}
.smalls .lab{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;padding:10px 0 6px}
.smalls .r{display:grid;grid-template-columns:56px 1fr auto;gap:12px;align-items:center;padding:10px 0;border-top:1px solid var(--line)}
.smalls .th{width:56px;height:37px;border-radius:4px;background:#0e0d0c center/cover;border:1px solid var(--line)}
.tone .smalls .th{filter:grayscale(.85) sepia(.25) brightness(.62)}
.tone .smalls .r:hover .th{filter:none}
.smalls h4{margin:0;font-size:14px;font-weight:500}
.smalls .d{font:11px var(--mono);color:var(--mute)}
.smalls .mk{padding:1px 6px}
.b3 .smalls .r{padding:8px 0}
.empty{border:1px dashed var(--line);background:none}
.legend2{display:flex;gap:18px;font:11.5px var(--mono);color:var(--mute);margin:-6px 0 16px}
</style>
</head>
<body>
<div class="wrap">
<p class="meta" style="margin-top:28px">Round 4 · taking F and H and removing what made them busy: <b style="color:var(--ink);font-weight:500">every block is the same size</b>, small projects come in blocks of their own (still at today's row size), <b style="color:var(--ink);font-weight:500">screenshots are toned</b> to the page until you point at one, and tiles carry only number, title, one line and the AI mark.</p>
<!-- ================= I ================= -->
<div class="opt-head first"><span class="L">I</span><div><h1>Equal blocks, two across</h1><p>A plain two-column grid where every block is identical in size. A block is either one picked project or a group of four small ones. After the first pair, a block of small ones takes every few slots, so the small projects show up among the big ones, not after them.</p></div></div>
<div class="note">Why it should feel calmer than F/H: one shape only, aligned rows, the same image treatment on every tile, and much less text. Hover any tile to see its real colours.</div>
<div class="sh"><h2>Projects</h2><span class="n">13 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="blocks b2 tone">
<a class="blk"><div class="vis draw"><span class="tag">config-editor · hover</span><div class="code"><b>services:</b><br>&nbsp;&nbsp;jellyfin:<br>&nbsp;&nbsp;&nbsp;&nbsp;image: <u>lscr.io/linuxserver/jellyfin</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ 2 hosts up to date</u></div></div><div class="tx"><div class="row1"><span class="num">01 <span class="meta">· own</span></span><span class="mk ai"><i></i>made with AI</span></div><h3>Config</h3><p>Store, sync and manage docker-compose based deployment on servers.</p></div></a>
<a class="blk"><div class="vis img" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="row1"><span class="num">02 <span class="meta">· own</span></span><span class="mk ai"><i></i>made with AI</span></div><h3>Event Tracker for Gacha Games</h3><p>Which live service game events to prioritize.</p></div></a>
<a class="blk"><div class="vis img" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="row1"><span class="num">03 <span class="meta">· school · thesis</span></span><span class="mk"><i></i>by hand</span></div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p></div></a>
<div class="blk smalls"><div class="lab">More · own</div>
<div class="r"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="d">react · webapp</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses Tracker</h4><div class="d">javascript · webapp</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Discord Bot</h4><div class="d">node.js · bot</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Norman Borlaugh</h4><div class="d">html · css</div></div><span class="mk"><i></i></span></div>
</div>
<a class="blk"><div class="vis draw"><span class="tag">rowing-stroke · hover</span><svg width="80%" height="120" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/><path d="M0 95 C45 95 55 35 95 35 S145 95 185 95 S235 40 265 40" fill="none" stroke="#8e877c" stroke-width="1.5" stroke-dasharray="4 4"/></svg></div><div class="tx"><div class="row1"><span class="num">04 <span class="meta">· own</span></span><span class="mk"><i></i>by hand</span></div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p></div></a>
<a class="blk"><div class="vis img" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="row1"><span class="num">05 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>Student Dashboard</h3><p>A concept dashboard, built upon conducted user studies.</p></div></a>
<div class="blk smalls"><div class="lab">More · school &amp; own</div>
<div class="r"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="d">unity · VR · C#</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="d">python · game</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="d">react · website</div></div><span class="mk"><i></i></span></div>
</div>
<a class="blk"><div class="vis img" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="row1"><span class="num">06 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>VR-Classroom</h3><p>Register, then create and sign up for classes.</p></div></a>
</div>
<!-- ================= J ================= -->
<div class="opt-head"><span class="L">J</span><div><h1>Equal blocks, three across</h1><p>The same idea, denser: three identical blocks per row, groups of three small projects per block. More fits on one screen; each picked project gets a bit less room.</p></div></div>
<div class="note">The row of three makes the six read as "the main ones" at a glance.</div>
<div class="sh"><h2>Projects</h2><span class="n">13 · 6 picked</span><span class="r"><span class="seg"><span class="on">All</span><span>Own</span><span>School</span></span><span class="search">Search projects &amp; certificates</span></span></div>
<div class="blocks b3 tone">
<a class="blk"><div class="vis draw"><span class="tag">config-editor · hover</span><div class="code" style="padding:20px 18px;font-size:11px"><b>services:</b><br>&nbsp;&nbsp;jellyfin: <u>✓</u><br><b>hosts:</b> [ lucwin-01, lucwin-02 ]<br><b>sync:</b> <u>✓ up to date</u></div></div><div class="tx"><div class="row1"><span class="num">01 <span class="meta">· own</span></span><span class="mk ai"><i></i>AI</span></div><h3>Config</h3><p>Store, sync and manage docker-compose deployments.</p></div></a>
<a class="blk"><div class="vis img" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="row1"><span class="num">02 <span class="meta">· own</span></span><span class="mk ai"><i></i>AI</span></div><h3>Event Tracker for Gacha Games</h3><p>Which live service game events to prioritize.</p></div></a>
<div class="blk smalls"><div class="lab">More · own</div>
<div class="r"><div class="th" style="background-image:url(/files/chess-swap.jpg)"></div><div><h4>Chessswap</h4><div class="d">react</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/budget.jpg)"></div><div><h4>Monthly Expenses Tracker</h4><div class="d">javascript</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/lol-winrate-discord-bot.jpg)"></div><div><h4>LoL Winrate Discord Bot</h4><div class="d">node.js</div></div><span class="mk"><i></i></span></div>
</div>
<a class="blk"><div class="vis img" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="row1"><span class="num">03 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p></div></a>
<a class="blk"><div class="vis draw"><span class="tag">rowing-stroke · hover</span><svg width="80%" height="90" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/></svg></div><div class="tx"><div class="row1"><span class="num">04 <span class="meta">· own</span></span><span class="mk"><i></i>by hand</span></div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p></div></a>
<a class="blk"><div class="vis img" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="row1"><span class="num">05 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>Student Dashboard</h3><p>A concept dashboard built on user studies.</p></div></a>
<div class="blk smalls"><div class="lab">More · school</div>
<div class="r"><div class="th" style="background-image:url(/files/censor-simulator.jpg)"></div><div><h4>Censor Simulator</h4><div class="d">unity · VR</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/breakout-python.jpg)"></div><div><h4>BreakoutPython</h4><div class="d">python</div></div><span class="mk"><i></i></span></div>
<div class="r"><div class="th" style="background-image:url(/files/tribute-to-bourlaug.jpg)"></div><div><h4>Tribute to Norman Borlaugh</h4><div class="d">html · css</div></div><span class="mk"><i></i></span></div>
</div>
<a class="blk"><div class="vis img" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="row1"><span class="num">06 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>VR-Classroom</h3><p>Register, then create and sign up for classes.</p></div></a>
<div class="blk smalls"><div class="lab">More · own</div>
<div class="r"><div class="th" style="background-image:url(/files/portfolio.jpg)"></div><div><h4>Portfolio (2021)</h4><div class="d">react</div></div><span class="mk"><i></i></span></div>
</div>
</div>
<!-- untoned comparison -->
<div class="opt-head"><span class="L g">?</span><div><h1>Same blocks without the toning</h1><p>For comparison: the first row of I with the screenshots at full colour. The white Bachelor Report and bright VR-Classroom screenshots are a big part of what made F and H feel noisy.</p></div></div>
<div class="blocks b2" style="margin-top:16px">
<a class="blk"><div class="vis img" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="row1"><span class="num">03 <span class="meta">· school · thesis</span></span><span class="mk"><i></i>by hand</span></div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p></div></a>
<a class="blk"><div class="vis img" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="row1"><span class="num">06 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>VR-Classroom</h3><p>Register, then create and sign up for classes.</p></div></a>
</div>
<div class="pick">
<button data-choice="i" onclick="pick(this)">I · equal blocks, two across</button>
<button data-choice="j" onclick="pick(this)">J · equal blocks, three across</button>
</div>
</div>
<script>function pick(b){document.querySelectorAll('.pick button').forEach(x=>x.classList.remove('selected'));b.classList.add('selected');if(window.brainstorm&&brainstorm.send)brainstorm.send({type:'click',choice:b.dataset.choice,text:b.textContent});}</script>
</body>
</html>
+404
View File
@@ -0,0 +1,404 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Work page: full-page directions</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{--bg:#131210;--panel:#1b1916;--panel2:#221f1b;--line:#2b2824;--ink:#ede7dd;--mute:#8e877c;--acc:#ea7444;--ok:#a8b48f;
--sans:'Geist',system-ui,sans-serif;--mono:'Geist Mono',ui-monospace,monospace;--e:cubic-bezier(.2,.8,.2,1)}
*{box-sizing:border-box}html,body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 var(--sans)}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.opt-head{border-top:1px dashed #3a352f;margin-top:80px;padding:28px 0 8px;display:flex;gap:18px;align-items:baseline}
.opt-head.first{margin-top:24px;border-top:0}
.opt-head .L{font:600 13px var(--mono);color:var(--bg);background:var(--acc);border-radius:4px;padding:2px 8px}
.opt-head .L.g{background:var(--mute)}
.opt-head h1{font-size:22px;margin:0;font-weight:600}.opt-head p{margin:4px 0 0;color:var(--mute);max-width:720px}
.note{font:12px/1.55 var(--mono);color:var(--mute);border-left:2px solid var(--acc);padding:2px 0 2px 12px;margin:12px 0 22px;max-width:860px}
.sh{display:flex;align-items:baseline;gap:12px;margin:34px 0 16px}
.sh h2{font-size:22px;margin:0;font-weight:600}.sh .n{font:12px var(--mono);color:var(--mute)}
.sh .r{margin-left:auto;display:flex;gap:10px;align-items:center;font:12px var(--mono);color:var(--mute)}
.seg{display:flex;gap:2px}.seg span{font:12.5px var(--sans);color:var(--mute);padding:4px 9px;border-radius:5px}.seg span.on{background:var(--panel2);color:var(--ink);border:1px solid var(--line)}
.search{background:var(--bg);border:1px solid var(--line);border-radius:6px;padding:6px 10px;font:13px var(--sans);color:var(--mute);min-width:240px}
.search b{color:var(--ink);font-weight:400}
.meta{font:11px var(--mono);color:var(--mute);letter-spacing:.02em}
.ph{border-bottom:1px dotted var(--mute);cursor:help}
.mk{display:inline-flex;align-items:center;gap:6px;font:11px var(--mono);border:1px solid var(--line);border-radius:99px;padding:2px 8px;white-space:nowrap}
.mk i{width:8px;height:8px;border-radius:50%;border:1.5px solid currentColor;display:inline-block}
.mk.ai{color:var(--acc);border-color:#6b3a26}.mk.ai i{background:var(--acc);border-color:var(--acc)}
.mk.un i{border-style:dashed}
.chip{font:11px var(--mono);color:var(--mute);border:1px solid var(--line);border-radius:4px;padding:1px 6px}
/* tiles */
.t{background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;min-height:0;transition:border-color .2s var(--e)}
.t:hover{border-color:#4a433b}
.t .vis{flex:1;min-height:0;background:#0e0d0c center top/cover no-repeat;border-bottom:1px solid var(--line);position:relative}
.t .tx{padding:12px 16px 14px}
.t h3{margin:3px 0 2px;font-size:17px;font-weight:600;line-height:1.25}
.t p{margin:4px 0 0;color:#c9c2b6;font-size:13.5px;line-height:1.45}
.t .ft{display:flex;justify-content:space-between;align-items:center;margin-top:10px}
.t .open{font:12px var(--mono);color:var(--acc)}
.t.L h3{font-size:22px}
.tag{position:absolute;top:10px;left:12px;font:10px var(--mono);color:var(--mute)}
.draw{background:var(--panel2)!important;display:flex;align-items:center;justify-content:center}
.code{font:12px/1.7 var(--mono);color:#b9b2a6;padding:30px 24px;width:100%}.code b{color:var(--acc);font-weight:400}.code u{color:var(--ok);text-decoration:none}
/* small tile: same footprint as today's list row */
.s{flex-direction:row;align-items:center;gap:12px;padding:0 12px}
.s .th{width:60px;height:40px;border-radius:4px;background:#0e0d0c center/cover;flex:none;border:1px solid var(--line)}
.s h4{margin:0;font-size:14px;font-weight:500;line-height:1.3}
.s .mk{margin-left:auto;padding:1px 6px}
/* other-work tiles */
.ow .vis{background:repeating-linear-gradient(135deg,#1d1b18 0 10px,#1a1815 10px 20px)!important;display:flex;align-items:center;justify-content:center}
.site{font:500 15px var(--mono);color:var(--ink);border:1px solid var(--line);background:var(--bg);border-radius:6px;padding:8px 14px}
.site small{display:block;font:10px var(--mono);color:var(--mute);margin-top:2px}
.badge{font:10px var(--mono);color:var(--ok);border:1px solid #3d4433;border-radius:4px;padding:0 5px}
.badge.gone{color:var(--mute);border-color:var(--line)}
/* ---------- D : woven pattern ---------- */
.gD{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px}
/* ---------- E : dense auto-pack ---------- */
.gE{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-rows:62px;gap:12px;grid-auto-flow:row dense}
.gE .L{grid-column:span 7;grid-row:span 6}
.gE .M{grid-column:span 5;grid-row:span 5}
.gE .T{grid-column:span 4;grid-row:span 6}
.gE .W{grid-column:span 5;grid-row:span 4}
.gE .ow{grid-column:span 3;grid-row:span 3}
.gE .s{grid-column:span 3;grid-row:span 1}
/* ---------- record ---------- */
.rec{display:grid;grid-template-columns:1fr 1.25fr;gap:14px}
.box{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.box h3{margin:0 0 4px;font:500 11px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
.box .sum{font-size:14px;color:#c9c2b6;margin:0 0 12px}
.box .sum b{color:var(--ink);font-weight:500}
.led{display:grid;grid-template-columns:44px 1fr auto;gap:0 14px;font-size:14px}
.led>div{padding:8px 0;border-top:1px solid var(--line)}
.led .y{font:12px var(--mono);color:var(--mute)}.led .res{font:12px var(--mono);color:var(--mute);text-align:right}
.led .hi{color:var(--acc)}
.ku{display:grid;grid-template-columns:1fr auto auto auto;gap:0 18px;font-size:14px;align-items:center}
.ku>div{padding:9px 0;border-top:1px solid var(--line)}
.ku .h{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;border-top:0;padding-top:0}
.ku .c{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.cert{display:inline-flex;align-items:center;gap:5px;font:12px var(--mono);color:var(--ink);white-space:nowrap}
.cert svg{flex:none}
.ku .c.cer{color:var(--ink)}
.more{display:inline-block;margin-top:14px;font:12px var(--mono);color:var(--acc)}
/* search results */
.res-wrap{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.rgrid{display:grid;grid-template-columns:1.1fr 1fr;gap:18px}
.rh{font:500 10.5px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;margin:0 0 8px}
.rl>div{display:grid;grid-template-columns:1fr auto;gap:10px;padding:8px 0;border-top:1px solid var(--line);font-size:14px}
.rl .m{font:11.5px var(--mono);color:var(--mute);white-space:nowrap}
mark{background:none;color:var(--acc)}
/* other work in history */
.hist{display:grid;grid-template-columns:90px 1fr auto;gap:0 16px;font-size:14px}
.hist>div{padding:10px 0;border-top:1px solid var(--line)}.hist .k{font:11px var(--mono);color:var(--mute);padding-top:12px}
.pick{display:flex;gap:10px;margin:26px 0 70px}
.pick button{font:13px var(--mono);background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:8px 14px;cursor:pointer}
.pick button.selected,.pick button:hover{border-color:var(--acc);color:var(--acc)}
body{padding-bottom:80px}
.tabs{position:sticky;top:0;z-index:50;background:#0c0b0a;border-bottom:1px solid var(--line);display:flex;gap:6px;align-items:center;padding:10px 32px}
.tabs .lbl{font:11px var(--mono);color:var(--mute);margin-right:10px}
.tabs button{font:12.5px var(--mono);background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:6px 12px;cursor:pointer}
.tabs button.on{border-color:var(--acc);color:var(--acc)}
.tabs .desc{margin-left:14px;font:12px var(--sans);color:var(--mute)}
.page{display:none}.page.on{display:block}
/* site chrome */
.top{display:flex;align-items:center;gap:22px;height:56px;border-bottom:1px solid var(--line);padding:0 32px;font-size:13.5px}
.top .gate{font:12px var(--mono);border:1px solid var(--line);border-radius:5px;padding:3px 8px;color:var(--mute)}
.top .nm{font-weight:600}.top .nm span{color:var(--mute);font-weight:400}
.top nav{display:flex;gap:18px;color:var(--mute)}
.top .pref{margin-left:auto;display:flex;align-items:center;gap:8px;font:12px var(--mono);color:var(--mute)}
.top .pref .sw{display:flex;border:1px solid var(--line);border-radius:6px;padding:2px}
.top .pref .sw span{padding:3px 8px;border-radius:4px}.top .pref .sw span.on{background:var(--ink);color:var(--bg)}
.foot{border-top:1px solid var(--line);margin-top:70px;padding:22px 32px;font:12px var(--mono);color:var(--mute);display:flex;gap:22px}
/* muted screenshots */
.mut{filter:saturate(.5) brightness(.82) contrast(1.02);transition:filter .3s var(--e)}
a:hover .mut,.hov:hover .mut{filter:none}
a{color:inherit;text-decoration:none}
.lab{font:500 10.5px var(--mono);letter-spacing:.09em;color:var(--mute);text-transform:uppercase}
.acc{color:var(--acc)}
.seal{display:inline-block;vertical-align:-2px}
/* common bits */
.kv{display:grid;grid-template-columns:78px 1fr;gap:9px 16px;font-size:15px}
.kv .k{font:11.5px var(--mono);color:var(--mute);padding-top:3px}
.btns{display:flex;gap:8px;flex-wrap:wrap}
.btn{font:12px var(--mono);border:1px solid var(--line);border-radius:5px;padding:4px 10px;color:var(--ink)}
.btn.p{border-color:#6b3a26;color:var(--acc)}
.hl{display:grid;grid-template-columns:1fr auto;gap:0 14px;font-size:14px}
.hl>div{padding:9px 0;border-top:1px solid var(--line)}
.hl .r{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.hl .r.acc{color:var(--acc)}
.big{font-size:30px;font-weight:600;letter-spacing:-.01em;line-height:1}
/* project cards */
.pc{display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden;transition:border-color .2s var(--e)}
.pc:hover{border-color:#4a433b}
.pc .vis{background:#0e0d0c center top/cover no-repeat;border-bottom:1px solid var(--line);position:relative}
.pc .tx{padding:14px 18px 16px}
.pc h3{margin:6px 0 3px;font-size:18px;font-weight:600}
.pc p{margin:0;color:#c3bcb0;font-size:13.5px}
.pc .row1{display:flex;justify-content:space-between;align-items:center}
.num{font:11px var(--mono);color:var(--acc)}
.dr{background:var(--panel2)!important;display:flex;align-items:center;justify-content:center}
/* quiet "also made" */
.also{display:grid;gap:0 28px}
.also a{display:grid;grid-template-columns:1fr auto;gap:10px;padding:7px 0;border-top:1px solid var(--line);font-size:13.5px;color:#b9b2a6}
.also a:hover{color:var(--ink)}
.also .m{font:11px var(--mono);color:var(--mute)}
.also .mk{padding:0 5px;font-size:10px;border-color:transparent}
.ai-note{font-size:13px;color:var(--mute);display:flex;align-items:center;gap:14px}
/* ===== K ===== */
.k-hero{display:grid;grid-template-columns:1.35fr 1fr;gap:0;border:1px solid var(--line);border-radius:12px;background:var(--panel);margin-top:28px;overflow:hidden}
.k-hero .cv{padding:30px 34px}
.k-hero .side{border-left:1px solid var(--line);padding:26px 28px;background:#181614;display:flex;flex-direction:column;gap:22px}
.k-hero h1{font-size:34px;line-height:1.1;margin:10px 0 6px;font-weight:600;letter-spacing:-.015em}
.k-hero .tg{color:var(--mute);margin:0 0 24px;font-size:16px}
.k-stats{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;align-items:baseline}
.k-stats .s{font:12px var(--mono);color:var(--mute)}
.k6{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.k6 .vis{height:190px}
.lowr{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.ku2{display:grid;grid-template-columns:1fr auto auto auto;gap:0 18px;font-size:14px}
.ku2>div{padding:8px 0;border-top:1px solid var(--line)}
.ku2 .c{font:12px var(--mono);color:var(--mute);text-align:right;white-space:nowrap}
.ku2 .h{font:500 10px var(--mono);letter-spacing:.08em;color:var(--mute);text-transform:uppercase;border-top:0}
/* ===== L ===== */
.l-wrap{display:grid;grid-template-columns:330px 1fr;gap:44px;max-width:1240px;margin:0 auto;padding:0 32px}
.l-side{position:sticky;top:64px;align-self:start;padding-top:30px}
.l-side h1{font-size:28px;margin:8px 0 4px;font-weight:600;line-height:1.1}
.l-side .tg{color:var(--mute);margin:0 0 20px;font-size:14.5px}
.l-side .kv{grid-template-columns:62px 1fr;font-size:14px;gap:8px 12px}
.l-side .blk{border-top:1px solid var(--line);padding:16px 0}
.l-main{padding-top:30px}
.l-lead{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.l-lead .vis{height:240px}
.l-four{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:14px}
.l-four .vis{height:120px}.l-four h3{font-size:15px}.l-four p{display:none}
/* ===== M ===== */
.m-intro{margin-top:30px;display:flex;align-items:baseline;gap:18px}
.m-intro h1{margin:0;font-size:26px;font-weight:600}.m-intro span{color:var(--mute)}
.m-band{display:grid;grid-template-columns:1.4fr 1fr 1fr;border:1px solid var(--line);border-radius:12px;background:var(--panel);margin-top:18px}
.m-band>div{padding:22px 24px}.m-band>div+div{border-left:1px solid var(--line)}
.m-band .kv{font-size:14px;grid-template-columns:62px 1fr}
.m-feat{display:grid;grid-template-columns:1.25fr 1fr;gap:14px}
.m-feat .lead .vis{height:330px}
.m-feat .stack{display:grid;grid-template-rows:1fr 1fr;gap:14px}
.m-feat .stack .pc{flex-direction:row}.m-feat .stack .vis{width:46%;border-bottom:0;border-right:1px solid var(--line)}
.m-row{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:14px}
.m-row .pc{flex-direction:row}.m-row .vis{width:120px;flex:none;border-bottom:0;border-right:1px solid var(--line)}
.m-row h3{font-size:15px}.m-row .tx{padding:12px 14px}
</style>
</head>
<body>
<svg width="0" height="0" style="position:absolute"><defs><symbol id="seal" viewBox="0 0 16 16"><circle cx="8" cy="6.5" r="4.6" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M5.2 10.2 4.4 15l3.6-1.8 3.6 1.8-.8-4.8" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/></symbol>
<symbol id="cfg" viewBox="0 0 300 150"><text x="18" y="34" font-family="Geist Mono,monospace" font-size="12" fill="#ea7444">services:</text><text x="18" y="54" font-family="Geist Mono,monospace" font-size="12" fill="#b9b2a6"> jellyfin: image: linuxserver/jellyfin</text><text x="18" y="74" font-family="Geist Mono,monospace" font-size="12" fill="#ea7444">hosts:<tspan fill="#b9b2a6"> [ lucwin-01, lucwin-02 ]</tspan></text><text x="18" y="94" font-family="Geist Mono,monospace" font-size="12" fill="#ea7444">sync:<tspan fill="#a8b48f"> ✓ 2 hosts up to date</tspan></text></symbol>
<symbol id="row" viewBox="0 0 300 110"><path d="M0 90 C40 90 50 20 90 20 S140 90 180 90 S230 25 260 25 S290 80 300 85" fill="none" stroke="#ea7444" stroke-width="2"/><path d="M0 95 C45 95 55 35 95 35 S145 95 185 95 S235 40 265 40" fill="none" stroke="#8e877c" stroke-width="1.5" stroke-dasharray="4 4"/></symbol></defs></svg>
<div class="tabs"><span class="lbl">Round 5 · full pages</span>
<button data-p="k" class="on">K · CV hero</button><button data-p="l">L · CV sidebar</button><button data-p="m">M · at-a-glance band</button>
<span class="desc" id="desc"></span>
</div>
<!-- =========================================================== K -->
<section class="page on" id="k" data-desc="The CV is a big card at the top; highlights and certificates sit inside it on the right. Then the six, then a quiet list.">
<div class="top"><span class="gate">← gate</span><span class="nm">Lucas Winther <span>/ work</span></span><nav><span>Projects</span><span>Record</span><span>Writing</span><span>History</span></nav><span class="pref">projects made: <span class="sw"><span class="on">any way</span><span>not fully by AI</span><span>by hand only</span></span></span></div>
<div class="wrap">
<div class="k-hero">
<div class="cv">
<div class="lab"><span class="acc">●</span>&nbsp; CV in ten seconds</div>
<h1>Lucas Winther</h1>
<p class="tg">Computer Scientist with passion for development.</p>
<div class="kv">
<span class="k">now</span><span>IT-medarbejder, IT Research Tech, Aarhus University <span class="meta">2025–now</span></span>
<span class="k">before</span><span>Intern, ScienceAtHome <span class="meta">2019</span><br>Student helper, Local Configuration Management, TERMA Group <span class="meta">2016–2018</span></span>
<span class="k">degree</span><span>Bachelor in Computer Science</span>
<span class="k">contact</span><span style="text-decoration:underline;text-decoration-color:var(--acc);text-underline-offset:3px">lucas@lucaswinther.info</span>
</div>
<div class="btns" style="margin-top:22px"><span class="btn">full history ↓</span><span class="btn">GitHub</span><span class="btn">LinkedIn</span></div>
</div>
<div class="side">
<div><div class="lab" style="margin-bottom:6px">Highlights</div>
<div class="hl">
<div class="acc">AUHackathon 2019</div><div class="r acc">winner</div>
<div>First Lego League</div><div class="r acc">won round 1, twice</div>
<div>Google Hash Code 2021</div><div class="r acc">top 12%</div>
</div><a class="meta" style="display:block;margin-top:8px">+ 3 more in the record ↓</a></div>
<div><div class="lab" style="margin-bottom:10px">Keeping up</div>
<div class="k-stats"><span class="big acc"><svg class="seal" width="22" height="22"><use href="#seal"/></svg> 18</span><span>certificates <span class="s">· 23 courses &amp; labs · ~27 h since Feb 2025</span></span></div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:12px"><span class="chip">Ansible 5</span><span class="chip">Serverless/AWS 5</span><span class="chip">RAG &amp; LLMs 4</span><span class="chip">Security 2</span><span class="chip">Linux 1</span></div>
<a class="meta" style="display:block;margin-top:10px">all courses ↓</a></div>
</div>
</div>
<div class="sh" style="margin-top:46px"><h2>Projects I'm proudest of</h2><span class="n">6</span><span class="r ai-note">marked by how much AI went into them · <span class="mk ai"><i></i>AI</span><span class="mk"><i></i>by hand</span></span></div>
<div class="k6">
<a class="pc"><div class="vis dr"><svg width="92%" height="150"><use href="#cfg"/></svg></div><div class="tx"><div class="row1"><span class="num">01 <span class="meta">· own</span></span><span class="mk ai"><i></i>made with AI</span></div><h3>Config</h3><p>Store, sync and manage docker-compose deployments on servers.</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="row1"><span class="num">02 <span class="meta">· own</span></span><span class="mk ai"><i></i>made with AI</span></div><h3>Event Tracker for Gacha Games</h3><p>Which live service game events to prioritize.</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="row1"><span class="num">03 <span class="meta">· school · thesis</span></span><span class="mk"><i></i>by hand</span></div><h3>Bachelor Report</h3><p>Reputation systems in peer-to-peer archival.</p></div></a>
<a class="pc"><div class="vis dr"><svg width="80%" height="110"><use href="#row"/></svg></div><div class="tx"><div class="row1"><span class="num">04 <span class="meta">· own</span></span><span class="mk"><i></i>by hand</span></div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="row1"><span class="num">05 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>Student Dashboard</h3><p>A concept dashboard built upon user studies.</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="row1"><span class="num">06 <span class="meta">· school</span></span><span class="mk"><i></i>by hand</span></div><h3>VR-Classroom</h3><p>Register, then create and sign up for classes.</p></div></a>
</div>
<div style="display:grid;grid-template-columns:180px 1fr;gap:20px;margin-top:26px">
<div><div class="lab">Also made</div><p class="meta" style="margin:6px 0 0;line-height:1.6">7 smaller and older projects · search</p></div>
<div class="also" style="grid-template-columns:repeat(3,1fr)">
<a>Chessswap <span class="m">react</span></a><a>Monthly Expenses Tracker <span class="m">js</span></a><a>LoL Winrate Discord Bot <span class="m">node</span></a>
<a>Censor Simulator <span class="m">unity · VR</span></a><a>BreakoutPython <span class="m">python</span></a><a>Tribute to Norman Borlaugh <span class="m">html</span></a>
<a>Portfolio (2021) <span class="m">react</span></a>
</div>
</div>
<div class="sh" style="margin-top:60px"><h2>Record</h2><span class="n">the full version of the highlights</span></div>
<div class="lowr">
<div class="box"><h3>Recognition &amp; volunteering</h3>
<div class="hl" style="margin-top:10px">
<div class="acc">AUHackathon 2019</div><div class="r acc">winner · best AUHack</div>
<div>First Lego League <span class="meta">· four years</span></div><div class="r acc">won round 1, two years running</div>
<div>Google Hash Code 2021</div><div class="r acc">top 12%</div>
<div>De Danske Cybermesterskaber 2024</div><div class="r">regional participant</div>
<div>Art Bubble <span class="meta">· art-bubble.dk ↗</span></div><div class="r">volunteer IT &amp; website · ongoing</div>
<div>Lystrup Genbrugser</div><div class="r">volunteer IT &amp; website · site retired</div>
</div></div>
<div class="box"><h3>Keeping up · 18 certificates</h3>
<div class="ku2" style="margin-top:10px">
<div class="h">topic</div><div class="h" style="text-align:right">done</div><div class="h" style="text-align:right">cert.</div><div class="h" style="text-align:right">time</div>
<div>Ansible &amp; configuration</div><div class="c">2 courses · 3 labs</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 5</div><div class="c">9.4h</div>
<div>Linux administration</div><div class="c">1 course</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 1</div><div class="c">6.7h</div>
<div>Security</div><div class="c">2 courses · 1 lab</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 2</div><div class="c">4.9h</div>
<div>Serverless on AWS</div><div class="c">5 courses · 3 labs</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 5</div><div class="c">3.9h</div>
<div>RAG &amp; LLM systems</div><div class="c">4 courses · 1 lab</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 4</div><div class="c">1.8h</div>
<div>Observability</div><div class="c">1 course</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 1</div><div class="c">0.4h</div>
</div><a class="more">All courses and certificates, searchable →</a></div>
</div>
<div class="lowr" style="margin-top:14px">
<div class="box"><h3>Writing · 1 post</h3><div style="font-size:14px">A synthetic work post <span class="meta">· 14 Mar 2025</span></div></div>
<div class="box"><h3>Where I've worked</h3><div class="kv" style="font-size:14px;margin-top:10px"><span class="k">now</span><span>IT Research Tech, Aarhus University (2025–now)</span><span class="k">before</span><span>Intern, ScienceAtHome (2019)<br>Student helper, TERMA Group (2016–2018)</span><span class="k">degree</span><span>Bachelor in Computer Science</span></div></div>
</div>
</div>
<div class="foot"><span>← back to the gate</span><span>/simple</span><span>GitHub</span><span>LinkedIn</span><span>lucas@lucaswinther.info</span></div>
</section>
<!-- =========================================================== L -->
<section class="page" id="l" data-desc="The CV, highlights and certificates live in a left column that stays put while you scroll the projects. Like a CV with a portfolio attached.">
<div class="top"><span class="gate">← gate</span><span class="nm">Lucas Winther <span>/ work</span></span><nav><span>Projects</span><span>Record</span><span>Writing</span></nav><span class="pref">projects made: <span class="sw"><span class="on">any way</span><span>not fully by AI</span><span>by hand only</span></span></span></div>
<div class="l-wrap">
<aside class="l-side">
<div class="lab"><span class="acc">●</span>&nbsp; CV in ten seconds</div>
<h1>Lucas Winther</h1><p class="tg">Computer Scientist with passion for development.</p>
<div class="kv"><span class="k">now</span><span>IT-medarbejder, IT Research Tech, Aarhus University <span class="meta">2025–</span></span><span class="k">before</span><span>Intern, ScienceAtHome <span class="meta">2019</span><br>Student helper, TERMA Group <span class="meta">2016–18</span></span><span class="k">degree</span><span>BSc Computer Science</span></div>
<div class="btns" style="margin:16px 0 4px"><span class="btn">GitHub</span><span class="btn">LinkedIn</span><span class="btn">Email</span></div>
<div class="blk" style="margin-top:14px"><div class="lab" style="margin-bottom:4px">Highlights</div>
<div class="hl"><div class="acc">AUHackathon 2019</div><div class="r acc">winner</div><div>First Lego League</div><div class="r acc">round 1 ×2</div><div>Hash Code 2021</div><div class="r acc">top 12%</div></div></div>
<div class="blk"><div class="lab" style="margin-bottom:8px">Keeping up</div>
<div><span class="big acc" style="font-size:26px"><svg class="seal" width="20" height="20"><use href="#seal"/></svg> 18</span> certificates</div>
<div class="meta" style="margin-top:6px">23 courses &amp; labs · ~27 h · since Feb 2025<br>Ansible · AWS serverless · RAG · security · Linux</div></div>
</aside>
<main class="l-main">
<div class="sh" style="margin-top:0"><h2>Projects I'm proudest of</h2><span class="n">6</span><span class="r ai-note"><span class="mk ai"><i></i>AI</span><span class="mk"><i></i>by hand</span></span></div>
<div class="l-lead">
<a class="pc"><div class="vis dr"><svg width="92%" height="160"><use href="#cfg"/></svg></div><div class="tx"><div class="row1"><span class="num">01 <span class="meta">· own</span></span><span class="mk ai"><i></i>made with AI</span></div><h3>Config</h3><p>Store, sync and manage docker-compose deployments on servers.</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="row1"><span class="num">02 <span class="meta">· own</span></span><span class="mk ai"><i></i>made with AI</span></div><h3>Event Tracker for Gacha Games</h3><p>Which live service game events to prioritize.</p></div></a>
</div>
<div class="l-four">
<a class="pc"><div class="vis mut" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="row1"><span class="num">03</span><span class="mk"><i></i></span></div><h3>Bachelor Report</h3></div></a>
<a class="pc"><div class="vis dr"><svg width="80%" height="70"><use href="#row"/></svg></div><div class="tx"><div class="row1"><span class="num">04</span><span class="mk"><i></i></span></div><h3>Mixed-Reality Rowing</h3></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="row1"><span class="num">05</span><span class="mk"><i></i></span></div><h3>Student Dashboard</h3></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="row1"><span class="num">06</span><span class="mk"><i></i></span></div><h3>VR-Classroom</h3></div></a>
</div>
<div style="margin-top:26px"><div class="lab" style="margin-bottom:6px">Also made · 7</div>
<div class="also" style="grid-template-columns:repeat(2,1fr)">
<a>Chessswap <span class="m">react</span></a><a>Censor Simulator <span class="m">unity · VR</span></a>
<a>Monthly Expenses Tracker <span class="m">js</span></a><a>BreakoutPython <span class="m">python</span></a>
<a>LoL Winrate Discord Bot <span class="m">node</span></a><a>Tribute to Norman Borlaugh <span class="m">html</span></a>
<a>Portfolio (2021) <span class="m">react</span></a>
</div></div>
<div class="sh" style="margin-top:56px"><h2>Record</h2></div>
<div class="box"><h3>Recognition &amp; volunteering</h3><div class="hl" style="margin-top:10px">
<div class="acc">AUHackathon 2019</div><div class="r acc">winner · best AUHack</div>
<div>First Lego League <span class="meta">· four years</span></div><div class="r acc">won round 1, two years running</div>
<div>Google Hash Code 2021</div><div class="r acc">top 12%</div>
<div>De Danske Cybermesterskaber 2024</div><div class="r">regional participant</div>
<div>Art Bubble <span class="meta">· art-bubble.dk ↗</span></div><div class="r">volunteer IT &amp; website · ongoing</div>
<div>Lystrup Genbrugser</div><div class="r">volunteer IT &amp; website · site retired</div></div></div>
<div class="box" style="margin-top:14px"><h3>Keeping up · 18 certificates · 23 courses &amp; labs</h3>
<div class="ku2" style="margin-top:10px">
<div>Ansible &amp; configuration</div><div class="c">2 courses · 3 labs</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 5</div><div class="c">9.4h</div>
<div>Linux administration</div><div class="c">1 course</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 1</div><div class="c">6.7h</div>
<div>Security</div><div class="c">2 courses · 1 lab</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 2</div><div class="c">4.9h</div>
<div>Serverless on AWS</div><div class="c">5 courses · 3 labs</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 5</div><div class="c">3.9h</div>
<div>RAG &amp; LLM systems</div><div class="c">4 courses · 1 lab</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 4</div><div class="c">1.8h</div>
</div><a class="more">All courses and certificates, searchable →</a></div>
<div class="box" style="margin-top:14px"><h3>Writing · 1 post</h3><div style="font-size:14px">A synthetic work post <span class="meta">· 14 Mar 2025</span></div></div>
</main>
</div>
<div class="foot"><span>← back to the gate</span><span>/simple</span><span>GitHub</span><span>LinkedIn</span><span>lucas@lucaswinther.info</span></div>
</section>
<!-- =========================================================== M -->
<section class="page" id="m" data-desc="A three-part band across the top (CV · highlights · keeping up), then one lead project, then the other five, then a quiet list.">
<div class="top"><span class="gate">← gate</span><span class="nm">Lucas Winther <span>/ work</span></span><nav><span>Projects</span><span>Record</span><span>Writing</span><span>History</span></nav><span class="pref">projects made: <span class="sw"><span class="on">any way</span><span>not fully by AI</span><span>by hand only</span></span></span></div>
<div class="wrap">
<div class="m-intro"><h1>Lucas Winther</h1><span>Computer Scientist with passion for development.</span></div>
<div class="m-band">
<div><div class="lab" style="margin-bottom:12px"><span class="acc">●</span>&nbsp; CV in ten seconds</div>
<div class="kv"><span class="k">now</span><span>IT-medarbejder, IT Research Tech, Aarhus University <span class="meta">2025–now</span></span><span class="k">before</span><span>Intern, ScienceAtHome <span class="meta">2019</span> · Student helper, TERMA Group <span class="meta">2016–2018</span></span><span class="k">degree</span><span>Bachelor in Computer Science</span></div>
<div class="btns" style="margin-top:16px"><span class="btn">GitHub</span><span class="btn">LinkedIn</span><span class="btn">Email</span></div></div>
<div><div class="lab" style="margin-bottom:6px">Highlights</div>
<div class="hl"><div class="acc">AUHackathon 2019</div><div class="r acc">winner</div><div>First Lego League</div><div class="r acc">round 1 ×2</div><div>Google Hash Code 2021</div><div class="r acc">top 12%</div></div>
<a class="meta" style="display:block;margin-top:8px">+ 3 more ↓</a></div>
<div><div class="lab" style="margin-bottom:10px">Keeping up</div>
<div><span class="big acc"><svg class="seal" width="22" height="22"><use href="#seal"/></svg> 18</span> <span>certificates</span></div>
<div class="meta" style="margin:8px 0 10px">23 courses &amp; labs · ~27 h since Feb 2025</div>
<div style="display:flex;gap:6px;flex-wrap:wrap"><span class="chip">Ansible</span><span class="chip">AWS serverless</span><span class="chip">RAG</span><span class="chip">Security</span><span class="chip">Linux</span></div></div>
</div>
<div class="sh" style="margin-top:46px"><h2>Projects I'm proudest of</h2><span class="n">6</span><span class="r ai-note">marked by how much AI went into them · <span class="mk ai"><i></i>AI</span><span class="mk"><i></i>by hand</span></span></div>
<div class="m-feat">
<a class="pc lead"><div class="vis dr"><svg width="92%" height="200"><use href="#cfg"/></svg></div><div class="tx"><div class="row1"><span class="num">01 <span class="meta">· own · personal project</span></span><span class="mk ai"><i></i>made with AI</span></div><h3 style="font-size:24px">Config</h3><p>A repository to store, sync and manage docker-compose based deployment on servers.</p></div></a>
<div class="stack">
<a class="pc"><div class="vis mut" style="background-image:url(/files/gacha-event-tracker.jpg)"></div><div class="tx"><div class="row1"><span class="num">02</span><span class="mk ai"><i></i>AI</span></div><h3>Event Tracker for Gacha Games</h3><p>Which live service game events to prioritize.</p></div></a>
<a class="pc"><div class="vis dr"><svg width="86%" height="90"><use href="#row"/></svg></div><div class="tx"><div class="row1"><span class="num">03</span><span class="mk"><i></i>by hand</span></div><h3>Mixed-Reality Rowing Game</h3><p>Two people, an Arduino and two real oars.</p></div></a>
</div>
</div>
<div class="m-row">
<a class="pc"><div class="vis mut" style="background-image:url(/files/bachelor-report.jpg)"></div><div class="tx"><div class="row1"><span class="num">04</span><span class="mk"><i></i></span></div><h3>Bachelor Report</h3><p class="meta">school · thesis</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/student-dashboard.jpg)"></div><div class="tx"><div class="row1"><span class="num">05</span><span class="mk"><i></i></span></div><h3>Student Dashboard</h3><p class="meta">school</p></div></a>
<a class="pc"><div class="vis mut" style="background-image:url(/files/vr-classroom.jpg)"></div><div class="tx"><div class="row1"><span class="num">06</span><span class="mk"><i></i></span></div><h3>VR-Classroom</h3><p class="meta">school</p></div></a>
</div>
<div style="margin-top:22px;display:flex;gap:10px 22px;flex-wrap:wrap;align-items:baseline;font-size:13.5px;color:#a39c90">
<span class="lab" style="margin-right:4px">Also made</span>
<a>Chessswap</a><a>Monthly Expenses Tracker</a><a>LoL Winrate Discord Bot</a><a>Censor Simulator</a><a>BreakoutPython</a><a>Tribute to Norman Borlaugh</a><a>Portfolio (2021)</a>
<span class="meta">· all projects, searchable →</span>
</div>
<div class="sh" style="margin-top:60px"><h2>Record</h2><span class="n">the full version</span></div>
<div class="lowr">
<div class="box"><h3>Recognition &amp; volunteering</h3><div class="hl" style="margin-top:10px">
<div class="acc">AUHackathon 2019</div><div class="r acc">winner · best AUHack</div>
<div>First Lego League <span class="meta">· four years</span></div><div class="r acc">won round 1, two years running</div>
<div>Google Hash Code 2021</div><div class="r acc">top 12%</div>
<div>De Danske Cybermesterskaber 2024</div><div class="r">regional participant</div>
<div>Art Bubble <span class="meta">· art-bubble.dk ↗</span></div><div class="r">volunteer IT &amp; website · ongoing</div>
<div>Lystrup Genbrugser</div><div class="r">volunteer IT &amp; website · site retired</div></div></div>
<div class="box"><h3>Keeping up · 18 certificates</h3><div class="ku2" style="margin-top:10px">
<div>Ansible &amp; configuration</div><div class="c">2 courses · 3 labs</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 5</div><div class="c">9.4h</div>
<div>Linux administration</div><div class="c">1 course</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 1</div><div class="c">6.7h</div>
<div>Security</div><div class="c">2 courses · 1 lab</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 2</div><div class="c">4.9h</div>
<div>Serverless on AWS</div><div class="c">5 courses · 3 labs</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 5</div><div class="c">3.9h</div>
<div>RAG &amp; LLM systems</div><div class="c">4 courses · 1 lab</div><div class="c" style="color:var(--ink)"><svg class="seal" width="12" height="12"><use href="#seal"/></svg> 4</div><div class="c">1.8h</div>
</div><a class="more">All courses and certificates, searchable →</a></div>
</div>
<div class="lowr" style="margin-top:14px">
<div class="box"><h3>Writing · 1 post</h3><div style="font-size:14px">A synthetic work post <span class="meta">· 14 Mar 2025</span></div></div>
<div class="box"><h3>Where I've worked</h3><div class="kv" style="font-size:14px;margin-top:10px"><span class="k">now</span><span>IT Research Tech, Aarhus University (2025–now)</span><span class="k">before</span><span>Intern, ScienceAtHome (2019)<br>Student helper, TERMA Group (2016–2018)</span></div></div>
</div>
</div>
<div class="foot"><span>← back to the gate</span><span>/simple</span><span>GitHub</span><span>LinkedIn</span><span>lucas@lucaswinther.info</span></div>
</section>
<script>
(function(){var d=document.getElementById('desc');function show(id){document.querySelectorAll('.page').forEach(function(p){p.classList.toggle('on',p.id===id)});document.querySelectorAll('.tabs button').forEach(function(b){b.classList.toggle('on',b.dataset.p===id)});d.textContent=document.getElementById(id).dataset.desc;window.scrollTo(0,0);if(window.brainstorm&&brainstorm.send)brainstorm.send({type:'click',choice:id,text:'viewed '+id});}
document.querySelectorAll('.tabs button').forEach(function(b){b.onclick=function(){show(b.dataset.p)}});show((location.hash||'#k').slice(1));})();
</script>
</body>
</html>