initial commit

This commit is contained in:
t3jfel 2026-04-29 17:09:16 +02:00
commit 785e92cbea
19 changed files with 1890 additions and 0 deletions

BIN
assets/images/cat1.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/images/cat2.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
assets/images/logo.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
assets/images/m01-p01.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

BIN
assets/images/m01-p02.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 MiB

BIN
assets/images/m01-p03.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

BIN
assets/images/m01-p04.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

BIN
assets/images/m01-thumb.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
assets/images/s01-p01.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
assets/images/s02-p01.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

6
components/footer.html Executable file
View file

@ -0,0 +1,6 @@
<div class="container">
<p class="mono" style="opacity: 0.8;">
&copy; 2026 Made with ❤ by t3jfel in Europe.
</p>
</div>

13
components/header.html Executable file
View file

@ -0,0 +1,13 @@
<div class="container">
<nav>
<div class="logo mono">
<a href="{{prefix}}index.html">t3jfel<span class="text-gradient">SEC</span></a>
</div>
<div class="nav-links">
<a href="{{prefix}}index.html#about">About</a>
<a href="{{prefix}}sec.html">SEC</a>
<a href="{{prefix}}magic.html">Magic</a> <a href="{{prefix}}index.html#contact">Contact</a>
</div>
</nav>
</div>

1097
css/style.css Executable file

File diff suppressed because it is too large Load diff

120
index.html Executable file
View file

@ -0,0 +1,120 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>t3jfel SEC</title>
<link rel="icon" type="image/x-icon" href="assets/images/logo.jpg">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="bg-grid"></div>
<div class="bg-orb"></div>
<header></header>
<main>
<section class="hero">
<div class="container hero-content">
<span class="status-badge mono">STATUS: NSA Probably watching.</span>
<h1>All Things About <br><span class="text-gradient">Cybersecurity</span></h1>
<p class="mono hero-typed"></p>
</div>
</section>
<section id="about">
<div class="container">
<h2><span class="text-gradient">&gt;</span> Operator Profile</h2>
<p>I'm a student trying to become Cybersecurity Professional because I'm curious about the "how"
and "why".</p>
<br>
</div>
</section>
<section id="skills">
<div class="container">
<h2><span class="text-gradient">&gt;</span> Obsessions</h2>
<div class="skills-grid reveal-stagger">
<div class="skill-card">
<h3 class="mono text-blue">SOC Operations</h3>
<p>Splunk SPL, ELK Stack</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">Digital Forensics</h3>
<p>Disk Imaging, Memory Forensics</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">Malware Analysis</h3>
<p>IDA, Ghidra, x64dbg, Static &amp; Dynamic Analysis</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">0-Day Research</h3>
<p>Exploit Development</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">Scripting</h3>
<p>Bash, PowerShell, Python, C/C++.</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">Blockchain</h3>
<p>Crypto Networks &amp;&amp; Payments</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">Electronics</h3>
<p>Hardware Hacking &amp;&amp; Messing around with hardware in general</p>
</div>
<div class="skill-card">
<h3 class="mono text-blue">Digital World</h3>
<p>Security &amp;&amp; Privacy, Steam Collector, E-Sports</p>
</div>
</div>
</div>
</section>
<section id="cases">
<div class="container">
<h2><span class="text-gradient">&gt;</span> SEC</h2>
<div id="post-container" class="post-list">
<p class="mono">Loading...</p>
</div>
</div>
</section>
<section id="contact">
<div class="container">
<h2><span class="text-gradient">&gt;</span> Slide into DM's</h2>
<div class="contact-box">
<p>Only unserious business!</p>
<ul class="mono" style="list-style: none;">
<li>E-mail: <a href="mailto:t3jfelsec.catalyst652@passmail.net" class="text-blue">t3jfelsec.catalyst652@passmail.net</a></li>
<li>HackTheBox: <a href="https://app.hackthebox.com/users/2301507" target="_blank" class="text-blue">HTB</a></li>
<li>pwn.college: <a href="pwn.college" target="_blank" class="text-blue">t3jfel</a></li>
<li>LetsDefend: <a href="https://app.letsdefend.io/user/t3jfel" target="_blank" class="text-blue">LD</a></li>
<li>Codeberg: <a href="https://code.t3jfel.dev" target="_blank" class="text-blue">Codeberg (Forgejo)</a></li>
<li>Matrix Protocol: <a href="https://matrix.to/#/@t3jfel:t3jfel.dev" target="_blank" class="text-blue">Matrix</a></li>
<li>Mastodon Social: <a href="https://mastodon.social/@t3jfel" target="_blank" class="text-blue">Mastodon</a></li>
<li>In CTF's my name is also: <a target="_blank" class="text-blue">t3jfel</a></li>
<li>I also take my steam account and video games seriously: <a href="https://steamcommunity.com/profiles/76561199191057192/" target="_blank" class="text-blue">Steam</a></li>
<li>Antique Steam Account: <a href="https://steamcommunity.com/profiles/76561197991879304/" target="_blank" class="text-blue">Steam OLD</a></li>
</ul>
<img src="assets/images/cat2.jpg" alt="cat2">
<div class="ticker-wrap">
<div class="ticker-content" id="skill-issue-feed"></div>
</div>
</div>
</div>
</section>
</main>
<footer></footer>
<script src="js/main.js"></script>
</body>
</html>

