<!DOCTYPE html>
<html lang="no">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AIP2100 · LinkedIn Challenge</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Mono:wght@300;400;500&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Mono:wght@300;400;500&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap"></noscript>
<style>
:root {
--bg: #0a0a0f;
--surface: #111118;
--surface2: #1a1a24;
--border: #2a2a38;
--green: #00e5a0;
--green-dim: rgba(0,229,160,0.12);
--green-glow: rgba(0,229,160,0.25);
--amber: #ffb830;
--amber-dim: rgba(255,184,48,0.12);
--blue: #4d9fff;
--blue-dim: rgba(77,159,255,0.12);
--red: #ff5f7e;
--text: #e8e8f0;
--text-dim: #7a7a94;
--text-faint: #3a3a52;
--gold: #ffd700;
--silver: #c0c0d0;
--bronze: #cd7f45;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--text);
font-family: 'DM Sans', sans-serif;
min-height: 100vh;
overflow-x: hidden;
}
/* Grid background */
body::before {
content: '';
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(0,229,160,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0,229,160,0.03) 1px, transparent 1px);
background-size: 60px 60px;
pointer-events: none;
z-index: 0;
}
/* Radial glow top */
body::after {
content: '';
position: fixed;
top: -200px;
left: 50%;
transform: translateX(-50%);
width: 800px;
height: 400px;
background: radial-gradient(ellipse, rgba(0,229,160,0.08) 0%, transparent 70%);
pointer-events: none;
z-index: 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
position: relative;
z-index: 1;
}
/* HEADER */
header {
padding: 40px 0 32px;
border-bottom: 1px solid var(--border);
position: relative;
z-index: 1;
}
.header-inner {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 24px;
flex-wrap: wrap;
}
.logo-area h1 {
font-family: 'Syne', sans-serif;
font-size: 2.4rem;
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1;
color: var(--text);
}
.logo-area h1 span {
color: var(--green);
}
.logo-area p {
font-family: 'DM Mono', monospace;
font-size: 0.75rem;
color: var(--text-dim);
margin-top: 6px;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.header-stats {
display: flex;
gap: 32px;
}
.hstat {
text-align: right;
}
.hstat-value {
font-family: 'Syne', sans-serif;
font-size: 1.8rem;
font-weight: 700;
color: var(--green);
line-height: 1;
}
.hstat-label {
font-size: 0.7rem;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.1em;
margin-top: 4px;
font-family: 'DM Mono', monospace;
}
/* LAST UPDATED */
.last-updated {
padding: 12px 0;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 8px;
position: relative;
z-index: 1;
}
.pulse {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--green);
animation: pulse 2s ease infinite;
flex-shrink: 0;
}
@keyframes pulse {
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 var(--green-glow); }
50% { opacity: 0.7; box-shadow: 0 0 0 6px transparent; }
}
.last-updated span {
font-family: 'DM Mono', monospace;
font-size: 0.72rem;
color: var(--text-dim);
letter-spacing: 0.06em;
}
.last-updated strong {
color: var(--green);
font-weight: 500;
}
/* NAV TABS */
.nav-tabs {
display: flex;
gap: 4px;
padding: 24px 0 0;
border-bottom: 1px solid var(--border);
position: relative;
z-index: 1;
}
.tab-btn {
font-family: 'DM Mono', monospace;
font-size: 0.75rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 10px 20px;
background: transparent;
border: 1px solid transparent;
border-bottom: none;
color: var(--text-dim);
cursor: pointer;
transition: all 0.2s;
position: relative;
bottom: -1px;
}
.tab-btn:hover { color: var(--text); border-color: var(--border); }
.tab-btn.active {
color: var(--green);
border-color: var(--border);
border-bottom-color: var(--bg);
background: var(--surface);
}
/* MAIN LAYOUT */
.main {
padding: 32px 0 80px;
position: relative;
z-index: 1;
}
.section { display: none; }
.section.active { display: block; }
/* LEADERBOARD */
.leaderboard-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-bottom: 32px;
}
@media (max-width: 800px) {
.leaderboard-grid { grid-template-columns: 1fr; }
}
.lb-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
}
.lb-card-header {
padding: 16px 20px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
}
.lb-card-title {
font-family: 'Syne', sans-serif;
font-size: 0.85rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.lb-card-title .icon {
margin-right: 8px;
}
.lb-badge {
font-family: 'DM Mono', monospace;
font-size: 0.65rem;
padding: 3px 8px;
border-radius: 4px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.badge-green { background: var(--green-dim); color: var(--green); border: 1px solid rgba(0,229,160,0.2); }
.badge-amber { background: var(--amber-dim); color: var(--amber); border: 1px solid rgba(255,184,48,0.2); }
.lb-list {
list-style: none;
}
.lb-item {
display: flex;
align-items: center;
padding: 12px 20px;
gap: 14px;
border-bottom: 1px solid var(--border);
transition: background 0.15s;
cursor: default;
}
.lb-item:last-child { border-bottom: none; }
.lb-item:hover { background: var(--surface2); }
.lb-rank {
font-family: 'DM Mono', monospace;
font-size: 0.85rem;
font-weight: 500;
width: 28px;
text-align: center;
flex-shrink: 0;
}
.rank-1 { color: var(--gold); }
.rank-2 { color: var(--silver); }
.rank-3 { color: var(--bronze); }
.rank-other { color: var(--text-faint); }
.lb-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--surface2);
border: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: center;
font-family: 'Syne', sans-serif;
font-size: 0.75rem;
font-weight: 700;
color: var(--text-dim);
flex-shrink: 0;
}
.lb-info {
flex: 1;
min-width: 0;
}
.lb-name {
font-size: 0.88rem;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--text);
}
.lb-meta {
font-family: 'DM Mono', monospace;
font-size: 0.68rem;
color: var(--text-dim);
margin-top: 2px;
display: flex;
align-items: center;
gap: 6px;
}
.teacher-badge {
background: rgba(77,159,255,0.15);
color: var(--blue);
border: 1px solid rgba(77,159,255,0.25);
border-radius: 3px;
font-size: 0.6rem;
padding: 1px 5px;
letter-spacing: 0.05em;
}
.lb-score {
text-align: right;
flex-shrink: 0;
}
.lb-xp {
font-family: 'Syne', sans-serif;
font-size: 1.1rem;
font-weight: 700;
color: var(--green);
}
.lb-xp-label {
font-family: 'DM Mono', monospace;
font-size: 0.6rem;
color: var(--text-faint);
letter-spacing: 0.08em;
text-transform: uppercase;
}
/* XP bar */
.xp-bar-wrap {
height: 3px;
background: var(--surface2);
border-radius: 2px;
margin-top: 4px;
overflow: hidden;
}
.xp-bar {
height: 100%;
border-radius: 2px;
background: linear-gradient(90deg, var(--green), var(--blue));
transition: width 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
/* STREAK */
.streak-dots {
display: flex;
gap: 3px;
margin-top: 4px;
}
.streak-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--text-faint);
}
.streak-dot.active {
background: var(--amber);
box-shadow: 0 0 4px var(--amber);
}
/* POSTS FEED */
.feed-controls {
display: flex;
gap: 12px;
margin-bottom: 20px;
flex-wrap: wrap;
align-items: center;
}
.feed-filter {
font-family: 'DM Mono', monospace;
font-size: 0.72rem;
padding: 7px 14px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-dim);
cursor: pointer;
transition: all 0.15s;
letter-spacing: 0.06em;
}
.feed-filter:hover, .feed-filter.active {
border-color: var(--green);
color: var(--green);
background: var(--green-dim);
}
.feed-search {
flex: 1;
min-width: 200px;
font-family: 'DM Sans', sans-serif;
font-size: 0.85rem;
padding: 8px 16px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text);
outline: none;
transition: border-color 0.15s;
}
.feed-search:focus { border-color: var(--green); }
.feed-search::placeholder { color: var(--text-faint); }
.posts-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.post-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px 20px;
display: grid;
grid-template-columns: auto 1fr auto;
gap: 16px;
align-items: start;
transition: border-color 0.15s, transform 0.15s;
text-decoration: none;
color: inherit;
}
.post-card:hover {
border-color: rgba(0,229,160,0.3);
transform: translateY(-1px);
}
.post-week-badge {
font-family: 'DM Mono', monospace;
font-size: 0.65rem;
color: var(--text-faint);
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 4px;
padding: 3px 7px;
white-space: nowrap;
letter-spacing: 0.05em;
}
.post-body {
min-width: 0;
}
.post-author-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 5px;
flex-wrap: wrap;
}
.post-author {
font-size: 0.88rem;
font-weight: 500;
color: var(--text);
}
.post-team-tag {
font-family: 'DM Mono', monospace;
font-size: 0.62rem;
padding: 2px 7px;
border-radius: 3px;
background: var(--surface2);
color: var(--text-dim);
border: 1px solid var(--border);
letter-spacing: 0.04em;
}
.post-text {
font-size: 0.85rem;
color: var(--text-dim);
line-height: 1.5;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.post-date {
font-family: 'DM Mono', monospace;
font-size: 0.65rem;
color: var(--text-faint);
margin-top: 4px;
}
.post-stats {
display: flex;
gap: 12px;
align-items: center;
flex-shrink: 0;
}
.pstat {
text-align: center;
}
.pstat-value {
font-family: 'Syne', sans-serif;
font-size: 1rem;
font-weight: 700;
line-height: 1;
}
.pstat-label {
font-family: 'DM Mono', monospace;
font-size: 0.58rem;
color: var(--text-faint);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-top: 2px;
}
.likes-val { color: var(--amber); }
.comments-val { color: var(--blue); }
.ext-val { color: var(--green); }
.ext-highlight {
background: var(--green-dim);
border-color: rgba(0,229,160,0.25) !important;
}
/* WEEK SECTION DIVIDER */
.week-divider {
display: flex;
align-items: center;
gap: 12px;
margin: 24px 0 12px;
}
.week-divider-label {
font-family: 'DM Mono', monospace;
font-size: 0.7rem;
color: var(--text-faint);
letter-spacing: 0.1em;
text-transform: uppercase;
white-space: nowrap;
}
.week-divider-line {
flex: 1;
height: 1px;
background: var(--border);
}
/* STATS OVERVIEW */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 16px;
margin-bottom: 32px;
}
.stat-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 2px;
}
.stat-card.green::before { background: var(--green); }
.stat-card.amber::before { background: var(--amber); }
.stat-card.blue::before { background: var(--blue); }
.stat-card.red::before { background: var(--red); }
.stat-value {
font-family: 'Syne', sans-serif;
font-size: 2.2rem;
font-weight: 800;
line-height: 1;
margin-bottom: 6px;
}
.stat-card.green .stat-value { color: var(--green); }
.stat-card.amber .stat-value { color: var(--amber); }
.stat-card.blue .stat-value { color: var(--blue); }
.stat-card.red .stat-value { color: var(--red); }
.stat-label {
font-size: 0.8rem;
color: var(--text-dim);
line-height: 1.4;
}
.stat-sub {
font-family: 'DM Mono', monospace;
font-size: 0.65rem;
color: var(--text-faint);
margin-top: 8px;
letter-spacing: 0.05em;
}
/* TOP POST HIGHLIGHT */
.top-post-section {
background: var(--surface);
border: 1px solid rgba(0,229,160,0.25);
border-radius: 12px;
padding: 20px 24px;
margin-bottom: 24px;
position: relative;
overflow: hidden;
}
.top-post-section::before {
content: '🏆 UKENS INNLEGG';
font-family: 'DM Mono', monospace;
font-size: 0.65rem;
letter-spacing: 0.12em;
color: var(--amber);
display: block;
margin-bottom: 12px;
}
.top-post-glow {
position: absolute;
top: -60px; right: -60px;
width: 200px; height: 200px;
background: radial-gradient(circle, rgba(0,229,160,0.08), transparent 70%);
pointer-events: none;
}
/* SCORE MODEL INFO */
.score-model {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
margin-top: 24px;
}
.score-model h3 {
font-family: 'Syne', sans-serif;
font-size: 1rem;
font-weight: 700;
margin-bottom: 16px;
color: var(--text);
letter-spacing: 0.02em;
}
.score-table {
width: 100%;
border-collapse: collapse;
}
.score-table tr {
border-bottom: 1px solid var(--border);
}
.score-table tr:last-child { border-bottom: none; }
.score-table td {
padding: 10px 0;
font-size: 0.83rem;
vertical-align: middle;
}
.score-table td:first-child { color: var(--text); flex: 1; }
.score-table td:last-child {
text-align: right;
font-family: 'DM Mono', monospace;
font-weight: 500;
padding-left: 12px;
white-space: nowrap;
}
.pts-green { color: var(--green); }
.pts-amber { color: var(--amber); }
.pts-blue { color: var(--blue); }
/* ANIMATION */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.lb-item, .post-card, .stat-card {
animation: fadeIn 0.4s ease both;
}
.lb-item:nth-child(1) { animation-delay: 0.05s; }
.lb-item:nth-child(2) { animation-delay: 0.1s; }
.lb-item:nth-child(3) { animation-delay: 0.15s; }
.lb-item:nth-child(4) { animation-delay: 0.2s; }
.lb-item:nth-child(5) { animation-delay: 0.25s; }
.lb-item:nth-child(6) { animation-delay: 0.3s; }
.lb-item:nth-child(7) { animation-delay: 0.35s; }
.lb-item:nth-child(8) { animation-delay: 0.4s; }
.lb-item:nth-child(9) { animation-delay: 0.45s; }
.lb-item:nth-child(10) { animation-delay: 0.5s; }
/* FOOTER */
footer {
border-top: 1px solid var(--border);
padding: 20px 0;
position: relative;
z-index: 1;
}
footer p {
font-family: 'DM Mono', monospace;
font-size: 0.65rem;
color: var(--text-faint);
letter-spacing: 0.06em;
text-align: center;
}
/* RESPONSIVE */
/* Global word-wrap to prevent text overflow on small screens */
* { overflow-wrap: break-word; }
@media (max-width: 600px) {
.container { padding: 0 16px; }
.logo-area h1 { font-size: 1.6rem; }
.header-stats { gap: 16px; }
.hstat-value { font-size: 1.4rem; }
.nav-tabs { flex-wrap: wrap; gap: 4px; padding: 16px 0 0; }
.tab-btn { padding: 8px 12px; font-size: 0.7rem; }
.post-card { grid-template-columns: 1fr; }
.post-week-badge { display: none; }
.leaderboard-grid { grid-template-columns: 1fr; }
.feed-search { min-width: 0; width: 100%; }
.main { padding: 20px 0 60px; }
}
@media (max-width: 380px) {
.logo-area h1 { font-size: 1.3rem; }
.tab-btn { padding: 7px 10px; font-size: 0.65rem; }
.hstat-value { font-size: 1.2rem; }
.hstat-label { font-size: 0.6rem; }
}
</style>
</head>
<body>
<header>
<div class="container">
<div class="header-inner">
<div class="logo-area">
<h1>AIP2100 <span>#LinkedInChallenge</span></h1>
<p>Høyskolen Kristiania · Vår 2026</p>
</div>
<div class="header-stats">
<div class="hstat">
<div class="hstat-value" id="total-posts">60</div>
<div class="hstat-label">Innlegg</div>
</div>
<div class="hstat">
<div class="hstat-value" id="total-likes">1299</div>
<div class="hstat-label">Reaksjoner</div>
</div>
<div class="hstat">
<div class="hstat-value" id="total-ext">2</div>
<div class="hstat-label">Ext. komm.</div>
</div>
</div>
</div>
</div>
</header>
<noscript>
<div style="background:#c0392b;color:#fff;padding:14px 20px;text-align:center;font-family:sans-serif;font-size:14px;position:sticky;top:0;z-index:9999;">
⚠️ <strong>JavaScript er blokkert.</strong> Åpne filen direkte i Safari — ikke via e-post/Quick Look. Del filen via AirDrop og velg «Åpne i Safari».
</div>
</noscript>
<div class="last-updated container">
<div class="pulse"></div>
<span>Sist oppdatert: <strong>Uke 8, 26. feb 2026</strong> · Neste oppdatering etter forelesning</span>
</div>
<div class="container">
<nav class="nav-tabs">
<button class="tab-btn" onclick="showTab('leaderboard', this)">🏆 Leaderboard</button>
<button class="tab-btn active" onclick="showTab('feed', this)">📋 Innlegg</button>
<button class="tab-btn" onclick="showTab('stats', this)">📊 Statistikk</button>
<button class="tab-btn" onclick="showTab('rules', this)">📖 Regler</button>
</nav>
</div>
<div class="container main">
<!-- ===== LEADERBOARD TAB ===== -->
<div id="tab-leaderboard" class="section">
<div class="leaderboard-grid">
<!-- INDIVIDUAL -->
<div class="lb-card">
<div class="lb-card-header">
<div class="lb-card-title"><span class="icon">👤</span> Individuelle</div>
<span class="lb-badge badge-green">XP-poeng</span>
</div>
<ul class="lb-list" id="individual-lb"></ul>
</div>
<!-- TEAM -->
<div class="lb-card">
<div class="lb-card-header">
<div class="lb-card-title"><span class="icon">🤝</span> Team</div>
<span class="lb-badge badge-amber">Aggregert XP</span>
</div>
<ul class="lb-list" id="team-lb"></ul>
</div>
</div>
<!-- TOP POST OF THE WEEK -->
<div class="top-post-section" id="top-post-box">
<div class="top-post-glow"></div>
<div id="top-post-content"></div>
</div>
</div>
<!-- ===== FEED TAB ===== -->
<div id="tab-feed" class="section active">
<div class="feed-controls">
<input class="feed-search" type="text" placeholder="Søk etter navn, innhold, team..." id="search-input" oninput="filterFeed()">
<button class="feed-filter active" onclick="setFilter('all', this)">Alle</button>
<button class="feed-filter" onclick="setFilter('external', this)">🌐 Ekstern</button>
<button class="feed-filter" onclick="setFilter('popular', this)">🔥 Populære (10+)</button>
</div>
<div class="posts-list" id="posts-list"></div>
</div>
<!-- ===== STATS TAB ===== -->
<div id="tab-stats" class="section">
<div class="stats-grid">
<div class="stat-card green">
<div class="stat-value" id="s-posts">52</div>
<div class="stat-label">Totale innlegg</div>
<div class="stat-sub">med #AIP2100</div>
</div>
<div class="stat-card amber">
<div class="stat-value" id="s-likes">916</div>
<div class="stat-label">Totale reaksjoner</div>
<div class="stat-sub">likes + reaksjoner</div>
</div>
<div class="stat-card blue">
<div class="stat-value" id="s-comments">84</div>
<div class="stat-label">Totale kommentarer</div>
<div class="stat-sub">inkl. interne</div>
</div>
<div class="stat-card red">
<div class="stat-value" id="s-ext">3</div>
<div class="stat-label">Eksterne kommentarer</div>
<div class="stat-sub">fra utenfor klassen</div>
</div>
<div class="stat-card blue">
<div class="stat-value" id="s-reposts">0</div>
<div class="stat-label">Totale reposts</div>
<div class="stat-sub">videredeling 🔄</div>
</div>
<div class="stat-card green">
<div class="stat-value" id="s-active">30</div>
<div class="stat-label">Aktive studenter</div>
<div class="stat-sub">har postet minst én gang</div>
</div>
<div class="stat-card amber">
<div class="stat-value" id="s-avg">17.6</div>
<div class="stat-label">Snitt reaksjoner</div>
<div class="stat-sub">per innlegg</div>
</div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:24px;">
<h3 style="font-family:'Syne',sans-serif;font-size:1rem;font-weight:700;margin-bottom:16px;">Aktivitet per uke</h3>
<div id="week-chart" style="display:flex;align-items:flex-end;gap:8px;height:120px;"></div>
<div id="week-labels" style="display:flex;gap:8px;margin-top:6px;"></div>
</div>
</div>
<!-- ===== RULES TAB ===== -->
<div id="tab-rules" class="section">
<div class="score-model">
<h3>📊 Poengmodell</h3>
<table class="score-table">
<tr><td>Publisert innlegg med #AIP2100</td><td class="pts-green">+3 XP</td></tr>
<tr><td>Innlegg med 10+ reaksjoner</td><td class="pts-green">+2 XP bonus</td></tr>
<tr><td>Kommentar fra noen utenfor kurset</td><td class="pts-green">+3 XP per stk.</td></tr>
<tr><td>Kommentar på medstudents innlegg</td><td class="pts-blue">+1 XP</td></tr>
<tr><td>Ukentlig streak (3+ uker på rad)</td><td class="pts-amber">+2 XP/uke</td></tr>
</table>
</div>
<div class="score-model" style="margin-top:16px;">
<h3>📋 Regler</h3>
<ul style="list-style:none;display:flex;flex-direction:column;gap:10px;">
<li style="font-size:0.85rem;color:var(--text-dim);padding-left:16px;position:relative;">
<span style="position:absolute;left:0;color:var(--green);">→</span>
Alle innlegg må inneholde <strong style="color:var(--text);">#AIP2100</strong> for å telle
</li>
<li style="font-size:0.85rem;color:var(--text-dim);padding-left:16px;position:relative;">
<span style="position:absolute;left:0;color:var(--green);">→</span>
Innholdet må være relatert til kurset, AI, teknologi eller innovasjon
</li>
<li style="font-size:0.85rem;color:var(--text-dim);padding-left:16px;position:relative;">
<span style="position:absolute;left:0;color:var(--green);">→</span>
Rene reposts teller ikke — du må legge til egen tekst
</li>
<li style="font-size:0.85rem;color:var(--text-dim);padding-left:16px;position:relative;">
<span style="position:absolute;left:0;color:var(--green);">→</span>
Kommentarer må være substansielle (ikke bare «Bra innlegg!»)
</li>
<li style="font-size:0.85rem;color:var(--text-dim);padding-left:16px;position:relative;">
<span style="position:absolute;left:0;color:var(--green);">→</span>
Konkurransen er frivillig og påvirker ikke karakteren
</li>
</ul>
</div>
<div class="score-model" style="margin-top:16px;">
<h3>🏅 Premiering</h3>
<div style="display:flex;flex-direction:column;gap:10px;">
<div style="font-size:0.85rem;color:var(--text-dim);">
<strong style="color:var(--amber);">Ukentlig:</strong> «Ukens innlegg» får shoutout i forelesningen + repost fra foreleser
</div>
<div style="font-size:0.85rem;color:var(--text-dim);">
<strong style="color:var(--gold);">Kursslutt:</strong> Topp 3 totalt får personlig LinkedIn-anbefaling fra foreleser
</div>
<div style="font-size:0.85rem;color:var(--text-dim);">
<strong style="color:var(--green);">Kategorivinnere:</strong> Beste kommentator, størst rekkevidde, beste enkeltinnlegg
</div>
</div>
</div>
</div>
</div>
<footer>
<div class="container">
<p>AIP2100 · LinkedIn Challenge · Høyskolen Kristiania · Vår 2026 · Oppdateres ukentlig av foreleser</p>
</div>
</footer>
<script>
// ============================================================
// DATA
// ============================================================
const STUDENTS = [
// Team 1
{ id: 'dominic-guardian', name: 'Dominic Guardian', team: 'team-1', teacher: false },
{ id: 'adele-nilssen-fossli', name: 'Adele Nilssen Fossli', team: 'team-1', teacher: false },
{ id: 'glena-armada', name: 'Glena Armada', team: 'team-1', teacher: false },
{ id: 'abdiqadir-ibrahim', name: 'Abdiqadir Ibrahim', team: 'team-1', teacher: false },
// Team 2
{ id: 'peter-sagen', name: 'Peter Sagen', team: 'team-2', teacher: false },
{ id: 'mathilde-reiersrud', name: 'Mathilde Reiersrud', team: 'team-2', teacher: false },
// Team 3
{ id: 'pia-westbye', name: 'Pia Westbye', team: 'team-3', teacher: false },
{ id: 'silje-lunde-nesdal', name: 'Silje Lunde Nesdal', team: 'team-3', teacher: false },
{ id: 'eva-valerie-lange', name: 'Eva Valerie Lange', team: 'team-3', teacher: false },
{ id: 'rody-haidar', name: 'Rody Haidar', team: 'team-3', teacher: false },
// Team 4
{ id: 'christine-stocker', name: 'Christine Stocker', team: 'team-4', teacher: false },
// Team 5
{ id: 'tone-himyr-folmo', name: 'Tone Høimyr Folmo', team: 'team-5', teacher: false },
{ id: 'annamaria-kurucz', name: 'Annamaria Kurucz', team: 'team-5', teacher: false },
{ id: 'esra-bekiri', name: 'Esra Bekiri', team: 'team-5', teacher: false },
{ id: 'madelene-typpo', name: 'Madelene Typpö', team: 'team-5', teacher: false },
// Team 7
{ id: 'marlen-bkheet', name: 'Marlen Bkheet', team: 'team-7', teacher: false },
// Team 8
{ id: 'herman-hovland', name: 'Herman Hovland', team: 'team-8', teacher: false },
{ id: 'anders-hollekim-rodak', name: 'Anders Hollekim Rodak', team: 'team-8', teacher: false },
{ id: 'markus-wold-bjerklund', name: 'Markus Wold Bjerklund', team: 'team-8', teacher: false },
{ id: 'shuayb-abdisamad-shire', name: 'Shuayb Abdisamad Shire', team: 'team-8', teacher: false },
// Team 9
{ id: 'charlotte-wollan', name: 'Charlotte Wollan', team: 'team-9', teacher: false },
// Team 10
{ id: 'synnve-seeberg-nygaard', name: 'Synnøve Seeberg Nygaard', team: 'team-10', teacher: false },
{ id: 'anne-marie-harlem-forbord', name: 'Anne Marie Harlem Forbord', team: 'team-10', teacher: false },
{ id: 'martinius-strmdal', name: 'Martinius Strømdal', team: 'team-10', teacher: false },
// Team 11
{ id: 'sakaria-sharrawe', name: 'Sakaria Sharrawe', team: 'team-11', teacher: false },
{ id: 'seda-duvarci', name: 'Seda Duvarci', team: 'team-11', teacher: false },
{ id: 'joshua-gong-ro', name: 'Joshua Gong Ro', team: 'team-11', teacher: false },
{ id: 'herman-myra-olsen', name: 'Herman Myra Olsen', team: 'team-11', teacher: false },
// Team 12
{ id: 'sindre-friberg', name: 'Sindre Friberg', team: 'team-12', teacher: false },
{ id: 'elmin-selimanovic', name: 'Elmin Selimanovic', team: 'team-12', teacher: false },
{ id: 'lisa-stefansdottir', name: 'Lisa Stefansdottir', team: 'team-12', teacher: false },
{ id: 'ludvik-foss', name: 'Ludvik Foss', team: 'team-12', teacher: false },
// Team 13
{ id: 'katrine-alderin', name: 'Katrine Alderin', team: 'team-13', teacher: false },
{ id: 'silje-karsrud', name: 'Silje Karsrud', team: 'team-13', teacher: false },
{ id: 'ida-marie-smedberg', name: 'Ida Marie Smedberg', team: 'team-13', teacher: false },
{ id: 'maria-michelle-foyn-boe', name: 'Maria Michelle Foyn Bøe', team: 'team-13', teacher: false },
// Team 14
{ id: 'erik-andre-skauen-nilsen', name: 'Erik-André Skauen Nilsen', team: 'team-14', teacher: false },
{ id: 'mina-nygard', name: 'Mina Nygård', team: 'team-14', teacher: false },
{ id: 'aryaan-yassin', name: 'Aryaan Yassin', team: 'team-14', teacher: false },
{ id: 'muhammad-husnain', name: 'Muhammad Husnain', team: 'team-14', teacher: false },
// Team 15 – ENCOM (Kapitalforvaltning)
{ id: 'steven-wong', name: 'Steven Wong', team: 'team-15', teacher: false },
{ id: 'carlos-martinez-devora', name: 'Carlos Martínez Dévora', team: 'team-15', teacher: false },
{ id: 'julia-elisabeth-kraemer', name: 'Julia Elisabeth Kraemer', team: 'team-15', teacher: false },
{ id: 'anna-rojewska', name: 'Anna Rojewska', team: 'team-15', teacher: false },
// Team 16 – Læreryrket
{ id: 'olav-berge', name: 'Olav Berge', team: 'team-16', teacher: false },
{ id: 'bendik-naess', name: 'Bendik Næss', team: 'team-16', teacher: false },
{ id: 'jesper-swensson', name: 'Jesper Swensson', team: 'team-16', teacher: false },
{ id: 'anders-fjuk', name: 'Anders Fjuk', team: 'team-16', teacher: false },
// Team 17
{ id: 'madeleine-holm', name: 'Madeleine Holm', team: 'team-17', teacher: false },
{ id: 'emilie-nielsen', name: 'Emilie Nielsen', team: 'team-17', teacher: false },
{ id: 'tina-saliim', name: 'Tina Saliim', team: 'team-17', teacher: false },
// Team 18
{ id: 'filip-jakub-smolen', name: 'Filip Jakub Smolen', team: 'team-18', teacher: false },
{ id: 'andre-hias', name: 'Andre Høiås', team: 'team-18', teacher: false },
{ id: 'carl-fernandez-hoff', name: 'Carl Fernandez Hoff', team: 'team-18', teacher: false },
{ id: 'carl-ludvig-ova-behrendt', name: 'Carl Ludvig Ova Behrendt', team: 'team-18', teacher: false },
{ id: 'ole-thomas-lunde', name: 'Ole Thomas Lunde', team: 'team-18', teacher: false },
// Team 20
{ id: 'william-stvik', name: 'William Østvik', team: 'team-20', teacher: false },
{ id: 'lava-issa-hamid', name: 'Lava Issa Hamid', team: 'team-20', teacher: false },
{ id: 'kenny-feng', name: 'Kenny Feng', team: 'team-20', teacher: false },
{ id: 'jesper-norstad', name: 'Jesper Norstad', team: 'team-20', teacher: false },
{ id: 'adrian-sylte', name: 'Adrian Sylte', team: 'team-20', teacher: false },
// Team 21
{ id: 'kris-sharma', name: 'Kris Sharma', team: 'team-21', teacher: false },
{ id: 'mahnoor-baig', name: 'Mahnoor Baig', team: 'team-21', teacher: false },
{ id: 'aron-k-stgard', name: 'Aron K. Østgård', team: 'team-21', teacher: false },
{ id: 'herman-hol', name: 'Herman Holø', team: 'team-21', teacher: false },
{ id: 'thor-winther', name: 'Thor Winther', team: 'team-21', teacher: false },
{ id: 'pascal-wilondja', name: 'Pascal Wilondja', team: 'team-21', teacher: false },
// Team 22
{ id: 'inga-sundheim', name: 'Inga Sundheim', team: 'team-22', teacher: false },
{ id: 'aryo-hosseinian', name: 'Aryo Hosseinian', team: 'team-22', teacher: false },
{ id: 'sofie-martina-evensen', name: 'Sofie Martina Evensen', team: 'team-22', teacher: false },
// Team 23
{ id: 'sander-petersen-linas', name: 'Sander Petersen Linås', team: 'team-23', teacher: false },
{ id: 'maren-gullikstad', name: 'Maren Gullikstad', team: 'team-23', teacher: false },
{ id: 'ola-troan', name: 'Ola Troan', team: 'team-23', teacher: false },
{ id: 'frya-vereide', name: 'Frøya Vereide', team: 'team-23', teacher: false },
{ id: 'eirik-holter', name: 'Eirik Holter', team: 'team-23', teacher: false },
// Team 24
{ id: 'emma-tran', name: 'Emma Trøan', team: 'team-24', teacher: false },
{ id: 'william-bjrnstad', name: 'William Bjørnstad', team: 'team-24', teacher: false },
// Team 27
{ id: 'stella-echem', name: 'Stella Echem', team: 'team-27', teacher: false },
{ id: 'zing-hlei', name: 'Zing Hlei', team: 'team-27', teacher: false },
{ id: 'eman-mubarak', name: 'Eman Mubarak', team: 'team-27', teacher: false },
{ id: 'yad-faraj', name: 'Yad Faraj', team: 'team-27', teacher: false },
// Ukjent team / løse studenter
{ id: 'trine-johansen-meza', name: 'Trine Johansen Meza', team: 'team-0', teacher: false },
{ id: 'andreas-carlsen', name: 'Andreas Carlsen', team: 'team-0', teacher: true },
{ id: 'sarim-nasar', name: 'Sarim Nasar', team: 'team-0', teacher: false },
// Forelesere / gjesteforelesere
{ id: 'karl-philip-lund', name: 'Karl Philip Lund', team: 'team-0', teacher: true },
{ id: 'hans-petter-nygard-hansen', name: 'Hans-Petter Nygård-Hansen', team: 'team-0', teacher: true },
{ id: 'aleksander-stensby', name: 'Aleksander Stensby', team: 'team-0', teacher: true },
{ id: 'magne-ilsaas', name: 'Magne Ilsaas', team: 'team-0', teacher: true },
];
const POSTS = [
// ---- W03 ----
{ id: 'p-kpl-1', url: 'https://www.linkedin.com/posts/philiplund_aip2100-activity-7414663178393030656-wywd', date: '2026-01-18', week: '2026-W03', studentId: 'karl-philip-lund', likes: 18, comments: 1, reposts: 0, extComments: 0, text: 'Oppstart av AI i praksis: innovasjon, teknologi og strategi' },
{ id: 'p-kpl-2', url: 'https://www.linkedin.com/posts/philiplund_aip2100-haeoyskolenkristiania-aip2100-activity-7420016395423232000-VwUh', date: '2026-01-18', week: '2026-W03', studentId: 'karl-philip-lund', likes: 22, comments: 3, reposts: 0, extComments: 0, text: 'AIP2100 – uke 1 oppsummering' },
{ id: 'p-kpl-3', url: 'https://www.linkedin.com/posts/philiplund_aip2100-haeoyskolenkristiania-aip2100-activity-7420101301495197696-dibY', date: '2026-01-18', week: '2026-W03', studentId: 'karl-philip-lund', likes: 8, comments: 2, reposts: 0, extComments: 0, text: 'AIP2100 – studenter i gang' },
{ id: 'p-kpl-ai', url: 'https://www.linkedin.com/posts/philiplund_ai-utdanning-innovasjon-activity-7389605293317423104-Yzoo', date: '2026-01-18', week: '2026-W03', studentId: 'karl-philip-lund', likes: 48, comments: 16, reposts: 1, extComments: 0, text: 'AI, utdanning og innovasjon' },
{ id: 'p-kpl-pen', url: 'https://www.linkedin.com/posts/philiplund_hvordan-kan-ai-gjøre-pensumlitteratur-mer-activity-7407033256539217920-9NRI', date: '2026-01-18', week: '2026-W03', studentId: 'karl-philip-lund', likes: 40, comments: 7, reposts: 0, extComments: 0, text: 'Hvordan kan AI gjøre pensumlitteratur mer tilgjengelig?' },
{ id: 'p-andreas-1', url: 'https://www.linkedin.com/posts/andreas-carlsen-6b9827220_aip2100-activity-7414673897008156672-TNfz', date: '2026-01-18', week: '2026-W03', studentId: 'andreas-carlsen', likes: 13, comments: 0, reposts: 0, extComments: 0, text: 'Oppstart av AIP2100 på Kristiania' },
{ id: 'p-emilie-1', url: 'https://www.linkedin.com/posts/emilie-nordby-b947a939b_aip2100-activity-7414609292072361985-Wo6i', date: '2026-01-18', week: '2026-W03', studentId: 'emilie-nielsen', likes: 32, comments: 1, reposts: 0, extComments: 0, text: 'Inspirerende start på faget AI' },
{ id: 'p-marlen-1', url: 'https://www.linkedin.com/posts/marlen-bkheet-b43079325_ai-psykologi-helseteknologi-activity-7417170506329677824-Tilk', date: '2026-01-18', week: '2026-W03', studentId: 'marlen-bkheet', likes: 24, comments: 1, reposts: 0, extComments: 0, text: 'AI møter medisinsk psykologi' },
{ id: 'p-marlen-2', url: 'https://www.linkedin.com/posts/marlen-bkheet-b43079325_aip2100-aip2100-activity-7414665633025470464-esM8', date: '2026-01-18', week: '2026-W03', studentId: 'marlen-bkheet', likes: 23, comments: 1, reposts: 0, extComments: 0, text: 'Inspirerende forelesning i faget AIP2100' },
// ---- W04 ----
{ id: 'p-lisa-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7422758990079770625', date: '2026-02-03', week: '2026-W06', studentId: 'lisa-stefansdottir', likes: 5, comments: 1, reposts: 0, extComments: 0, text: 'Kunstig intelligens i arkitekturanalyse' },
{ id: 'p-andreas-2', url: 'https://www.linkedin.com/posts/andreas-carlsen-6b9827220_aip2100-activity-7421877818499690497-C-ax', date: '2026-01-22', week: '2026-W04', studentId: 'andreas-carlsen', likes: 8, comments: 2, reposts: 0, extComments: 0, text: 'Takk for bra start på semesteret!' },
// ---- W05 ----
{ id: 'p-charlotte-1', url: 'https://www.linkedin.com/posts/activity-7419089910281707521-wl_T', date: '2026-01-27', week: '2026-W05', studentId: 'charlotte-wollan', likes: 6, comments: 0, reposts: 0, extComments: 0, text: 'AI i praksis - OKR-metoden' },
{ id: 'p-charlotte-2', url: 'https://www.linkedin.com/posts/charlotte-w-285a70259_ai-hotellbransjen-okr-activity-7420079438186422273-U-Ej', date: '2026-01-27', week: '2026-W05', studentId: 'charlotte-wollan', likes: 22, comments: 3, reposts: 1, extComments: 0, text: 'AI i hotellbransjen – OKR' },
{ id: 'p-charlotte-3', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7414679572488695809', date: '2026-01-27', week: '2026-W05', studentId: 'charlotte-wollan', likes: 8, comments: 2, reposts: 0, extComments: 0, text: 'OKR-presentasjon fra praksis' },
{ id: 'p-anne-1', url: 'https://www.linkedin.com/posts/activity-7424787028350947328-v2Mf', date: '2026-01-27', week: '2026-W05', studentId: 'anne-marie-harlem-forbord', likes: 22, comments: 3, reposts: 0, extComments: 0, text: 'AI i HR i praksis' },
{ id: 'p-anne-2', url: 'https://www.linkedin.com/posts/anne-marie-harlem-forbord-340009115_aip2100-haeoyskolenkristiania-aiihr-activity-7418571458378928128-T4ay', date: '2026-01-27', week: '2026-W05', studentId: 'anne-marie-harlem-forbord', likes: 18, comments: 1, reposts: 0, extComments: 0, text: 'Inspirerende fremlegg av June Steensen' },
{ id: 'p-tone-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7417170506329677824', date: '2026-01-27', week: '2026-W05', studentId: 'tone-himyr-folmo', likes: 18, comments: 0, reposts: 0, extComments: 0, text: 'Spennende prosjekt i AIP2100!' },
{ id: 'p-annamaria-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7419718942874828800', date: '2026-01-27', week: '2026-W05', studentId: 'annamaria-kurucz', likes: 18, comments: 0, reposts: 0, extComments: 0, text: 'Prosjektoppstart i AIP2100' },
{ id: 'p-mina-1', url: 'https://www.linkedin.com/posts/mina-nygård-10a83a37b_ai-markedsfaeoring-pr-activity-7419033552521977856-_FAv', date: '2026-01-27', week: '2026-W05', studentId: 'mina-nygard', likes: 15, comments: 2, reposts: 0, extComments: 0, text: 'AI møter markedsføring og PR' },
{ id: 'p-seda-1', url: 'https://www.linkedin.com/posts/sakaria-sharrawe-9bb90228b_eiendomsmegling-kunstigintelligens-ai-activity-7420059534934679552-UeZ8', date: '2026-01-27', week: '2026-W05', studentId: 'seda-duvarci', likes: 20, comments: 2, reposts: 0, extComments: 0, text: 'Prosjektstart i AIP2100 – AI møter eiendomsmegling' },
{ id: 'p-christine-1', url: 'https://www.linkedin.com/posts/christine-stocker-250209186_aip2100-haeoyskolenkristiania-ai-activity-7419718942874828800-4DYF', date: '2026-01-27', week: '2026-W05', studentId: 'christine-stocker', likes: 29, comments: 10, reposts: 0, extComments: 0, text: 'Første LinkedIn-innlegg fra oss' },
{ id: 'p-kpl-4', url: 'https://www.linkedin.com/posts/philiplund_aip2100-aiipraksis-kunstigintelligens-activity-7421474875606831105-mYOA', date: '2026-01-27', week: '2026-W05', studentId: 'karl-philip-lund', likes: 42, comments: 1, reposts: 8, extComments: 0, text: 'AIP2100 – AI i praksis og kunstig intelligens' },
{ id: 'p-kpl-5', url: 'https://www.linkedin.com/posts/philiplund_dårlige-prompter-gir-dårlige-ki-svar-det-activity-7421842746405158912-Dy27', date: '2026-01-27', week: '2026-W05', studentId: 'karl-philip-lund', likes: 6, comments: 0, reposts: 0, extComments: 0, text: 'Dårlige prompter gir dårlige KI-svar' },
// ---- W06 ----
{ id: 'p-emma-1', url: 'https://www.linkedin.com/posts/emmaquilletroan_haeoyskolenkristiania-aip2100-activity-7422632573362909185-SivG', date: '2026-02-03', week: '2026-W06', studentId: 'emma-tran', likes: 32, comments: 9, reposts: 0, extComments: 0, text: 'Mitt første offisielle innlegg på LinkedIn' },
{ id: 'p-william-1', url: 'https://www.linkedin.com/posts/william-bjørnstad-a14202345_haeoyskolenkristiania-aip2100-activity-7423635128339554304-d8fE', date: '2026-02-03', week: '2026-W06', studentId: 'william-bjrnstad', likes: 33, comments: 3, reposts: 0, extComments: 0, text: 'Mitt første innlegg – Marketing' },
{ id: 'p-eva-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7422362901421748224', date: '2026-02-03', week: '2026-W06', studentId: 'eva-valerie-lange', likes: 20, comments: 1, reposts: 0, extComments: 0, text: 'Prosjekt i faget AI i praksis' },
{ id: 'p-rody-1', url: 'https://www.linkedin.com/posts/rody-haidar-148083152_aip2100-haeoyskolenkristiania-activity-7422349727507251200-Q7pL', date: '2026-02-03', week: '2026-W06', studentId: 'rody-haidar', likes: 29, comments: 3, reposts: 0, extComments: 0, text: 'Gjesteforelesning i AIP2100 KI i praksis' },
{ id: 'p-rody-2', url: 'https://www.linkedin.com/posts/rody-haidar-148083152_aip2100-haeoyskolenkristiania-aip2100-activity-7423228541586178048-cKmH', date: '2026-02-03', week: '2026-W06', studentId: 'rody-haidar', likes: 5, comments: 0, reposts: 0, extComments: 0, text: 'AI i AIP2100 – uke 2' },
{ id: 'p-pia-1', url: 'https://www.linkedin.com/posts/pia-westbye-70aa42345_aip2100-aip2100-activity-7424146495886741506-xbfZ', date: '2026-02-03', week: '2026-W06', studentId: 'pia-westbye', likes: 18, comments: 0, reposts: 0, extComments: 0, text: 'Prosjekt ved Kristiania University' },
{ id: 'p-silje-1', url: 'https://www.linkedin.com/posts/silje-lunde-nesdal-64135b307_chatgpt-aip2100-haeoyskolenkristiania-activity-7421978218934472705-FDwG', date: '2026-02-03', week: '2026-W06', studentId: 'silje-lunde-nesdal', likes: 14, comments: 0, reposts: 0, extComments: 0, text: 'ChatGPT og AIP2100' },
{ id: 'p-sindre-1', url: 'https://www.linkedin.com/posts/sindre-bjerknes-friberg-a1b488299_prfaq-activity-7422657163954921472-udLj', date: '2026-02-03', week: '2026-W06', studentId: 'sindre-friberg', likes: 18, comments: 0, reposts: 0, extComments: 0, text: 'PR/FAQ – Godt i gang med prosjektet' },
{ id: 'p-erik-1', url: 'https://www.linkedin.com/posts/erik-andré-skauen-nilsen-83567b2aa_aip2100-aip2100-ai-activity-7422164073368276992-V__D', date: '2026-02-03', week: '2026-W06', studentId: 'erik-andre-skauen-nilsen', likes: 35, comments: 4, reposts: 0, extComments: 1, text: 'Lager prompt-app for å hjelpe folk med KI' },
{ id: 'p-martinius-1', url: 'https://www.linkedin.com/posts/martinius-strømdal-b2322a390_hans-petter-nygård-hansen-forbrukerrådet-activity-7422240726706696192-WJdG', date: '2026-02-03', week: '2026-W06', studentId: 'martinius-strmdal', likes: 11, comments: 1, reposts: 0, extComments: 0, text: 'Hans-Petter Nygård-Hansen om forbrukerrådet' },
{ id: 'p-synnove-1', url: 'https://www.linkedin.com/posts/synnøve-seeberg-nygaard-a01343116_aip2100-activity-7422331439448338433-1Wbv', date: '2026-02-03', week: '2026-W06', studentId: 'synnve-seeberg-nygaard', likes: 34, comments: 4, reposts: 0, extComments: 0, text: 'Forelesning med Hans-Petter Nygård-Hansen' },
{ id: 'p-sakaria-1', url: 'https://www.linkedin.com/posts/sakaria-sharrawe-9bb90228b_aip2100-digitalisering-ai-activity-7426971751324102657-wan3', date: '2026-02-03', week: '2026-W06', studentId: 'sakaria-sharrawe', likes: 0, comments: 0, reposts: 0, extComments: 0, text: 'AI møter markedsføring og PR' },
{ id: 'p-sarim-1', url: 'https://www.linkedin.com/posts/sarim-nasar-646b86395_aip2100-aip2100-ai-activity-7424808986622812160-73aj', date: '2026-02-03', week: '2026-W06', studentId: 'sarim-nasar', likes: 24, comments: 1, reposts: 0, extComments: 0, text: 'AI i organisasjoner' },
{ id: 'p-carlos-1', url: 'https://www.linkedin.com/posts/carlos-martinez-dévora-03a550b7_er-vi-for-eller-imot-teknologi-eller-bare-activity-7422228724172988417-0UU7', date: '2026-02-03', week: '2026-W06', studentId: 'carlos-martinez-devora', likes: 15, comments: 0, reposts: 0, extComments: 0, text: 'Er vi for eller imot teknologi – eller bare redde?' },
{ id: 'p-madeleine-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7421978218934472705', date: '2026-02-03', week: '2026-W06', studentId: 'madeleine-holm', likes: 7, comments: 0, reposts: 0, extComments: 0, text: 'AI møter hjemmesykepleien' },
{ id: 'p-hpnh-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7422956709939245056', date: '2026-02-03', week: '2026-W06', studentId: 'hans-petter-nygard-hansen', likes: 32, comments: 1, reposts: 0, extComments: 0, text: 'AI er ikke fremtiden – valgene vi tar er' },
// ---- W07 ----
{ id: 'p-madelene-1', url: 'https://www.linkedin.com/posts/activity-7427318935089283072--EeV', date: '2026-02-13', week: '2026-W07', studentId: 'madelene-typpo', likes: 16, comments: 1, reposts: 0, extComments: 0, text: 'To inspirerende gjesteforelesere i AIP2100' },
{ id: 'p-adele-1', url: 'https://www.linkedin.com/posts/adele-nilsen-fossli_aip2100-advokater-advokatbransjen-activity-7424780311416283136-WTTJ', date: '2026-02-10', week: '2026-W07', studentId: 'adele-nilssen-fossli', likes: 22, comments: 5, reposts: 0, extComments: 0, text: 'AI i advokatbransjen – AIP2100' },
{ id: 'p-tone-2', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7424808986622812160', date: '2026-02-10', week: '2026-W07', studentId: 'tone-himyr-folmo', likes: 34, comments: 1, reposts: 0, extComments: 0, text: 'Når AI går fra verktøy til arbeidsmåte' },
{ id: 'p-martinius-2', url: 'https://www.linkedin.com/posts/martinius-strømdal-b2322a390_digitale-løsninger-for-mennesker-og-samfunn-activity-7427306592494272512-KSWA', date: '2026-02-13', week: '2026-W07', studentId: 'martinius-strmdal', likes: 13, comments: 1, reposts: 0, extComments: 0, text: 'Digitale løsninger for mennesker og samfunn' },
{ id: 'p-anne-3', url: 'https://www.linkedin.com/posts/anne-marie-harlem-forbord-340009115_aip2100-activity-7427317803206225920-HNrD', date: '2026-02-13', week: '2026-W07', studentId: 'anne-marie-harlem-forbord', likes: 20, comments: 3, reposts: 0, extComments: 0, text: 'Forelesning med Magne Ilsaas' },
{ id: 'p-pia-2', url: 'https://www.linkedin.com/posts/pia-westbye-70aa42345_aip2100-activity-7427336679826288640-nJlC', date: '2026-02-13', week: '2026-W07', studentId: 'pia-westbye', likes: 18, comments: 0, reposts: 0, extComments: 0, text: 'Besøk av Hans-Petter Nygård-Hansen' },
{ id: 'p-pia-3', url: 'https://www.linkedin.com/posts/pia-westbye-70aa42345_aip2100-activity-7427350491828879360-K7ze', date: '2026-02-13', week: '2026-W07', studentId: 'pia-westbye', likes: 12, comments: 0, reposts: 0, extComments: 0, text: 'Er du skeptisk til ekte bruk av AI?' },
{ id: 'p-pia-4', url: 'https://www.linkedin.com/posts/pia-westbye-70aa42345_aip2100-activity-7427365642963689474-fjRB', date: '2026-02-13', week: '2026-W07', studentId: 'pia-westbye', likes: 7, comments: 0, reposts: 0, extComments: 0, text: 'AI i AIP2100 – uke 6' },
{ id: 'p-synnove-2', url: 'https://www.linkedin.com/posts/synnøve-seeberg-nygaard-a01343116_aip2100-hrnorge-aiihr-activity-7425479895209627648-TTm6', date: '2026-02-10', week: '2026-W07', studentId: 'synnve-seeberg-nygaard', likes: 20, comments: 7, reposts: 0, extComments: 0, text: 'Spennende prosjekt i kurset AI i praksis' },
{ id: 'p-synnove-3', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7424874545045753856', date: '2026-02-10', week: '2026-W07', studentId: 'synnve-seeberg-nygaard', likes: 18, comments: 2, reposts: 0, extComments: 0, text: 'Inspirerende og justerende forelesningsdag' },
{ id: 'p-peter-1', url: 'https://www.linkedin.com/posts/peter-sagen-280419292_aiipraksis-aip2100-digitalhelse-activity-7424089438172925952-fGHf', date: '2026-02-10', week: '2026-W07', studentId: 'peter-sagen', likes: 21, comments: 1, reposts: 0, extComments: 0, text: 'AI i digitale helsetjenester – risiko?' },
{ id: 'p-mathilde-1', url: 'https://www.linkedin.com/posts/mathilde-reiersrud-4253a0269_aip2100-aiipraksis-digitalhelse-activity-7424914508646862848-AYNt', date: '2026-02-10', week: '2026-W07', studentId: 'mathilde-reiersrud', likes: 33, comments: 3, reposts: 0, extComments: 0, text: 'AI som hjelpemiddel i digitale helsetjenester' },
{ id: 'p-julia-1', url: 'https://www.linkedin.com/posts/julia-elisabeth-kraemer_aip2100-ai-ki-activity-7425497023161712640-w3Z6', date: '2026-02-10', week: '2026-W07', studentId: 'julia-elisabeth-kraemer', likes: 37, comments: 5, reposts: 0, extComments: 0, text: 'AI i kapitalforvaltning – nytt prosjekt' },
{ id: 'p-christine-2', url: 'https://www.linkedin.com/posts/christine-stocker-250209186_aip2100-ai-offentligsektor-activity-7427672054490935297-h_qp', date: '2026-02-14', week: '2026-W07', studentId: 'christine-stocker', likes: 10, comments: 0, reposts: 0, extComments: 0, text: 'Spørsmål til saksbehandlere i offentlig sektor' },
{ id: 'p-sakaria-2', url: 'https://www.linkedin.com/posts/sakaria-sharrawe-9bb90228b_aip2100-digitalisering-ai-activity-7426971751324102657-wan3', date: '2026-02-13', week: '2026-W07', studentId: 'sakaria-sharrawe', likes: 54, comments: 4, reposts: 0, extComments: 0, text: 'Intervju med Fredrick Hyggen Frilseth' },
{ id: 'p-carlos-2', url: 'https://www.linkedin.com/posts/carlos-martinez-dévora-03a550b7_aip2100-ai-ki-activity-7425512501431181312-k8Yj', date: '2026-02-10', week: '2026-W07', studentId: 'carlos-martinez-devora', likes: 0, comments: 0, reposts: 0, extComments: 0, text: 'AIP2100 – AI og KI i praksis' },
{ id: 'p-aleksander-1', url: 'https://www.linkedin.com/feed/update/urn:li:activity:7425566857031745536', date: '2026-02-10', week: '2026-W07', studentId: 'aleksander-stensby', likes: 56, comments: 5, reposts: 0, extComments: 0, text: 'Undervisning som gjestelektor om AI på Høyskolen Kristiania' },
{ id: 'p-kpl-6', url: 'https://www.linkedin.com/posts/philiplund_aip2100-aip2100-ai-activity-7428494867451977728-0GX1', date: '2026-02-13', week: '2026-W07', studentId: 'karl-philip-lund', likes: 75, comments: 9, reposts: 6, extComments: 0, text: 'AIP2100 – uke 6 oppsummering' },
// ---- W08 ----
{ id: 'p-martinius-3', url: 'https://www.linkedin.com/posts/martinius-strømdal-b2322a390_når-kunstig-intelligens-frigjør-tid-til-mennesker-activity-7429831502571433984-1eNU', date: '2026-02-17', week: '2026-W08', studentId: 'martinius-strmdal', likes: 4, comments: 0, reposts: 0, extComments: 0, text: 'Når kunstig intelligens frigjør tid til mennesker' },
{ id: 'p-synnove-4', url: 'https://www.linkedin.com/posts/synnøve-seeberg-nygaard-a01343116_den-største-risikoen-fremover-er-ikke-at-activity-7429911764672311296-waq8', date: '2026-02-17', week: '2026-W08', studentId: 'synnve-seeberg-nygaard', likes: 18, comments: 3, reposts: 0, extComments: 0, text: 'Den største risikoen fremover er ikke at...' },
{ id: 'p-erik-2', url: 'https://www.linkedin.com/posts/erik-andré-skauen-nilsen-83567b2aa_loftet-en-inkubator-for-studentgründere-activity-7429785496312131584-IaqS', date: '2026-02-17', week: '2026-W08', studentId: 'erik-andre-skauen-nilsen', likes: 19, comments: 8, reposts: 0, extComments: 1, text: 'Loftet – en inkubator for studentgründere' },
];
// ============================================================
// COMPUTE XP
// ============================================================
function computeStudentXP(studentId) {
const posts = POSTS.filter(p => p.studentId === studentId);
let xp = 0;
const weeks = new Set();
posts.forEach(p => {
xp += 3; // base per post
if (p.likes >= 10) xp += 2;
xp += (p.reposts || 0) * 2; // reposts: 2 XP each
xp += p.extComments * 3;
weeks.add(p.week);
});
// Streak bonus: if active 3+ consecutive weeks
const weekNums = [...weeks].map(w => parseInt(w.split('W')[1])).sort((a,b)=>a-b);
let streak = 0, maxStreak = 0, cur = 0;
for (let i = 0; i < weekNums.length; i++) {
if (i === 0 || weekNums[i] === weekNums[i-1] + 1) { cur++; }
else { cur = 1; }
maxStreak = Math.max(maxStreak, cur);
}
if (maxStreak >= 3) xp += (maxStreak - 2) * 2;
return { xp, posts: posts.length, weeks: weeks.size };
}
function getStudentById(id) {
return STUDENTS.find(s => s.id === id);
}
const TEAM_NAMES = {
'team-0': 'Foreleser/Gjest',
'team-1': 'Team 1',
'team-2': 'Team 2',
'team-3': 'Team 3',
'team-4': 'Team 4',
'team-5': 'Team 5',
'team-7': 'Team 7',
'team-8': 'Team 8',
'team-9': 'Team 9',
'team-10': 'Team 10',
'team-11': 'Team 11',
'team-12': 'Team 12',
'team-13': 'Team 13 – Smart Hospitality',
'team-14': 'Team 14',
'team-15': 'Team 15 – ENCOM',
'team-16': 'Team 16 – Læreryrket',
'team-17': 'Team 17',
'team-18': 'Team 18',
'team-20': 'Team 20',
'team-21': 'Team 21',
'team-22': 'Team 22',
'team-23': 'Team 23',
'team-24': 'Team 24',
'team-27': 'Team 27',
};
function getTeamLabel(teamId) {
return TEAM_NAMES[teamId] || teamId.replace('team-', 'Team ');
}
function initials(name) {
return name.split(' ').slice(0,2).map(n=>n[0]).join('').toUpperCase();
}
// ============================================================
// BUILD LEADERBOARDS
// ============================================================
function buildLeaderboards() {
// Individual
const scores = STUDENTS.map(s => {
const { xp, posts, weeks } = computeStudentXP(s.id);
return { ...s, xp, posts, weeks };
}).filter(s => s.xp > 0).sort((a,b) => b.xp - a.xp);
const maxXP = (scores[0] ? scores[0].xp : 0) || 1;
const indEl = document.getElementById('individual-lb');
scores.slice(0, 10).forEach((s, i) => {
const rankClass = i === 0 ? 'rank-1' : i === 1 ? 'rank-2' : i === 2 ? 'rank-3' : 'rank-other';
const rankIcon = i === 0 ? '🥇' : i === 1 ? '🥈' : i === 2 ? '🥉' : `${i+1}`;
const li = document.createElement('li');
li.className = 'lb-item';
li.innerHTML = `
<span class="lb-rank ${rankClass}">${rankIcon}</span>
<div class="lb-avatar">${initials(s.name)}</div>
<div class="lb-info">
<div class="lb-name">${s.name}${s.teacher ? ' <span class="teacher-badge">FORELESER</span>' : ''}</div>
<div class="lb-meta">
<span>${getTeamLabel(s.team)}</span>
<span>·</span>
<span>${s.posts} innlegg</span>
<span>·</span>
<span>${s.weeks} uker</span>
</div>
<div class="xp-bar-wrap">
<div class="xp-bar" style="width:${(s.xp/maxXP*100).toFixed(1)}%"></div>
</div>
</div>
<div class="lb-score">
<div class="lb-xp">${s.xp}</div>
<div class="lb-xp-label">XP</div>
</div>
`;
indEl.appendChild(li);
});
// Team
const teamMap = {};
STUDENTS.forEach(s => {
const tid = s.team;
if (!teamMap[tid]) teamMap[tid] = { teamId: tid, xp: 0, members: 0, posts: 0 };
const { xp, posts } = computeStudentXP(s.id);
teamMap[tid].xp += xp;
teamMap[tid].posts += posts;
if (xp > 0) teamMap[tid].members++;
});
const teams = Object.values(teamMap).filter(t => t.xp > 0).sort((a,b) => b.xp - a.xp);
const maxTeamXP = (teams[0] ? teams[0].xp : 0) || 1;
const teamEl = document.getElementById('team-lb');
teams.slice(0, 10).forEach((t, i) => {
const rankClass = i === 0 ? 'rank-1' : i === 1 ? 'rank-2' : i === 2 ? 'rank-3' : 'rank-other';
const rankIcon = i === 0 ? '🥇' : i === 1 ? '🥈' : i === 2 ? '🥉' : `${i+1}`;
const li = document.createElement('li');
li.className = 'lb-item';
const label = getTeamLabel(t.teamId);
li.innerHTML = `
<span class="lb-rank ${rankClass}">${rankIcon}</span>
<div class="lb-avatar" style="font-size:0.7rem">${t.teamId === 'team-0' ? '🎓' : t.teamId.replace('team-','T')}</div>
<div class="lb-info">
<div class="lb-name">${label}${t.teamId === 'team-0' ? ' <span class="teacher-badge">FORELESERE</span>' : ''}</div>
<div class="lb-meta">
<span>${t.members} aktive</span>
<span>·</span>
<span>${t.posts} innlegg</span>
</div>
<div class="xp-bar-wrap">
<div class="xp-bar" style="width:${(t.xp/maxTeamXP*100).toFixed(1)}%"></div>
</div>
</div>
<div class="lb-score">
<div class="lb-xp">${t.xp}</div>
<div class="lb-xp-label">XP</div>
</div>
`;
teamEl.appendChild(li);
});
// Top post of the week — filter to latest week in POSTS, then pick highest score
const latestWeek = POSTS.reduce((max, p) => p.week > max ? p.week : max, '');
const thisWeekPosts = POSTS.filter(p => p.week === latestWeek);
const sortedByLikes = [...thisWeekPosts].sort((a,b) => (b.likes + b.comments*2 + (b.reposts||0)*2 + b.extComments*3) - (a.likes + a.comments*2 + (a.reposts||0)*2 + a.extComments*3));
const top = sortedByLikes[0];
const topStudent = getStudentById(top.studentId);
document.getElementById('top-post-content').innerHTML = `
<div style="display:flex;align-items:start;gap:16px;flex-wrap:wrap">
<div style="flex:1;min-width:200px">
<div style="font-family:'Syne',sans-serif;font-size:1rem;font-weight:700;margin-bottom:4px;">${top.text}</div>
<div style="font-size:0.82rem;color:var(--text-dim);margin-bottom:12px;">
${(topStudent ? topStudent.name : null) || top.studentId} · ${getTeamLabel((topStudent ? topStudent.team : null) || 'team-0')} · ${top.date}
</div>
<a href="${top.url}" target="_blank" style="font-family:'DM Mono',monospace;font-size:0.72rem;color:var(--green);text-decoration:none;letter-spacing:0.06em;border:1px solid rgba(0,229,160,0.3);padding:6px 14px;border-radius:4px;">
SE INNLEGG →
</a>
</div>
<div style="display:flex;gap:20px;align-items:center">
<div style="text-align:center"><div style="font-family:'Syne',sans-serif;font-size:1.5rem;font-weight:800;color:var(--amber)">${top.likes}</div><div style="font-family:'DM Mono',monospace;font-size:0.6rem;color:var(--text-faint);text-transform:uppercase;letter-spacing:0.08em">Reaksjoner</div></div>
<div style="text-align:center"><div style="font-family:'Syne',sans-serif;font-size:1.5rem;font-weight:800;color:var(--blue)">${top.comments}</div><div style="font-family:'DM Mono',monospace;font-size:0.6rem;color:var(--text-faint);text-transform:uppercase;letter-spacing:0.08em">Komm.</div></div>
${top.extComments > 0 ? `<div style="text-align:center"><div style="font-family:'Syne',sans-serif;font-size:1.5rem;font-weight:800;color:var(--green)">${top.extComments}</div><div style="font-family:'DM Mono',monospace;font-size:0.6rem;color:var(--text-faint);text-transform:uppercase;letter-spacing:0.08em">Ext. komm.</div></div>` : ''}
</div>
</div>
`;
}
// ============================================================
// BUILD FEED
// ============================================================
let currentFilter = 'all';
function setFilter(f, el) {
currentFilter = f;
document.querySelectorAll('.feed-filter').forEach(function(b) { b.classList.remove('active'); });
el.classList.add('active');
renderFeed();
}
function filterFeed() { renderFeed(); }
function renderFeed() {
const search = document.getElementById('search-input').value.toLowerCase();
const sorted = [...POSTS].sort((a,b) => new Date(b.date) - new Date(a.date));
let filtered = sorted.filter(p => {
const student = getStudentById(p.studentId);
const name = ((student ? student.name : null) || p.studentId).toLowerCase();
const team = getTeamLabel((student ? student.team : null) || '').toLowerCase();
const matchSearch = !search || name.includes(search) || p.text.toLowerCase().includes(search) || team.includes(search);
const matchFilter =
currentFilter === 'all' ||
(currentFilter === 'external' && p.extComments > 0) ||
(currentFilter === 'popular' && p.likes >= 10);
return matchSearch && matchFilter;
});
const container = document.getElementById('posts-list');
container.innerHTML = '';
let lastWeek = null;
filtered.forEach(p => {
const student = getStudentById(p.studentId);
const weekLabel = p.week.replace('2026-', '');
if (weekLabel !== lastWeek) {
const div = document.createElement('div');
div.className = 'week-divider';
div.innerHTML = `<span class="week-divider-label">${weekLabel}</span><div class="week-divider-line"></div>`;
container.appendChild(div);
lastWeek = weekLabel;
}
const card = document.createElement('a');
card.href = p.url;
card.target = '_blank';
card.className = 'post-card' + (p.extComments > 0 ? ' ext-highlight' : '');
card.innerHTML = `
<span class="post-week-badge">${weekLabel}</span>
<div class="post-body">
<div class="post-author-row">
<span class="post-author">${(student ? student.name : null) || p.studentId}${(student && student.teacher) ? ' <span class="teacher-badge">FORELESER</span>' : ''}</span>
<span class="post-team-tag">${getTeamLabel((student ? student.team : null) || 'team-0')}</span>
</div>
<div class="post-text">${p.text}</div>
<div class="post-date">${p.date}</div>
</div>
<div class="post-stats">
<div class="pstat"><div class="pstat-value likes-val">${p.likes}</div><div class="pstat-label">❤️</div></div>
<div class="pstat"><div class="pstat-value comments-val">${p.comments}</div><div class="pstat-label">💬</div></div>
${p.reposts > 0 ? `<div class="pstat"><div class="pstat-value reposts-val">${p.reposts}</div><div class="pstat-label">🔄</div></div>` : ''}
${p.extComments > 0 ? `<div class="pstat"><div class="pstat-value ext-val">${p.extComments}</div><div class="pstat-label">🌐</div></div>` : ''}
</div>
`;
container.appendChild(card);
});
if (filtered.length === 0) {
container.innerHTML = '<div style="padding:40px;text-align:center;color:var(--text-faint);font-family:DM Mono,monospace;font-size:0.8rem;letter-spacing:0.06em;">Ingen innlegg funnet</div>';
}
}
// ============================================================
// BUILD STATS
// ============================================================
function buildStats() {
const totalLikes = POSTS.reduce((s,p) => s+p.likes, 0);
const totalComments = POSTS.reduce((s,p) => s+p.comments, 0);
const totalReposts = POSTS.reduce((s,p) => s+(p.reposts||0), 0);
const totalExt = POSTS.reduce((s,p) => s+p.extComments, 0);
const activeStudents = new Set(POSTS.map(p=>p.studentId)).size;
const avgLikes = (totalLikes / POSTS.length).toFixed(1);
document.getElementById('s-posts').textContent = POSTS.length;
document.getElementById('s-likes').textContent = totalLikes;
document.getElementById('s-comments').textContent = totalComments;
document.getElementById('s-reposts').textContent = totalReposts;
document.getElementById('s-ext').textContent = totalExt;
document.getElementById('s-active').textContent = activeStudents;
document.getElementById('s-avg').textContent = avgLikes;
// Header stats
document.getElementById('total-posts').textContent = POSTS.length;
document.getElementById('total-likes').textContent = totalLikes;
document.getElementById('total-ext').textContent = totalExt;
// Week chart
const weekData = {};
POSTS.forEach(p => {
const w = p.week.replace('2026-','');
if (!weekData[w]) weekData[w] = { count: 0, likes: 0 };
weekData[w].count++;
weekData[w].likes += p.likes;
});
const weeks = Object.keys(weekData).sort();
const maxCount = Math.max(...weeks.map(w => weekData[w].count));
const chartEl = document.getElementById('week-chart');
const labelEl = document.getElementById('week-labels');
weeks.forEach(w => {
const d = weekData[w];
const h = Math.max(8, (d.count / maxCount * 100));
const bar = document.createElement('div');
bar.style.cssText = `flex:1;background:linear-gradient(180deg,var(--green),rgba(0,229,160,0.3));border-radius:4px 4px 0 0;height:${h}%;transition:height 0.8s ease;position:relative;min-width:24px;cursor:default;`;
bar.title = `${w}: ${d.count} innlegg, ${d.likes} likes`;
chartEl.appendChild(bar);
const lbl = document.createElement('div');
lbl.style.cssText = `flex:1;font-family:'DM Mono',monospace;font-size:0.6rem;color:var(--text-faint);text-align:center;letter-spacing:0.04em;`;
lbl.textContent = w;
labelEl.appendChild(lbl);
});
}
// ============================================================
// TABS
// ============================================================
function showTab(name, btn) {
document.querySelectorAll('.section').forEach(function(s) { s.classList.remove('active'); });
document.querySelectorAll('.tab-btn').forEach(function(b) { b.classList.remove('active'); });
document.getElementById('tab-' + name).classList.add('active');
if (btn) btn.classList.add('active');
}
// ============================================================
// INIT
// ============================================================
function showError(e) {
var msg = e && e.message ? e.message : String(e);
var stack = e && e.stack ? e.stack : '';
var div = document.createElement('div');
div.style.cssText = 'background:#c0392b;color:#fff;padding:16px;font-family:monospace;font-size:12px;position:fixed;top:0;left:0;right:0;z-index:99999;overflow:auto;max-height:50vh;white-space:pre-wrap;word-break:break-all;';
div.textContent = 'JS FEIL: ' + msg + '\n\n' + stack;
document.body.insertBefore(div, document.body.firstChild);
}
function init() {
try { buildLeaderboards(); } catch(e) { showError(e); }
try { renderFeed(); } catch(e) { showError(e); }
try { buildStats(); } catch(e) { showError(e); }
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
</script>
</body>
</html>