FS Testsimulation 1

<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frankfurt School – AC-Test Mathematics</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=IBM+Plex+Sans:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
  --bg: #f9f8f5;
  --white: #ffffff;
  --border: #e8e6de;
  --border2: #d4d1c6;
  --text: #1c1a16;
  --muted: #7a7668;
  --accent: #1a3a6b;
  --accent2: #2554a0;
  --accent-light: #eef2fa;
  --green: #15803d;
  --green-light: #f0fdf4;
  --green-border: #86efac;
  --red: #b91c1c;
  --red-light: #fef2f2;
  --red-border: #fca5a5;
  --yellow: #92400e;
  --yellow-light: #fffbeb;
  --yellow-border: #fcd34d;
  --shadow: 0 1px 4px rgba(0,0,0,0.07), 0 4px 20px rgba(0,0,0,0.05);
  --shadow-lg: 0 8px 40px rgba(0,0,0,0.10);
}

- { box-sizing: border-box; margin: 0; padding: 0; }

body {
background: var(–bg);
color: var(–text);
font-family: ‘IBM Plex Sans’, sans-serif;
font-size: 15px;
line-height: 1.6;
min-height: 100vh;
}

/* ══ UTILS ══ */
.hidden { display: none !important; }

/* ══════════════════════════════════════
LOGIN
══════════════════════════════════════ */
#screen-login {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(–accent);
position: relative;
overflow: hidden;
}