276
js/main.js Executable file
View file

@ -0,0 +1,276 @@
document.addEventListener('DOMContentLoaded', () => {
loadComponents().then(() => {
initSkillIssueTicker();
initCryptoCopier();
});
loadRecentPosts();
initTypingEffect();
initScrollReveal();
initScrollParallax();
if (document.getElementById('sec-grid')) {
initSearchableGrid('sec', 'sec-grid', 'sec-search');
}
if (document.getElementById('magic-grid')) {
initSearchableGrid('magic', 'magic-grid', 'magic-search');
}
});
function initScrollParallax() {
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
const root = document.documentElement;
let scrollY = 0;
let ticking = false;
function update() {
root.style.setProperty('--scroll', scrollY);
ticking = false;
}
window.addEventListener('scroll', () => {
scrollY = window.scrollY || window.pageYOffset || 0;
if (!ticking) {
requestAnimationFrame(update);
ticking = true;
}
}, { passive: true });
}
async function loadComponents() {
try {
const headerRes = await fetch('components/header.html');
if (headerRes.ok) {
let headerHtml = await headerRes.text();
headerHtml = headerHtml.replaceAll('{{prefix}}', '');
const headerEl = document.querySelector('header');
if (headerEl) headerEl.innerHTML = headerHtml;
}
const footerRes = await fetch('components/footer.html');
if (footerRes.ok) {
const footerEl = document.querySelector('footer');
if (footerEl) footerEl.innerHTML = await footerRes.text();
}
} catch (e) {
console.error('Component load error:', e);
}
}
function initScrollReveal() {
const sections = document.querySelectorAll('main > section');
sections.forEach(section => {
if (!section.classList.contains('hero')) {
section.classList.add('reveal');
}
});
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.12, rootMargin: '0px 0px -60px 0px' });
document.querySelectorAll('.reveal, .reveal-stagger, main > section').forEach(el => {
observer.observe(el);
});
}
function attachStaggerObserver(root) {
if (!root) return;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
observer.observe(root);
}
function initTypingEffect() {
const el = document.querySelector('.hero-typed');
if (!el) return;
const text = "My Computer Science notes, mostly focused on trying to master cybersecurity.";
let index = 0;
function type() {
if (index < text.length) {
el.textContent += text[index];
index++;
setTimeout(type, 28 + Math.random() * 35);
} else {
el.classList.add('done');
}
}
setTimeout(type, 700);
}
async function loadRecentPosts() {
const container = document.getElementById('post-container');
if (!container) return;
try {
const response = await fetch('/api/collections/cases/records?sort=-created');
if (!response.ok) throw new Error('Status: ' + response.status);
const data = await response.json();
const posts = (data.items || []).slice(0, 6);
if (posts.length === 0) {
container.innerHTML = '<p class="empty-state mono">No posts yet.</p>';
return;
}
container.classList.add('reveal-stagger');
container.innerHTML = posts.map(post => {
const linkUrl = 'walkthroughs/view.html?id=' + post.id;
const tagStyle = post.category === 'magic'
? 'color: #a855f7; background: rgba(168, 85, 247, 0.1);'
: '';
const date = (post.created || '').split(' ')[0];
return `
<a href="${linkUrl}" class="post-item">
<span class="post-meta mono">
<span class="post-tag" style="${tagStyle}">[${escapeHtml(post.tag || '')}]</span>
${escapeHtml(date)}
</span>
<h3>${escapeHtml(post.title || '')}</h3>
<p>${escapeHtml(post.summary || '')}</p>
</a>`;
}).join('');
attachStaggerObserver(container);
} catch (e) {
console.error('Failed to sync data:', e);
container.innerHTML = '<p class="empty-state mono">Failed to load posts.</p>';
}
}
async function initSearchableGrid(category, gridId, searchId) {
const grid = document.getElementById(gridId);
const searchInput = document.getElementById(searchId);
if (!grid) return;
try {
const response = await fetch('/api/collections/cases/records?sort=-created');
if (!response.ok) throw new Error('Status: ' + response.status);
const data = await response.json();
const allPosts = data.items || [];
const categoryPosts = allPosts.filter(p => p.category === category);
const render = (items) => {
grid.classList.add('reveal-stagger');
grid.classList.remove('in-view');
if (items.length === 0) {
grid.classList.remove('reveal-stagger');
grid.innerHTML = '<p class="empty-state mono">No results found.</p>';
return;
}
grid.innerHTML = items.map(post => {
let imageHtml = '';
let cardClass = 'sec-card';
const date = (post.created || '').split(' ')[0];
if (category === 'magic' && post.thumbnail) {
imageHtml = `<div class="card-img" style="background-image: url('${escapeAttr(post.thumbnail)}');"></div>`;
cardClass += ' has-image';
}
return `
<a href="walkthroughs/view.html?id=${encodeURIComponent(post.id)}" class="${cardClass}">
${imageHtml}
<div class="card-content">
<h3 class="mono">${escapeHtml(post.title || '')}</h3>
<span class="card-meta mono">[${escapeHtml(post.tag || '')}] ${escapeHtml(date)}</span>
</div>
</a>`;
}).join('');
requestAnimationFrame(() => grid.classList.add('in-view'));
};
render(categoryPosts);
if (searchInput) {
searchInput.addEventListener('input', (e) => {
const term = e.target.value.toLowerCase();
const filtered = categoryPosts.filter(post =>
(post.title || '').toLowerCase().includes(term) ||
(post.tag || '').toLowerCase().includes(term) ||
(post.summary || '').toLowerCase().includes(term)
);
render(filtered);
});
}
} catch (e) {
console.error('Grid error:', e);
grid.innerHTML = '<p class="empty-state mono">Failed to load.</p>';
}
}
function initSkillIssueTicker() {
const tickerContainer = document.getElementById('skill-issue-feed');
if (!tickerContainer) return;
const messages = [
"Zero Days found: 0",
"Imposter Syndrome kicking in",
"Pigeons are liars",
"CERTIFICATIONS: Trust me bro",
"The S in IOT stand for Security.",
"Must be a layer 8 issue.",
"The best way to secure a computer is to turn it off and never power it on.",
"And then?"
];
const content = [...messages, ...messages, ...messages]
.map(msg => `<span class="ticker-item">${escapeHtml(msg)}</span>`)
.join('');
tickerContainer.innerHTML = content;
}
function initCryptoCopier() {
document.querySelectorAll('.crypto-addr').forEach(addr => {
addr.addEventListener('click', async () => {
const originalText = addr.innerText;
const cleanAddress = originalText.replace(/\s/g, '');
try {
await navigator.clipboard.writeText(cleanAddress);
addr.classList.add('copied');
addr.innerText = '[ ADDRESS COPIED ]';
setTimeout(() => {
addr.classList.remove('copied');
addr.innerText = originalText;
}, 1500);
} catch (err) {
console.error('Copy failed:', err);
}
});
});
}
function escapeHtml(str) {
if (str == null) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function escapeAttr(str) {
if (str == null) return '';
return String(str).replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

251
js/viewer.js Executable file
View file

@ -0,0 +1,251 @@
document.addEventListener('DOMContentLoaded', async () => {
await loadComponents();
initScrollParallax();
initLightbox();
const urlParams = new URLSearchParams(window.location.search);
const caseId = urlParams.get('id');
if (!caseId) {
document.getElementById('main-content').innerHTML =
'<div class="container"><h2>Error: No case ID specified.</h2></div>';
return;
}
await loadCaseData(caseId);
attachLightboxToImages();
});
function initScrollParallax() {
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
const root = document.documentElement;
let scrollY = 0;
let ticking = false;
function update() {
root.style.setProperty('--scroll', scrollY);
ticking = false;
}
window.addEventListener('scroll', () => {
scrollY = window.scrollY || window.pageYOffset || 0;
if (!ticking) {
requestAnimationFrame(update);
ticking = true;
}
}, { passive: true });
}
async function loadComponents() {
try {
const headerRes = await fetch('../components/header.html');
if (headerRes.ok) {
let headerHtml = await headerRes.text();
headerHtml = headerHtml.replaceAll('{{prefix}}', '../');
document.querySelector('header').innerHTML = headerHtml;
}
const footerRes = await fetch('../components/footer.html');
if (footerRes.ok) {
document.querySelector('footer').innerHTML = await footerRes.text();
}
} catch (e) {
console.error('Component load error', e);
}
}
async function loadCaseData(id) {
try {
const response = await fetch('/api/collections/cases/records');
const data = await response.json();
const cases = data.items || [];
const currentCase = cases.find(c => c.id === id);
if (!currentCase) {
document.getElementById('main-content').innerHTML =
'<div class="container"><h2>Error: Case not found.</h2></div>';
return;
}
const backLink = document.getElementById('back-link');
if (backLink) {
if (currentCase.category === 'magic') {
backLink.href = '../magic.html';
backLink.innerHTML = '&larr; BACK TO MAGIC';
} else {
backLink.href = '../sec.html';
backLink.innerHTML = '&larr; BACK TO SEC';
}
}
const titleElement = document.getElementById('case-title');
titleElement.innerText = currentCase.title || '';
if (currentCase.category === 'magic') {
titleElement.classList.add('expert-title');
titleElement.classList.remove('text-gradient');
}
document.title = (currentCase.title || 'Case Study') + ' | t3jfel SEC';
document.getElementById('case-tag').innerText = currentCase.tag || '';
const date = (currentCase.created || '').split(' ')[0];
document.getElementById('case-meta').innerText =
'DATE: ' + date + ' | ID: ' + currentCase.id;
document.getElementById('case-intro').innerText = currentCase.intro || '';
const container = document.getElementById('steps-container');
container.innerHTML = '';
if (currentCase.category === 'magic' && currentCase.sections) {
container.className = 'expert-container';
currentCase.sections.forEach(section => {
let sectionHtml =
'<div class="expert-section">' +
'<h2 class="expert-h2">' + escapeHtml(section.heading || '') + '</h2>';
(section.content || []).forEach(block => {
if (block.type === 'text') {
sectionHtml += '<p class="expert-p">' + escapeHtml(block.value) + '</p>';
} else if (block.type === 'code') {
const codeVal = Array.isArray(block.value) ? block.value.join('\n') : block.value;
sectionHtml +=
'<pre class="expert-code-block"><code>' +
escapeHtml(codeVal) + '</code></pre>';
} else if (block.type === 'image') {
const imgPath = block.value.startsWith('http') ? block.value : '../' + block.value;
sectionHtml +=
'<div class="expert-image-wrapper">' +
'<img src="' + escapeAttr(imgPath) + '" alt="Documentation Image" class="lightbox-trigger">' +
'</div>';
}
});
sectionHtml += '</div>';
container.insertAdjacentHTML('beforeend', sectionHtml);
});
} else {
container.className = 'analysis-steps-container';
(currentCase.steps || []).forEach((step, idx) => {
let bodyHtml = '';
if (step.body) {
step.body.forEach(block => {
if (block.type === 'text') {
bodyHtml += '<p>' + escapeHtml(block.value) + '</p>';
} else if (block.type === 'code') {
const codeVal = Array.isArray(block.value) ? block.value.join('\n') : block.value;
bodyHtml += '<pre><code>' + escapeHtml(codeVal) + '</code></pre>';
} else if (block.type === 'image') {
const imgPath = block.value.startsWith('http') ? block.value : '../' + block.value;
bodyHtml += '<img src="' + escapeAttr(imgPath) + '" alt="Step image" class="lightbox-trigger">';
}
});
}
const num = String(idx + 1).padStart(2, '0');
const stepHtml =
'<article class="blog-step">' +
'<div class="step-header">' +
'<span class="step-number mono">Step ' + num + '</span>' +
'<h2 class="step-title">' + escapeHtml(step.title || '') + '</h2>' +
'</div>' +
'<div class="step-body">' + bodyHtml + '</div>' +
'</article>';
container.insertAdjacentHTML('beforeend', stepHtml);
});
}
} catch (e) {
console.error(e);
}
}
var lb = { scale: 1, tx: 0, ty: 0 };
function initLightbox() {
const overlay = document.createElement('div');
overlay.id = 'lightbox-overlay';
overlay.innerHTML =
'<div id="lightbox-content">' +
'<img id="lightbox-img" src="" alt="Enlarged image">' +
'</div>' +
'<button id="lightbox-close" aria-label="Close">&times;</button>';
document.body.appendChild(overlay);
const img = document.getElementById('lightbox-img');
function applyTransform() {
img.style.transform =
'translate(' + lb.tx + 'px, ' + lb.ty + 'px) scale(' + lb.scale + ')';
}
overlay.addEventListener('click', function (e) {
if (e.target === overlay || e.target.id === 'lightbox-content') {
closeLightbox();
}
});
document.getElementById('lightbox-close').addEventListener('click', closeLightbox);
overlay.addEventListener('wheel', function (e) {
e.preventDefault();
const rect = img.getBoundingClientRect();
const dx = e.clientX - rect.left;
const dy = e.clientY - rect.top;
const factor = e.deltaY < 0 ? 1.12 : 0.9;
const newScale = Math.min(Math.max(lb.scale * factor, 0.15), 10);
const ratio = newScale / lb.scale;
lb.tx = lb.tx + dx * (1 - ratio);
lb.ty = lb.ty + dy * (1 - ratio);
lb.scale = newScale;
applyTransform();
}, { passive: false });
document.addEventListener('keydown', function (e) {
if (overlay.classList.contains('active') && e.key === 'Escape') {
closeLightbox();
}
});
}
function openLightbox(src) {
lb.scale = 1;
lb.tx = 0;
lb.ty = 0;
const img = document.getElementById('lightbox-img');
img.src = src;
img.style.transform = '';
document.getElementById('lightbox-overlay').classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
document.getElementById('lightbox-overlay').classList.remove('active');
document.body.style.overflow = '';
}
function attachLightboxToImages() {
document.querySelectorAll('.lightbox-trigger').forEach(function (img) {
img.addEventListener('click', function () {
openLightbox(img.src);
});
});
}
function escapeHtml(str) {
if (str == null) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function escapeAttr(str) {
if (str == null) return '';
return String(str).replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

45
magic.html Executable file
View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ohh Magic! | t3jfel SEC</title>
<link rel="icon" type="image/x-icon" href="assets/images/logo.jpg">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="bg-grid"></div>
<div class="bg-orb"></div>
<header></header>
<main>
<section class="hero archive-hero">
<div class="container">
<h1><span class="text-gradient">&gt;</span> It's Magic</h1>
<p class="mono"><b>Deep dives into how the world actually works and how it is getting bypassed or hacked. Maybe some mathematics and physics, cuz I hate it.</b></p>
</div>
</section>
<section>
<div class="container">
<div class="search-wrapper">
<input type="text" id="magic-search" class="search-input" placeholder="Search...">
</div>
<div id="magic-grid" class="compact-grid">
<p class="mono">Loading...</p>
</div>
</div>
</section>
</main>
<footer></footer>
<script src="js/main.js"></script>
</body>
</html>

45
sec.html Executable file
View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security | t3jfel SEC</title>
<link rel="icon" type="image/x-icon" href="assets/images/logo.jpg">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="bg-grid"></div>
<div class="bg-orb"></div>
<header></header>
<main>
<section class="hero archive-hero">
<div class="container">
<h1><span class="text-gradient">&gt;</span> Security Archive</h1>
<p class="mono"><b>These might help APT's compromise me, but I always report my findings (if i have :)) first ofc.</b></p>
</div>
</section>
<section>
<div class="container">
<div class="search-wrapper">
<input type="text" id="sec-search" class="search-input" placeholder="Search...">
</div>
<div id="sec-grid" class="compact-grid">
<p class="mono">Loading...</p>
</div>
</div>
</section>
</main>
<footer></footer>
<script src="js/main.js"></script>
</body>
</html>

37
walkthroughs/view.html Executable file
View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Case Study | Loading...</title>
<link rel="icon" type="image/x-icon" href="../assets/images/logo.jpg">
<link rel="stylesheet" href="../css/style.css">
</head>
<body>
<div class="bg-grid"></div>
<div class="bg-orb"></div>
<header></header>
<main id="main-content">
<section class="hero case-hero">
<div class="container case-hero-inner">
<a id="back-link" href="../sec.html" class="mono">&larr; BACK TO OPERATIONS</a>
<span id="case-tag" class="status-badge mono">LOADING...</span>
<h1 id="case-title">Loading...</h1>
<p id="case-meta" class="mono">...</p>
</div>
</section>
<section>
<div class="container">
<div id="case-intro"></div>
<div id="steps-container" class="analysis-steps-container"></div>
</div>
</section>
</main>
<footer></footer>
<script src="../js/viewer.js"></script>
</body>
</html>