.login-noise {
position: absolute; inset: 0;
background-image: url(“data:image/svg+xml,%3Csvg xmlns=‘http://www.w3.org/2000/svg’ width=‘400’ height=‘400’%3E%3Cfilter id=‘n’%3E%3CfeTurbulence type=‘fractalNoise’ baseFrequency=‘0.75’ numOctaves=‘4’ stitchTiles=‘stitch’/%3E%3C/filter%3E%3Crect width=‘400’ height=‘400’ filter=‘url(%23n)’ opacity=‘0.04’/%3E%3C/svg%3E”);
opacity: 0.5;
}

.login-deco {
position: absolute;
border-radius: 50%;
background: rgba(255,255,255,0.04);
}
.login-deco-1 { width: 500px; height: 500px; top: -200px; right: -100px; }
.login-deco-2 { width: 300px; height: 300px; bottom: -100px; left: -80px; }

.login-card {
position: relative; z-index: 2;
background: var(–white);
border-radius: 20px;
padding: 52px 48px;
width: 100%; max-width: 440px;
box-shadow: 0 40px 100px rgba(0,0,0,0.35);
animation: riseUp 0.5s cubic-bezier(.22,.68,0,1.2);
}

@keyframes riseUp {
from { opacity: 0; transform: translateY(30px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}

.login-school-badge {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(–accent-light);
border: 1px solid #c7d5ef;
border-radius: 8px;
padding: 6px 12px;
margin-bottom: 28px;
}

.login-school-dot {
width: 8px; height: 8px;
border-radius: 50%;
background: var(–accent);
}

.login-school-name {
font-size: 11px;
font-weight: 600;
letter-spacing: 1px;
text-transform: uppercase;
color: var(–accent);
}

.login-h1 {
font-family: ‘Playfair Display’, serif;
font-size: 30px;
font-weight: 700;
line-height: 1.2;
margin-bottom: 8px;
color: var(–text);
letter-spacing: -0.5px;
}

.login-sub {
font-size: 14px;
color: var(–muted);
margin-bottom: 36px;
line-height: 1.55;
}

.field-group { margin-bottom: 20px; }

.field-label {
display: block;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.9px;
text-transform: uppercase;
color: var(–muted);
margin-bottom: 7px;
}

.field-input {
width: 100%;
border: 1.5px solid var(–border);
border-radius: 10px;
padding: 13px 16px;
font-size: 15px;
font-family: ‘IBM Plex Sans’, sans-serif;
color: var(–text);
background: var(–bg);
outline: none;
transition: border-color 0.15s, box-shadow 0.15s;
}

.field-input:focus {
border-color: var(–accent);
box-shadow: 0 0 0 3px rgba(26,58,107,0.10);
background: var(–white);
}

.field-input.err { border-color: var(–red); }

.login-err-msg {
background: var(–red-light);
border: 1px solid var(–red-border);
color: var(–red);
border-radius: 8px;
padding: 10px 14px;
font-size: 13px;
margin-bottom: 18px;
}

.btn-login {
width: 100%;
background: var(–accent);
color: white;
border: none;
border-radius: 10px;
padding: 15px;
font-size: 15px;
font-weight: 600;
font-family: ‘IBM Plex Sans’, sans-serif;
cursor: pointer;
letter-spacing: 0.2px;
transition: background 0.15s, transform 0.15s;
}
.btn-login:hover { background: var(–accent2); transform: translateY(-1px); }

.login-footer {
margin-top: 24px;
text-align: center;
font-size: 12px;
color: #bbb9af;
}

/* ══════════════════════════════════════
TEST HEADER
══════════════════════════════════════ */
#screen-test { min-height: 100vh; }

.test-header {
background: var(–accent);
color: white;
padding: 0 40px;
height: 62px;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky; top: 0; z-index: 100;
}

.header-brand {
display: flex; align-items: center; gap: 14px;
}

.header-brand-name {
font-family: ‘Playfair Display’, serif;
font-size: 17px;
font-weight: 600;
letter-spacing: -0.2px;
}

.header-divider {
width: 1px; height: 20px;
background: rgba(255,255,255,0.25);
}

.header-test-name {
font-size: 13px;
font-weight: 500;
opacity: 0.75;
letter-spacing: 0.3px;
}

.header-right { display: flex; align-items: center; gap: 20px; }

.timer-wrap {
display: flex; align-items: center; gap: 8px;
}

.timer-icon { font-size: 14px; opacity: 0.7; }

.timer-val {
font-family: ‘IBM Plex Mono’, monospace;
font-size: 22px;
font-weight: 500;
letter-spacing: 2px;
color: white;
transition: color 0.3s;
}

.timer-val.warn { color: #fcd34d; }
.timer-val.danger { color: #fca5a5; animation: blink 1s step-end infinite; }

@keyframes blink {
50% { opacity: 0.4; }
}

.progress-strip {
height: 3px;
background: rgba(255,255,255,0.15);
}

.progress-fill {
height: 100%;
background: rgba(255,255,255,0.7);
transition: width 0.4s ease;
}

.header-submit-btn {
background: rgba(255,255,255,0.15);
border: 1px solid rgba(255,255,255,0.3);
color: white;
border-radius: 8px;
padding: 7px 16px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
font-family: ‘IBM Plex Sans’, sans-serif;
transition: background 0.15s;
}
.header-submit-btn:hover { background: rgba(255,255,255,0.25); }

/* ══════════════════════════════════════
TEST BODY
══════════════════════════════════════ */
.test-body {
display: grid;
grid-template-columns: 260px 1fr;
max-width: 1100px;
margin: 0 auto;
padding: 32px 24px;
gap: 28px;
}

/* SIDEBAR */
.sidebar {
position: sticky;
top: 94px;
height: fit-content;
}

.sidebar-box {
background: var(–white);
border: 1px solid var(–border);
border-radius: 14px;
padding: 20px;
box-shadow: var(–shadow);
margin-bottom: 16px;
}

.sidebar-title {
font-size: 11px;
font-weight: 600;
letter-spacing: 1px;
text-transform: uppercase;
color: var(–muted);
margin-bottom: 14px;
}

.nav-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 6px;
}

.nav-dot {
aspect-ratio: 1;
border-radius: 7px;
border: 1.5px solid var(–border);
background: var(–bg);
font-size: 11px;
font-family: ‘IBM Plex Mono’, monospace;
color: var(–muted);
cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: all 0.15s;
font-weight: 500;
}

.nav-dot:hover { border-color: var(–accent); color: var(–accent); }
.nav-dot.current { border-color: var(–accent); background: var(–accent); color: white; }
.nav-dot.answered { border-color: var(–accent2); background: var(–accent-light); color: var(–accent); }
.nav-dot.answered.current { background: var(–accent); color: white; }

.legend { display: flex; flex-direction: column; gap: 8px; }

.legend-item {
display: flex; align-items: center; gap: 8px;
font-size: 12px; color: var(–muted);
}

.legend-dot {
width: 12px; height: 12px; border-radius: 3px; flex-shrink: 0;
}

/* MAIN QUESTION AREA */
.question-area { min-width: 0; }

.q-card {
background: var(–white);
border: 1px solid var(–border);
border-radius: 16px;
box-shadow: var(–shadow);
overflow: hidden;
animation: slideQ 0.2s ease;
}

@keyframes slideQ {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}

.q-card-header {
padding: 18px 28px;
border-bottom: 1px solid var(–border);
background: #fafaf7;
display: flex;
align-items: center;
justify-content: space-between;
}

.q-tags { display: flex; gap: 8px; align-items: center; }

.q-num-tag {
background: var(–accent);
color: white;
font-family: ‘IBM Plex Mono’, monospace;
font-size: 11px;
font-weight: 500;
padding: 4px 10px;
border-radius: 6px;
letter-spacing: 0.5px;
}

.q-topic-tag {
background: var(–accent-light);
color: var(–accent);
border: 1px solid #c7d5ef;
font-size: 11px;
font-weight: 500;
padding: 4px 10px;
border-radius: 6px;
}

.q-type-tag {
background: var(–bg);
color: var(–muted);
border: 1px solid var(–border);
font-size: 11px;
padding: 4px 10px;
border-radius: 6px;
}

.q-points {
font-size: 12px;
color: var(–muted);
font-family: ‘IBM Plex Mono’, monospace;
}

.q-body { padding: 32px 28px 28px; }

.q-text {
font-size: 17px;
line-height: 1.7;
color: var(–text);
margin-bottom: 28px;
font-weight: 400;
}

.q-formula {
background: var(–accent-light);
border: 1px solid #c7d5ef;
border-radius: 8px;
padding: 14px 18px;
font-family: ‘IBM Plex Mono’, monospace;
font-size: 15px;
color: var(–accent);
margin-bottom: 28px;
display: inline-block;
}

/* OPTIONS */
.opts-2col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}

.opts-1col {
display: flex; flex-direction: column; gap: 8px;
}

.opt {
border: 1.5px solid var(–border);
border-radius: 11px;
padding: 14px 18px;
cursor: pointer;
transition: all 0.14s;
display: flex; align-items: center; gap: 12px;
background: var(–bg);
user-select: none;
}

.opt:hover { border-color: var(–accent); background: var(–accent-light); }
.opt.sel { border-color: var(–accent); background: var(–accent-light); }
.opt.sel .opt-ltr { background: var(–accent); color: white; }

.opt-ltr {
width: 28px; height: 28px; border-radius: 50%;
background: var(–border);
display: flex; align-items: center; justify-content: center;
font-family: ‘IBM Plex Mono’, monospace;
font-size: 11px; font-weight: 500;
flex-shrink: 0;
transition: background 0.14s;
}

.opt-txt { font-size: 14px; line-height: 1.4; }

/* FREE INPUT */
.free-row {
display: flex; align-items: center; gap: 14px;
}

.free-inp {
border: 1.5px solid var(–border);
border-radius: 10px;
padding: 13px 18px;
font-size: 17px;
font-family: ‘IBM Plex Mono’, monospace;
color: var(–text);
background: var(–bg);
outline: none;
width: 220px;
transition: all 0.15s;
}

.free-inp:focus {
border-color: var(–accent);
box-shadow: 0 0 0 3px rgba(26,58,107,0.08);
background: var(–white);
}

/* FOOTER */
.q-footer {
padding: 18px 28px;
border-top: 1px solid var(–border);
background: #fafaf7;
display: flex; align-items: center; justify-content: space-between;
}

.footer-left { font-size: 13px; color: var(–muted); }

.footer-right { display: flex; gap: 10px; }

.btn {
padding: 10px 22px;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
font-family: ‘IBM Plex Sans’, sans-serif;
border: none;
transition: all 0.14s;
letter-spacing: 0.2px;
}

.btn-ghost {
background: transparent;
border: 1.5px solid var(–border);
color: var(–muted);
}
.btn-ghost:hover { border-color: var(–border2); color: var(–text); }
.btn-ghost:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-primary {
background: var(–accent);
color: white;
}
.btn-primary:hover { background: var(–accent2); }

.btn-submit {
background: #15803d;
color: white;
}
.btn-submit:hover { background: #166534; }

/* ══════════════════════════════════════
CONFIRM MODAL
══════════════════════════════════════ */
.modal-overlay {
position: fixed; inset: 0; z-index: 200;
background: rgba(28,26,22,0.5);
backdrop-filter: blur(4px);
display: flex; align-items: center; justify-content: center;
animation: fadeIn 0.2s ease;
}

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.modal-box {
background: var(–white);
border-radius: 16px;
padding: 40px;
max-width: 420px;
width: 90%;
box-shadow: var(–shadow-lg);
animation: riseUp 0.25s ease;
text-align: center;
}

.modal-icon { font-size: 40px; margin-bottom: 16px; }

.modal-title {
font-family: ‘Playfair Display’, serif;
font-size: 22px;
font-weight: 700;
margin-bottom: 10px;
}

.modal-body {
font-size: 14px; color: var(–muted);
margin-bottom: 28px; line-height: 1.6;
}

.modal-btns { display: flex; gap: 10px; justify-content: center; }

/* ══════════════════════════════════════
RESULTS
══════════════════════════════════════ */
#screen-results {
min-height: 100vh;
background: var(–bg);
}

.results-header {
background: var(–accent);
color: white;
padding: 40px;
text-align: center;
}

.results-lernvia {
font-size: 11px;
font-weight: 600;
letter-spacing: 2px;
text-transform: uppercase;
opacity: 0.6;
margin-bottom: 8px;
}

.results-title {
font-family: ‘Playfair Display’, serif;
font-size: 32px;
font-weight: 700;
letter-spacing: -0.5px;
margin-bottom: 4px;
}

.results-sub { font-size: 14px; opacity: 0.7; }

.results-body {
max-width: 900px;
margin: 0 auto;
padding: 40px 24px 60px;
}

/* SCORE BANNER */
.score-banner {
background: var(–white);
border: 1px solid var(–border);
border-radius: 18px;
padding: 40px;
display: flex;
align-items: center;
justify-content: space-around;
box-shadow: var(–shadow-lg);
margin-bottom: 32px;
flex-wrap: wrap;
gap: 24px;
}

.score-ring-wrap { position: relative; flex-shrink: 0; }

.score-ring-wrap svg { transform: rotate(-90deg); }

.score-center {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
text-align: center;
pointer-events: none;
}

.score-pct {
font-family: ‘Playfair Display’, serif;
font-size: 38px;
font-weight: 700;
color: var(–text);
line-height: 1;
}

.score-label {
font-size: 11px;
letter-spacing: 1px;
text-transform: uppercase;
color: var(–muted);
margin-top: 2px;
}

.score-details { flex: 1; min-width: 200px; }

.score-verdict {
font-family: ‘Playfair Display’, serif;
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
letter-spacing: -0.3px;
}

.score-desc {
font-size: 14px;
color: var(–muted);
margin-bottom: 20px;
line-height: 1.6;
}

.score-meta {
display: flex; gap: 24px; flex-wrap: wrap;
}

.score-meta-item { text-align: center; }

.score-meta-val {
font-family: ‘IBM Plex Mono’, monospace;
font-size: 22px;
font-weight: 500;
line-height: 1;
margin-bottom: 3px;
}

.score-meta-lbl {
font-size: 11px;
color: var(–muted);
letter-spacing: 0.5px;
text-transform: uppercase;
}

/* TOPIC BREAKDOWN */
.section-hd {
font-family: ‘Playfair Display’, serif;
font-size: 20px;
font-weight: 600;
margin-bottom: 16px;
letter-spacing: -0.3px;
}

.breakdown-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 32px;
}

.breakdown-card {
background: var(–white);
border: 1px solid var(–border);
border-radius: 12px;
padding: 18px;
box-shadow: var(–shadow);
}

.bd-topic {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.5px;
color: var(–muted);
text-transform: uppercase;
margin-bottom: 10px;
}

.bd-bar-bg {
height: 6px;
background: var(–bg);
border-radius: 99px;
overflow: hidden;
margin-bottom: 8px;
}

.bd-bar-fill {
height: 100%;
border-radius: 99px;
transition: width 1.2s cubic-bezier(.22,.68,0,1);
}

.bd-nums {
display: flex; justify-content: space-between;
font-family: ‘IBM Plex Mono’, monospace;
font-size: 12px;
}

/* QUESTION REVIEW */
.review-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 32px; }

.review-item {
background: var(–white);
border: 1px solid var(–border);
border-radius: 12px;
overflow: hidden;
box-shadow: var(–shadow);
}

.review-item-header {
padding: 14px 20px;
display: flex; align-items: flex-start; gap: 14px;
cursor: pointer;
transition: background 0.12s;
}
.review-item-header:hover { background: #fafaf7; }

.review-status {
width: 28px; height: 28px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 13px; flex-shrink: 0; margin-top: 1px;
}

.review-status.ok { background: var(–green-light); color: var(–green); border: 1px solid var(–green-border); }
.review-status.fail { background: var(–red-light); color: var(–red); border: 1px solid var(–red-border); }
.review-status.skip { background: var(–bg); color: var(–muted); border: 1px solid var(–border); }

.review-q-text { font-size: 14px; color: var(–text); flex: 1; line-height: 1.5; }
.review-q-num { font-size: 11px; color: var(–muted); font-family: ‘IBM Plex Mono’, monospace; margin-bottom: 2px; }

.review-arrow { color: var(–muted); font-size: 12px; margin-top: 4px; transition: transform 0.2s; }
.review-arrow.open { transform: rotate(180deg); }

.review-detail {
padding: 14px 20px 18px 62px;
border-top: 1px solid var(–border);
background: #fafaf7;
font-size: 13px;
line-height: 1.6;
display: none;
}
.review-detail.open { display: block; }

.review-ans-row { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }

.ans-chip {
padding: 4px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
font-family: ‘IBM Plex Mono’, monospace;
}

.ans-yours { background: var(–red-light); color: var(–red); border: 1px solid var(–red-border); }
.ans-yours.correct { background: var(–green-light); color: var(–green); border: 1px solid var(–green-border); }
.ans-correct { background: var(–green-light); color: var(–green); border: 1px solid var(–green-border); }
.ans-skipped { background: var(–bg); color: var(–muted); border: 1px solid var(–border); }

.review-explanation { color: var(–muted); font-size: 13px; }

/* RESULTS FOOTER */
.results-footer {
display: flex; justify-content: center; gap: 14px; margin-top: 8px;
}

/* RESPONSIVE */
@media (max-width: 700px) {
.test-body { grid-template-columns: 1fr; padding: 16px; }
.sidebar { position: static; }
.breakdown-grid { grid-template-columns: 1fr 1fr; }
.test-header { padding: 0 16px; }
.q-body { padding: 20px 18px 16px; }
.q-footer { padding: 14px 18px; }
.q-card-header { padding: 14px 18px; }
.opts-2col { grid-template-columns: 1fr; }
.score-banner { padding: 28px 20px; }
.results-header { padding: 28px 20px; }
.results-body { padding: 24px 16px 40px; }
.score-meta { gap: 16px; }
}
</style>

</head>
<body>

<!-- ══════════ LOGIN ══════════ -->

<div id="screen-login">
  <div class="login-noise"></div>
  <div class="login-deco login-deco-1"></div>
  <div class="login-deco login-deco-2"></div>
  <div class="login-card">
    <div class="login-school-badge">
      <div class="login-school-dot"></div>
      <div class="login-school-name">Frankfurt School · AC-Test</div>
    </div>
    <h1 class="login-h1">Mathematics<br>Practice Exam</h1>
    <p class="login-sub">30 questions · 45 minutes · Full evaluation upon completion</p>

```
<div class="field-group">
  <label class="field-label">Your Name</label>
  <input id="inp-name" class="field-input" type="text" placeholder="e.g. Max Müller"
    onkeydown="if(event.key==='Enter')document.getElementById('inp-pw').focus()">
</div>

<div class="field-group">
  <label class="field-label">Access Password</label>
  <input id="inp-pw" class="field-input" type="password" placeholder="Enter password"
    onkeydown="if(event.key==='Enter')doLogin()">
</div>

<div id="login-err" class="login-err-msg hidden">Incorrect password. Please try again.</div>

<button class="btn-login" onclick="doLogin()">Start Exam →</button>
<div class="login-footer">powered by <strong style="color:#888">Lernvia</strong></div>
```

  </div>
</div>

<!-- ══════════ TEST ══════════ -->

<div id="screen-test" class="hidden">
  <div class="test-header">
    <div class="header-brand">
      <div class="header-brand-name">Frankfurt School</div>
      <div class="header-divider"></div>
      <div class="header-test-name">AC-Test Mathematics – Simulation</div>
    </div>
    <div class="header-right">
      <div class="timer-wrap">
        <div class="timer-icon">⏱</div>
        <div class="timer-val" id="timer-disp">45:00</div>
      </div>
      <button class="header-submit-btn" onclick="askSubmit()">Submit Test</button>
    </div>
  </div>
  <div class="progress-strip">
    <div class="progress-fill" id="prog-fill" style="width:0%"></div>
  </div>

  <div class="test-body">
    <!-- Sidebar -->
    <div class="sidebar">
      <div class="sidebar-box">
        <div class="sidebar-title">Question Navigator</div>
        <div class="nav-grid" id="nav-grid"></div>
      </div>
      <div class="sidebar-box">
        <div class="sidebar-title">Legend</div>
        <div class="legend">
          <div class="legend-item">
            <div class="legend-dot" style="background:var(--accent)"></div> Current
          </div>
          <div class="legend-item">
            <div class="legend-dot" style="background:var(--accent-light);border:1px solid var(--accent)"></div> Answered
          </div>
          <div class="legend-item">
            <div class="legend-dot" style="background:var(--bg);border:1px solid var(--border)"></div> Unanswered
          </div>
        </div>
      </div>
      <div class="sidebar-box">
        <div class="sidebar-title">Progress</div>
        <div id="sidebar-progress" style="font-size:13px;color:var(--muted)"></div>
      </div>
    </div>

```
<!-- Question -->
<div class="question-area" id="question-area"></div>
```

  </div>
</div>

<!-- ══════════ CONFIRM MODAL ══════════ -->

<div id="modal" class="modal-overlay hidden">
  <div class="modal-box">
    <div class="modal-icon" id="modal-icon">📋</div>
    <div class="modal-title" id="modal-title">Submit Test?</div>
    <div class="modal-body" id="modal-body"></div>
    <div class="modal-btns">
      <button class="btn btn-ghost" onclick="closeModal()">Go Back</button>
      <button class="btn btn-submit" onclick="submitTest()">Submit Now</button>
    </div>
  </div>
</div>

<!-- ══════════ RESULTS ══════════ -->

<div id="screen-results" class="hidden">
  <div class="results-header">
    <div class="results-lernvia">Lernvia · Frankfurt School AC-Test</div>
    <div class="results-title">Exam Results</div>
    <div class="results-sub" id="res-candidate"></div>
  </div>

  <div class="results-body">
    <!-- Score Banner -->
    <div class="score-banner">
      <div class="score-ring-wrap">
        <svg width="160" height="160" viewBox="0 0 160 160">
          <circle cx="80" cy="80" r="64" fill="none" stroke="#e8e6de" stroke-width="10"/>
          <circle cx="80" cy="80" r="64" fill="none" id="score-arc"
            stroke="#1a3a6b" stroke-width="10" stroke-linecap="round"
            stroke-dasharray="402" stroke-dashoffset="402"/>
        </svg>
        <div class="score-center">
          <div class="score-pct" id="res-pct">–</div>
          <div class="score-label">Score</div>
        </div>
      </div>
      <div class="score-details">
        <div class="score-verdict" id="res-verdict">–</div>
        <div class="score-desc" id="res-desc">–</div>
        <div class="score-meta">
          <div class="score-meta-item">
            <div class="score-meta-val" id="res-correct" style="color:var(--green)">–</div>
            <div class="score-meta-lbl">Correct</div>
          </div>
          <div class="score-meta-item">
            <div class="score-meta-val" id="res-wrong" style="color:var(--red)">–</div>
            <div class="score-meta-lbl">Wrong</div>
          </div>
          <div class="score-meta-item">
            <div class="score-meta-val" id="res-skipped" style="color:var(--muted)">–</div>
            <div class="score-meta-lbl">Skipped</div>
          </div>
          <div class="score-meta-item">
            <div class="score-meta-val" id="res-time" style="color:var(--accent)">–</div>
            <div class="score-meta-lbl">Time</div>
          </div>
        </div>
      </div>
    </div>

```
<!-- Topic Breakdown -->
<div class="section-hd">Performance by Topic</div>
<div class="breakdown-grid" id="breakdown-grid"></div>

<!-- Question Review -->
<div class="section-hd">Question Review</div>
<div class="review-list" id="review-list"></div>

<div class="results-footer">
  <button class="btn btn-ghost" onclick="restartTest()">Restart Test</button>
  <button class="btn btn-primary" onclick="window.print()">Print Results</button>
</div>
```

  </div>
</div>

<script>
// ════════════════════════════════════════════════
// QUESTIONS
// ════════════════════════════════════════════════
const Q = [
  // ALGEBRA
  { id:1, topic:'Algebra', type:'mc',
    text:'Let a and b be real numbers. Which expression is equivalent to (a + 2b)²?',
    opts:['a² + 4ab + 4b²','a² + 2ab + 4b²','a² + 4b²','a² + 2ab + 2b²'],
    correct:0, exp:'(a+2b)² = a² + 2·a·2b + (2b)² = a² + 4ab + 4b²' },

  { id:2, topic:'Algebra', type:'mc',
    text:'Simplify the expression (5x − 10) / (x² − 2x) for x ∉ {0, 2}.',
    opts:['5/x','5/(x−2)','(3x−10)/x²','Cannot be simplified'],
    correct:0, exp:'Factor: 5(x−2) / x(x−2) = 5/x' },

  { id:3, topic:'Algebra', type:'mc',
    text:'Which expression corresponds to (3a − 2b)²?',
    opts:['9a² − 12ab + 4b²','9a² − 6ab + 4b²','9a² + 4b²','9a² − 4b²'],
    correct:0, exp:'(3a−2b)² = 9a² − 2·3a·2b + 4b² = 9a² − 12ab + 4b²' },

  { id:4, topic:'Algebra', type:'mc',
    text:'Let a and b be real numbers. Which expression corresponds to max(a,b) − min(a,b)?',
    opts:['|b − a|','−|a − b|','(a+b+|a−b|)/2','(a+b−|a−b|)/2'],
    correct:0, exp:'max(a,b) − min(a,b) = |a−b| = |b−a| (always non-negative)' },

  // QUADRATICS
  { id:5, topic:'Quadratics', type:'free',
    text:'Compute the sum of the solutions of the quadratic equation 7x² + 14x = 19.',
    correct:'-2', exp:'Rewrite: 7x²+14x−19=0. By Vieta\'s: sum = −14/7 = −2' },

  { id:6, topic:'Quadratics', type:'free',
    text:'The parabola y = x² − 5x + 4 is given. Determine the sum of the x-values of the two zeros.',
    correct:'5', exp:'By Vieta\'s formulas: sum of roots = 5/1 = 5 (roots are x=1 and x=4)' },

  { id:7, topic:'Quadratics', type:'free',
    text:'Calculate the product of the solutions of the absolute value equation |2x − 1| = 5.',
    correct:'-3', exp:'2x−1=5 → x=3; 2x−1=−5 → x=−2. Product = 3·(−2) = −6. Wait: recheck: x=3 and x=−2. Product=−6.' },

  { id:8, topic:'Quadratics', type:'mc',
    text:'How many real solutions does x² − 4x + 5 = 0 have?',
    opts:['None (discriminant < 0)','Exactly one','Two distinct solutions','Infinitely many'],
    correct:0, exp:'D = 16 − 20 = −4 < 0 → no real solutions' },

  // LOGARITHMS
  { id:9, topic:'Logarithms', type:'free',
    text:'Calculate log₂(32) − log₃(81).',
    correct:'1', exp:'log₂(32)=5 (2⁵=32); log₃(81)=4 (3⁴=81). Result: 5−4=1' },

  { id:10, topic:'Logarithms', type:'free',
    text:'Calculate log₄(64).',
    correct:'3', exp:'4³ = 64, so log₄(64) = 3' },

  { id:11, topic:'Logarithms', type:'mc',
    text:'Which expression is equivalent to log(a²b) − log(ab²)?',
    opts:['log(a/b)','log(ab)','2·log(a/b)','log(a²/b²)'],
    correct:0, exp:'log(a²b/ab²) = log(a/b)' },

  { id:12, topic:'Logarithms', type:'free',
    text:'Solve for x: 3^x = 243.',
    correct:'5', exp:'3⁵ = 243, so x = 5' },

  // EXPONENTS & ROOTS
  { id:13, topic:'Exponents & Roots', type:'mc',
    text:'Let a > 0. Which expression corresponds to √(a · √(a³))?',
    opts:['⁴√(a⁵)','⁴√(a³)','√a','a'],
    correct:0, exp:'√(a³)=a^(3/2). a·a^(3/2)=a^(5/2). √(a^(5/2))=a^(5/4)=⁴√(a⁵)' },

  { id:14, topic:'Exponents & Roots', type:'mc',
    text:'Simplify: 8^(2/3) · 4^(1/2).',
    opts:['8','4','12','16'],
    correct:0, exp:'8^(2/3)=(∛8)²=4; 4^(1/2)=2; 4·2=8' },

  { id:15, topic:'Exponents & Roots', type:'mc',
    text:'Which expression equals ⁴√(x⁶) for x > 0?',
    opts:['x^(3/2)','x^(2/3)','x²','x^(4/6)'],
    correct:0, exp:'⁴√(x⁶) = x^(6/4) = x^(3/2)' },

  { id:16, topic:'Exponents & Roots', type:'free',
    text:'Solve: 2^x = 512.',
    correct:'9', exp:'2⁹ = 512, so x = 9' },

  // FUNCTIONS
  { id:17, topic:'Functions', type:'free',
    text:'Let f(x) = x² − 1 and g(x) = −2/x. Calculate f(g(4)).',
    correct:'-3/4', exp:'g(4)=−1/2. f(−1/2)=(1/4)−1=−3/4' },

  { id:18, topic:'Functions', type:'mc',
    text:'The function f(x) = x² − 6x + 9 has a zero at x =',
    opts:['x = 3 (double zero)','x = ±3','x = 6','x = 0 and x = 6'],
    correct:0, exp:'f(x)=(x−3)² → double zero at x=3' },

  { id:19, topic:'Functions', type:'free',
    text:'Let f(x) = 2x + 3 and g(x) = x². Calculate g(f(2)).',
    correct:'49', exp:'f(2)=7. g(7)=49' },

  // COMBINATORICS
  { id:20, topic:'Combinatorics', type:'free',
    text:'How many possibilities are there to place 4 different cars next to each other (order matters)?',
    correct:'24', exp:'4! = 4·3·2·1 = 24' },

  { id:21, topic:'Combinatorics', type:'free',
    text:'A PIN consists of 4 digits (0–9, repetition allowed). How many different PINs exist?',
    correct:'10000', exp:'10⁴ = 10 000' },

  { id:22, topic:'Combinatorics', type:'mc',
    text:'In how many ways can 6 students be arranged in a row?',
    opts:['720','120','36','36'],
    correct:0, exp:'6! = 720' },

  // PROBABILITY
  { id:23, topic:'Probability', type:'free',
    text:'You toss two fair coins. What is the probability of getting "tails" on both coins? (as a fraction)',
    correct:'1/4', exp:'P = 1/2 · 1/2 = 1/4' },

  { id:24, topic:'Probability', type:'mc',
    text:'Events A and B are independent with P(A) = 0.3 and P(B) = 0.5. What is P(A ∩ B)?',
    opts:['0.15','0.8','0.35','0.2'],
    correct:0, exp:'P(A∩B) = P(A)·P(B) = 0.3·0.5 = 0.15' },

  { id:25, topic:'Probability', type:'mc',
    text:'A bag contains 4 red and 6 blue balls. One is drawn randomly. What is P(red)?',
    opts:['2/5','3/5','4/6','1/4'],
    correct:0, exp:'P(red) = 4/10 = 2/5' },

  // ABSOLUTE VALUE
  { id:26, topic:'Absolute Value', type:'free',
    text:'Calculate the product of all zeros of (x + 4)(x² − 9).',
    correct:'36', exp:'Zeros: x=−4, x=3, x=−3. Product=(−4)·3·(−3)=36' },

  { id:27, topic:'Absolute Value', type:'free',
    text:'Calculate the product of the solutions of |4x − 2| = 10.',
    correct:'-3', exp:'4x−2=10→x=3; 4x−2=−10→x=−2. Product=3·(−2)=−6. Check: x=3 and x=−1. 4(3)−2=10✓; 4(−1)−2=−6, |−6|≠10. Recheck: 4x=12→x=3; 4x=−8→x=−2. Product=3·(−2)=−6.' },

  { id:28, topic:'Absolute Value', type:'mc',
    text:'How many solutions does |5x + 10| = 0 have?',
    opts:['Exactly one (x = −2)','None','Two','Infinitely many'],
    correct:0, exp:'|5x+10|=0 → 5x+10=0 → x=−2. Exactly one solution.' },

  // SERIES & GROWTH
  { id:29, topic:'Series & Growth', type:'free',
    text:'What is the value of the sum 1 + 2 + 3 + … + 6?',
    correct:'21', exp:'n(n+1)/2 = 6·7/2 = 21' },

  { id:30, topic:'Series & Growth', type:'mc',
    text:'A quantity y develops as y(t) = 5 · 2^(t/3). At what time t has y doubled compared to t = 0?',
    opts:['t = 3','t = 2','t = 5','t = 6'],
    correct:0, exp:'2^(t/3)=2 → t/3=1 → t=3' },
];

// Fix answer for Q7
Q[6].correct = '-6';
Q[6].exp = '2x−1=5 → x=3; 2x−1=−5 → x=−2. Product = 3·(−2) = −6';

// Fix answer for Q27
Q[26].correct = '-6';
Q[26].exp = '4x−2=10 → x=3; 4x−2=−10 → x=−2. Product = 3·(−2) = −6';

// ════════════════════════════════════════════════
// STATE
// ════════════════════════════════════════════════
let userName = '';
let answers = new Array(30).fill(null); // null = unanswered
let currentIdx = 0;
let timerSec = 45 * 60;
let timerInterval = null;
let startTime = null;
let testActive = false;

// ════════════════════════════════════════════════
// LOGIN
// ════════════════════════════════════════════════
function doLogin() {
  const name = document.getElementById('inp-name').value.trim();
  const pw = document.getElementById('inp-pw').value;
  const err = document.getElementById('login-err');

  if (!name) { document.getElementById('inp-name').focus(); return; }

  if (pw !== 'Lernvia 26') {
    err.classList.remove('hidden');
    document.getElementById('inp-pw').classList.add('err');
    document.getElementById('inp-pw').value = '';
    document.getElementById('inp-pw').focus();
    return;
  }

  userName = name;
  err.classList.add('hidden');
  document.getElementById('screen-login').classList.add('hidden');
  document.getElementById('screen-test').classList.remove('hidden');
  initTest();
}

// ════════════════════════════════════════════════
// TEST INIT
// ════════════════════════════════════════════════
function initTest() {
  answers = new Array(30).fill(null);
  currentIdx = 0;
  timerSec = 45 * 60;
  startTime = Date.now();
  testActive = true;
  buildNav();
  renderQ(0);
  startTimer();
}

function startTimer() {
  clearInterval(timerInterval);
  timerInterval = setInterval(() => {
    if (!testActive) return;
    timerSec--;
    updateTimer();
    if (timerSec <= 0) { clearInterval(timerInterval); submitTest(); }
  }, 1000);
}

function updateTimer() {
  const m = Math.floor(timerSec / 60);
  const s = timerSec % 60;
  const el = document.getElementById('timer-disp');
  el.textContent = `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`;
  el.className = 'timer-val';
  if (timerSec < 600) el.classList.add('warn');
  if (timerSec < 120) el.classList.remove('warn'), el.classList.add('danger');
}

// ════════════════════════════════════════════════
// NAV
// ════════════════════════════════════════════════
function buildNav() {
  const grid = document.getElementById('nav-grid');
  grid.innerHTML = '';
  Q.forEach((_, i) => {
    const d = document.createElement('div');
    d.className = 'nav-dot' + (i === 0 ? ' current' : '');
    d.id = `nd-${i}`;
    d.textContent = i + 1;
    d.onclick = () => goTo(i);
    grid.appendChild(d);
  });
  updateProgress();
}

function updateNav() {
  Q.forEach((_, i) => {
    const d = document.getElementById(`nd-${i}`);
    if (!d) return;
    d.className = 'nav-dot';
    if (answers[i] !== null) d.classList.add('answered');
    if (i === currentIdx) d.classList.add('current');
  });
  updateProgress();
}

function updateProgress() {
  const answered = answers.filter(a => a !== null).length;
  document.getElementById('prog-fill').style.width = `${(answered / 30) * 100}%`;
  document.getElementById('sidebar-progress').innerHTML =
    `<span style="font-family:'IBM Plex Mono',monospace;font-size:18px;font-weight:500;color:var(--accent)">${answered}</span><span style="color:var(--muted)"> / 30 answered</span>`;
}

// ════════════════════════════════════════════════
// RENDER QUESTION
// ════════════════════════════════════════════════
function renderQ(idx) {
  currentIdx = idx;
  updateNav();
  const q = Q[idx];
  const letters = ['A','B','C','D'];

  let answerHTML = '';
  if (q.type === 'mc') {
    const colClass = q.opts.length === 4 ? 'opts-2col' : 'opts-1col';
    answerHTML = `<div class="${colClass}">` +
      q.opts.map((o, i) => {
        const sel = answers[idx] === i ? ' sel' : '';
        return `<div class="opt${sel}" id="opt-${i}" onclick="pickOpt(${i})">
          <div class="opt-ltr">${letters[i]}</div>
          <div class="opt-txt">${o}</div>
        </div>`;
      }).join('') + '</div>';
  } else {
    const val = answers[idx] !== null ? answers[idx] : '';
    answerHTML = `<div class="free-row">
      <input id="free-inp" class="free-inp" type="text" placeholder="Your answer…"
        value="${val}"
        oninput="saveAns()"
        onkeydown="if(event.key==='Enter'&&${idx}<29)goTo(${idx+1})">
    </div>`;
  }

  document.getElementById('question-area').innerHTML = `
    <div class="q-card">
      <div class="q-card-header">
        <div class="q-tags">
          <div class="q-num-tag">Q ${idx + 1} / 30</div>
          <div class="q-topic-tag">${q.topic}</div>
          <div class="q-type-tag">${q.type === 'mc' ? 'Multiple Choice' : 'Free Input'}</div>
        </div>
        <div class="q-points">1 pt</div>
      </div>
      <div class="q-body">
        <div class="q-text">${q.text}</div>
        ${answerHTML}
      </div>
      <div class="q-footer">
        <div class="footer-left">
          ${answers[idx] !== null
            ? '<span style="color:var(--green);font-weight:500">✓ Answered</span>'
            : '<span style="color:var(--muted)">Not yet answered</span>'}
        </div>
        <div class="footer-right">
          <button class="btn btn-ghost" onclick="goTo(${idx-1})" ${idx===0?'disabled':''}>← Prev</button>
          ${idx < 29
            ? `<button class="btn btn-primary" onclick="goTo(${idx+1})">Next →</button>`
            : `<button class="btn btn-submit" onclick="askSubmit()">Submit Test ✓</button>`}
        </div>
      </div>
    </div>`;

  if (q.type === 'free') setTimeout(() => document.getElementById('free-inp')?.focus(), 60);
}

function pickOpt(i) {
  answers[currentIdx] = i;
  renderQ(currentIdx);
}

function saveAns() {
  const val = document.getElementById('free-inp')?.value.trim();
  answers[currentIdx] = val || null;
  updateNav();
}

function goTo(i) {
  if (i < 0 || i > 29) return;
  // save free input before leaving
  if (Q[currentIdx].type === 'free') {
    const val = document.getElementById('free-inp')?.value.trim();
    answers[currentIdx] = val || null;
  }
  renderQ(i);
}

// ════════════════════════════════════════════════
// SUBMIT
// ════════════════════════════════════════════════
function askSubmit() {
  const answered = answers.filter(a => a !== null).length;
  const unanswered = 30 - answered;
  const modal = document.getElementById('modal');
  document.getElementById('modal-body').innerHTML =
    `You have answered <strong>${answered}</strong> out of 30 questions.` +
    (unanswered > 0 ? ` <strong style="color:var(--red)">${unanswered} question${unanswered>1?'s':''} unanswered</strong>.` : '') +
    `<br><br>Once submitted, you cannot change your answers.`;
  modal.classList.remove('hidden');
}

function closeModal() {
  document.getElementById('modal').classList.add('hidden');
}

function submitTest() {
  closeModal();
  testActive = false;
  clearInterval(timerInterval);
  // save last free input
  if (Q[currentIdx].type === 'free') {
    const val = document.getElementById('free-inp')?.value.trim();
    answers[currentIdx] = val || null;
  }
  showResults();
}

// ════════════════════════════════════════════════
// RESULTS
// ════════════════════════════════════════════════
function showResults() {
  document.getElementById('screen-test').classList.add('hidden');
  document.getElementById('screen-results').classList.remove('hidden');

  // Score
  let correct = 0, wrong = 0, skipped = 0;
  Q.forEach((q, i) => {
    if (answers[i] === null) { skipped++; return; }
    const isOk = isCorrect(q, answers[i]);
    if (isOk) correct++; else wrong++;
  });
  const pct = Math.round((correct / 30) * 100);

  // Time
  const elapsed = Math.round((Date.now() - startTime) / 1000);
  const em = Math.floor(elapsed / 60), es = elapsed % 60;
  const timeStr = `${String(em).padStart(2,'0')}:${String(es).padStart(2,'0')}`;

  // Header
  document.getElementById('res-candidate').textContent =
    `${userName} · ${new Date().toLocaleDateString('en-GB', { day:'numeric', month:'long', year:'numeric' })}`;

  // Ring animation
  const arc = document.getElementById('score-arc');
  const circ = 402;
  const verdictData = getVerdict(pct);
  arc.style.stroke = verdictData.color;
  setTimeout(() => {
    arc.style.transition = 'stroke-dashoffset 1.4s cubic-bezier(.22,.68,0,1)';
    arc.style.strokeDashoffset = circ - (circ * pct / 100);
  }, 200);

  document.getElementById('res-pct').textContent = pct + '%';
  document.getElementById('res-verdict').textContent = verdictData.title;
  document.getElementById('res-verdict').style.color = verdictData.color;
  document.getElementById('res-desc').textContent = verdictData.desc;
  document.getElementById('res-correct').textContent = correct;
  document.getElementById('res-wrong').textContent = wrong;
  document.getElementById('res-skipped').textContent = skipped;
  document.getElementById('res-time').textContent = timeStr;

  // Topic breakdown
  const topics = {};
  Q.forEach((q, i) => {
    if (!topics[q.topic]) topics[q.topic] = { correct: 0, total: 0 };
    topics[q.topic].total++;
    if (answers[i] !== null && isCorrect(q, answers[i])) topics[q.topic].correct++;
  });

  document.getElementById('breakdown-grid').innerHTML = Object.entries(topics).map(([name, d]) => {
    const p = Math.round((d.correct / d.total) * 100);
    const col = p >= 70 ? '#15803d' : p >= 50 ? '#d97706' : '#b91c1c';
    return `<div class="breakdown-card">
      <div class="bd-topic">${name}</div>
      <div class="bd-bar-bg">
        <div class="bd-bar-fill" style="width:0%;background:${col}" data-w="${p}"></div>
      </div>
      <div class="bd-nums">
        <span style="color:${col};font-weight:500">${p}%</span>
        <span style="color:var(--muted)">${d.correct}/${d.total}</span>
      </div>
    </div>`;
  }).join('');

  // Animate bars
  setTimeout(() => {
    document.querySelectorAll('.bd-bar-fill').forEach(el => {
      el.style.transition = 'width 1.2s cubic-bezier(.22,.68,0,1)';
      el.style.width = el.dataset.w + '%';
    });
  }, 300);

  // Question review
  document.getElementById('review-list').innerHTML = Q.map((q, i) => {
    const ans = answers[i];
    const ok = ans !== null && isCorrect(q, ans);
    const statusCls = ans === null ? 'skip' : ok ? 'ok' : 'fail';
    const statusIcon = ans === null ? '–' : ok ? '✓' : '✗';
    const yourAnsText = ans === null ? 'Not answered'
      : q.type === 'mc' ? q.opts[ans] : ans;
    const correctAnsText = q.type === 'mc' ? q.opts[q.correct] : q.correct;
    const yourChipCls = ans === null ? 'ans-skipped' : ok ? 'ans-yours correct' : 'ans-yours';

    return `<div class="review-item">
      <div class="review-item-header" onclick="toggleReview(${i})">
        <div class="review-status ${statusCls}">${statusIcon}</div>
        <div style="flex:1">
          <div class="review-q-num">Q${i+1} · ${q.topic}</div>
          <div class="review-q-text">${q.text}</div>
        </div>
        <div class="review-arrow" id="rev-arrow-${i}">▼</div>
      </div>
      <div class="review-detail" id="rev-detail-${i}">
        <div class="review-ans-row">
          <span class="${yourChipCls}">Your answer: ${yourAnsText}</span>
          ${!ok ? `<span class="ans-correct">Correct: ${correctAnsText}</span>` : ''}
        </div>
        <div class="review-explanation">💡 ${q.exp}</div>
      </div>
    </div>`;
  }).join('');
}

function toggleReview(i) {
  const detail = document.getElementById(`rev-detail-${i}`);
  const arrow = document.getElementById(`rev-arrow-${i}`);
  const open = detail.classList.toggle('open');
  arrow.classList.toggle('open', open);
}

function isCorrect(q, ans) {
  if (q.type === 'mc') return ans === q.correct;
  return String(ans).trim().toLowerCase() === String(q.correct).trim().toLowerCase();
}

function getVerdict(pct) {
  if (pct >= 85) return {
    title: 'Excellent Performance',
    desc: 'Outstanding result — well above the typical Frankfurt School AC-Test benchmark. You are very well prepared.',
    color: '#15803d'
  };
  if (pct >= 70) return {
    title: 'Good Result',
    desc: 'Solid performance. You demonstrate a good grasp of the key mathematical areas. Minor review of weak topics recommended.',
    color: '#1a3a6b'
  };
  if (pct >= 55) return {
    title: 'Needs Improvement',
    desc: 'Approaching the benchmark. Focus on the topics where you lost the most points and practice regularly.',
    color: '#d97706'
  };
  return {
    title: 'More Practice Required',
    desc: 'The result suggests significant gaps in several areas. Consistent daily practice is strongly recommended before the real exam.',
    color: '#b91c1c'
  };
}

function restartTest() {
  document.getElementById('screen-results').classList.add('hidden');
  document.getElementById('screen-login').classList.remove('hidden');
  document.getElementById('inp-pw').value = '';
  document.getElementById('inp-name').value = '';
}
</script>

</body>
</html>