# brainScreener — Brain On BNB AI # Thirteen self-tests. No accounts, no tracking, no backend. # # This is the complete brainscreener bundle as a single file, so it can be read in # one fetch. 52 files, 9572 lines. # Download as a zip: https://brainonbnb.com/code/brainscreener.zip # Everything else: https://brainonbnb.com/code/index.txt # # No secrets are present: they are supplied at runtime through the environment. # MIT licensed. ============================================================================== === FILE: dashboard/brainscreener/404.html ============================================================================== Page not found — brainScreener
404

Page not found

This page does not exist or has been moved.

To the home page

============================================================================== === FILE: dashboard/brainscreener/adhd-result.html ============================================================================== Your results — ADHD screening · brainScreener
Results

ADHD screening

Date:
Anonymous results · generated client-side

Interpretation

Detailed profile

What does this mean?

Recommended next steps

    In an acute crisis

    If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

    • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
    • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
    • findahelpline.com – free, verified crisis helplines in 130+ countries
    • befrienders.org – worldwide emotional support network (Samaritans)
    Important note · no warranty. These results are a screening based on your self-report. They are no substitute for specialist medical, psychological or psychiatric diagnostics. A confirmed diagnosis requires a structured clinical interview, a detailed history and, where appropriate, further psychometric testing. Discuss the result with the doctor or psychologist treating you.

    Instruments used: ASRS v1.1 (Kessler et al., WHO), WURS-K (Retz-Junginger et al., 2002). Reference framework: DSM-5-TR (APA, 2022), ICD-11 (WHO, 2022).
    ============================================================================== === FILE: dashboard/brainscreener/adhd.html ============================================================================== ADHD test for adults — ASRS v1.1 + WURS-K · brainScreener
    ADHD screening for adults

    Structured self-test in three sections.

    This instrument combines the Adult ADHD Self-Report Scale (ASRS v1.1) by the WHO with the Wender Utah Rating Scale, short version (WURS-K) for the retrospective assessment of childhood symptoms — in line with the current standard of adult ADHD diagnostics under DSM-5-TR and ICD-11.

    • Durationapprox. 10–12 minutes
    • Items in total43 (6 + 12 + 25)
    • Resultsinstant, printable as PDF

    Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

    Allows the result to be anonymously matched to your file. It is written only onto the printed document and is not stored.

    Back to home page
    ============================================================================== === FILE: dashboard/brainscreener/aq50-result.html ============================================================================== Your results — AQ-50 · brainScreener
    Results

    AQ-50

    Date:
    Anonymous report · generated client-side

    Results

    Detailed profile

    What does this mean?

    Recommended next steps

      In an acute crisis

      If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

      • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
      • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
      • findahelpline.com – free, verified crisis helplines in 130+ countries
      • befrienders.org – worldwide emotional support network (Samaritans)
      Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

      Instrument used:
      ============================================================================== === FILE: dashboard/brainscreener/aq50.html ============================================================================== AQ-50 — Autism Screening · brainScreener

      • Duration
      • Items
      • Source

      Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

      Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

      Back to home page
      ============================================================================== === FILE: dashboard/brainscreener/assets/css/main.css ============================================================================== /* ======================================================================== brainScreener - Designsystem (BOBAI look) Palette: deep space navy, gold accent (#F0B90B), light ink Typografie: Space Grotesk Headlines, Inter Body Adapted with thanks from adhsiq.ch ======================================================================== */ /* The typefaces, served from this origin. This used to be an @import from Google, which the site's Content-Security-Policy (style-src 'self') blocked outright — so these pages loaded no webfont at all and quietly rendered in the system font while the rest of the site did not. Measured, not guessed: document.fonts was empty here and held Inter + Space Grotesk on the homepage. Declared here rather than imported: an @import is invisible to the preload scanner, and both files are almost certainly in cache already from the homepage. Both are variable fonts — one file carries every weight. */ @font-face{ font-family:'Inter'; font-style:normal; font-weight:100 900; font-display:swap; src:url('/fonts/inter-var.woff2') format('woff2'); } @font-face{ font-family:'Space Grotesk'; font-style:normal; font-weight:300 700; font-display:swap; src:url('/fonts/spacegrotesk-var.woff2') format('woff2'); } :root { --bg: #050510; --bg-alt: #0b0b20; --ink: #e8e9f4; --ink-soft: #b9bbd2; --ink-mute: #7b7d9e; --sage: #ffd54f; --sage-soft: rgba(240, 185, 11, 0.14); --gold: #F0B90B; --gold-soft: rgba(240, 185, 11, 0.35); --line: rgba(240, 185, 11, 0.12); --white: #10102a; --paper: #F7F5F1; --danger: #ff5a4f; --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.35); --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4), 0 2px 6px rgba(240, 185, 11, 0.04); --shadow-lg: 0 20px 50px rgba(0, 0, 0, 0.55), 0 0 80px rgba(240, 185, 11, 0.06); --radius-sm: 4px; --radius: 10px; --radius-lg: 18px; --serif: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif; --sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; --max: 1180px; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; } /* overflow-x: clip statt hidden — clippt horizontal, ohne position:sticky zu brechen */ html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; overflow-x: clip; } body { overflow-x: clip; } body { background: var(--bg); background-image: radial-gradient(ellipse 90% 40% at 50% -5%, rgba(240, 185, 11, 0.07), transparent 70%); background-attachment: fixed; color: var(--ink); font-family: var(--sans); font-size: 17px; line-height: 1.65; font-weight: 400; letter-spacing: 0.005em; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } h1, h2, h3, h4 { font-family: var(--serif); color: var(--ink); letter-spacing: -0.02em; line-height: 1.15; margin: 0 0 0.5em 0; font-weight: 700; } h1 { font-size: clamp(2.2rem, 4.5vw, 3.6rem); } h2 { font-size: clamp(1.7rem, 3vw, 2.4rem); } h3 { font-size: clamp(1.25rem, 2vw, 1.5rem); } h4 { font-size: 1.1rem; font-weight: 600; font-family: var(--sans); letter-spacing: 0.02em; text-transform: uppercase; color: var(--ink-soft); } p { margin: 0 0 1em 0; color: var(--ink-soft); } a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--gold); text-underline-offset: 4px; text-decoration-thickness: 1.5px; transition: color .2s; } a:hover { color: var(--gold); } img { max-width: 100%; height: auto; display: block; } /* Anker-Sprünge landen unter dem sticky Header — Ziel um Headerhöhe versetzen */ [id] { scroll-margin-top: 84px; } .container { max-width: var(--max); margin: 0 auto; padding: 0 28px; } .container-narrow { max-width: 760px; margin: 0 auto; padding: 0 28px; } /* ====================== HEADER / NAV ============================ */ .site-header { position: sticky; top: 0; z-index: 50; background: rgba(5, 5, 16, 0.88); backdrop-filter: saturate(120%) blur(24px); -webkit-backdrop-filter: saturate(120%) blur(24px); border-bottom: 1px solid var(--line); } .nav { display: flex; align-items: center; justify-content: space-between; padding: 18px 0; } .brand { font-family: var(--serif); font-size: 1.4rem; letter-spacing: 0.02em; text-decoration: none; color: var(--ink); display: flex; align-items: center; gap: 10px; } .brand-mark { width: 28px; height: 28px; border-radius: 50%; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='14' fill='%23101026'/%3E%3Ccircle cx='16' cy='16' r='13.5' fill='none' stroke='rgba(240,185,11,0.35)' stroke-width='1'/%3E%3Ccircle cx='12' cy='12' r='5' fill='%23F0B90B'/%3E%3Ccircle cx='20' cy='20' r='3' fill='%23ffd54f'/%3E%3C/svg%3E") center / contain no-repeat; box-shadow: 0 0 14px rgba(240, 185, 11, 0.25); } .brand-text strong { font-weight: 700; background: linear-gradient(135deg, var(--gold), var(--sage)); background-clip: text; -webkit-background-clip: text; color: transparent; } .brand-text span { color: var(--ink-mute); margin-left: 4px; font-size: 0.85em; } .nav-links { display: flex; gap: 28px; align-items: center; } .nav-links a { text-decoration: none; color: var(--ink-soft); font-size: 0.95rem; } .nav-links a:hover { color: var(--gold); } /* Back-Button im brainonbnb-Stil (identisch zu Worldcup/NFT-Pages) */ .back-btn { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 8px; background: rgba(240,185,11,.08); border: 1px solid rgba(240,185,11,.2); color: var(--gold) !important; font-size: 12px; font-weight: 600; text-decoration: none; letter-spacing: .3px; transition: transform .2s ease, background .2s, border-color .2s; white-space: nowrap; } .back-btn:hover { transform: translateX(-2px); background: rgba(240,185,11,.15); border-color: rgba(240,185,11,.4); color: var(--gold); } .back-btn span { font-size: 14px; line-height: 1; } /* Sprachumschalter */ .lang-switch { display: flex; align-items: center; gap: 7px; font-size: 0.8rem; letter-spacing: 0.06em; padding-left: 20px; border-left: 1px solid var(--line); } .lang-switch a { text-decoration: none; color: var(--ink-mute); } .lang-switch a:hover { color: var(--gold); } .lang-switch .lang-cur { color: var(--ink); font-weight: 600; } .lang-switch .lang-sep { color: var(--line); } @media (max-width: 640px) { .nav-links { gap: 16px; } .nav-links > a { display: none; } /* Menüpunkte aus */ .nav-links > a.back-btn { display: inline-flex; } /* Dashboard-Link bleibt */ .brand-text span { display: none; } /* "Screening"-Sublabel aus — Header bleibt ruhig */ } /* ====================== HERO ==================================== */ .hero { padding: 80px 0 60px; position: relative; } .hero-grid { display: grid; grid-template-columns: 1.05fr 1fr; gap: 64px; align-items: center; } @media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; gap: 40px; } .hero { padding: 50px 0 30px; } } .eyebrow { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.18em; color: var(--gold); font-weight: 600; margin-bottom: 18px; display: inline-block; } .hero h1 { margin-bottom: 22px; } .hero p.lead { font-size: 1.18rem; color: var(--ink-soft); max-width: 540px; } .hero-art { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-lg), 0 0 60px rgba(240, 185, 11, 0.12); background: var(--bg-alt); border: 1px solid var(--line); aspect-ratio: 3 / 2; } .hero-art img { width: 100%; height: 100%; object-fit: cover; } /* ====================== BUTTONS ================================= */ .btn { display: inline-flex; align-items: center; gap: 10px; padding: 14px 28px; border-radius: 999px; font-family: var(--sans); font-size: 0.98rem; font-weight: 500; text-decoration: none; border: 1.5px solid transparent; cursor: pointer; transition: all .18s ease; line-height: 1; } .btn-primary { background: linear-gradient(135deg, var(--gold), #e0a800); color: #050510; font-weight: 700; box-shadow: 0 2px 20px rgba(240, 185, 11, 0.2); } .btn-primary:hover { transform: translateY(-1px); box-shadow: 0 4px 32px rgba(240, 185, 11, 0.35); } .btn-outline { background: transparent; color: var(--gold); border-color: rgba(240, 185, 11, 0.45); } .btn-outline:hover { background: rgba(240, 185, 11, 0.08); border-color: var(--gold); color: var(--gold); } .btn-ghost { background: transparent; color: var(--ink-soft); } .btn-ghost:hover { color: var(--ink); } .btn-lg { padding: 16px 34px; font-size: 1.02rem; } .btn-row { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 28px; } /* ====================== TEST CARDS ============================== */ .tests { padding: 60px 0 80px; } .tests-head { text-align: center; margin-bottom: 56px; } .tests-head p { max-width: 580px; margin: 0 auto; } .test-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; } @media (max-width: 800px) { .test-cards { grid-template-columns: 1fr; } } /* Testbibliothek: 3-spaltiges Grid für viele Karten + Kategorie-Gruppen */ .test-library { padding: 60px 0 80px; } .category-block { margin-bottom: 56px; } .category-block:last-child { margin-bottom: 0; } .category-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 22px; padding-bottom: 14px; border-bottom: 1px solid var(--line); gap: 16px; flex-wrap: wrap; } .category-head h2 { margin: 0; font-size: 1.7rem; } .category-head .category-sub { color: var(--ink-mute); font-size: 0.95rem; margin: 0; } .test-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; } @media (max-width: 980px) { .test-grid { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 600px) { .test-grid { grid-template-columns: 1fr; } } .card.card-compact .card-img { aspect-ratio: 16 / 10; } .card.card-compact .card-body { padding: 22px 24px 24px; } .card.card-compact h3 { font-size: 1.25rem; margin-bottom: 8px; } .card.card-compact p { font-size: 0.93rem; line-height: 1.55; } .card.card-compact .meta-list { font-size: 0.82rem; margin: 8px 0 16px; } .card.card-compact .btn { padding: 10px 20px; font-size: 0.92rem; } /* Featured-Tests (ADHS + IQ) hervorgehoben oben */ .featured-tests { padding: 50px 0 30px; } .featured-tests .test-cards { grid-template-columns: repeat(3, 1fr); } @media (max-width: 980px) { .featured-tests .test-cards { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 640px) { .featured-tests .test-cards { grid-template-columns: 1fr; } } .card { background: rgba(12, 12, 28, 0.85); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); display: flex; flex-direction: column; transition: transform .25s ease, box-shadow .25s ease; } .card:hover { transform: translateY(-3px); box-shadow: 0 8px 32px rgba(240, 185, 11, 0.07), var(--shadow-md); border-color: rgba(240, 185, 11, 0.22); } .card-img { aspect-ratio: 16 / 11; background: var(--bg-alt); overflow: hidden; border-bottom: 1px solid var(--line); } .card-img img { width: 100%; height: 100%; object-fit: cover; } .card-body { padding: 28px 30px 30px; flex: 1; display: flex; flex-direction: column; } .card .meta { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.18em; color: var(--gold); font-weight: 600; margin-bottom: 8px; } .card h3 { margin-bottom: 10px; } .card p { font-size: 0.97rem; } .card ul.meta-list { list-style: none; padding: 0; margin: 10px 0 22px; font-size: 0.88rem; color: var(--ink-mute); } .card ul.meta-list li { padding: 6px 0; border-bottom: 1px dashed var(--line); display: flex; justify-content: space-between; } .card ul.meta-list li:last-child { border-bottom: none; } .card .btn { align-self: flex-start; margin-top: auto; } /* ====================== INFO / METHOD SECTION =================== */ .method { background: var(--bg-alt); padding: 80px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); } .method-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; } @media (max-width: 900px) { .method-grid { grid-template-columns: 1fr; } } .method-img { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-md); aspect-ratio: 1 / 1; max-width: 480px; } .method-img img { width: 100%; height: 100%; object-fit: cover; } .method ul { list-style: none; padding: 0; margin: 24px 0 0; display: grid; gap: 14px; } .method li { padding-left: 28px; position: relative; color: var(--ink-soft); font-size: 1.02rem; } .method li:before { content: ""; position: absolute; left: 0; top: 0.65em; width: 14px; height: 1.5px; background: var(--gold); } /* ====================== DISCLAIMER ============================== */ .disclaimer { padding: 56px 0; background: var(--bg); } .disclaimer-box { border: 1px solid var(--line); border-left: 3px solid var(--gold); padding: 28px 32px; border-radius: var(--radius); background: var(--white); box-shadow: var(--shadow-sm); } .disclaimer-box h4 { color: var(--ink); margin-bottom: 10px; } .disclaimer-box p { font-size: 0.95rem; margin-bottom: 8px; } .disclaimer-box p:last-child { margin-bottom: 0; } /* ====================== FOOTER ================================== */ .site-footer { padding: 50px 0 40px; background: #08081a; color: var(--ink-mute); border-top: 1px solid var(--line); margin-top: 60px; } .site-footer .container { display: flex; justify-content: space-between; gap: 28px; flex-wrap: wrap; } .site-footer a { color: var(--ink-soft); text-decoration-color: var(--gold); } .site-footer a:hover { color: var(--gold); } .site-footer .brand { color: var(--ink); } .site-footer .brand-text span { color: var(--ink-mute); } .site-footer small { color: var(--ink-mute); font-size: 0.85rem; line-height: 1.7; } /* ====================== TEST UI ================================= */ .test-shell { padding: 40px 0 80px; } .test-progress { position: sticky; top: 65px; z-index: 30; background: var(--bg); padding: 18px 0 20px; border-bottom: 1px solid var(--line); margin-bottom: 40px; } .progress-bar { height: 3px; background: var(--line); border-radius: 2px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, var(--sage), var(--gold)); transition: width .35s ease; width: 0%; } .progress-label { display: flex; justify-content: space-between; font-size: 0.86rem; color: var(--ink-mute); margin-bottom: 10px; letter-spacing: 0.02em; } .test-intro { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 44px 48px; box-shadow: var(--shadow-sm); margin-bottom: 30px; } @media (max-width: 640px) { .test-intro { padding: 30px 24px; } } .test-intro h1 { margin-bottom: 8px; } .test-intro .eyebrow { margin-bottom: 22px; } .section-banner { background: linear-gradient(135deg, rgba(240, 185, 11, 0.10), rgba(12, 12, 28, 0.9)); color: var(--ink); border: 1px solid rgba(240, 185, 11, 0.25); padding: 26px 32px; border-radius: var(--radius); margin: 30px 0 24px; } .section-banner h2 { color: var(--gold); margin-bottom: 6px; font-size: 1.5rem; } .section-banner p { color: var(--ink-soft); margin: 0; font-size: 0.95rem; } /* ----- Item (Likert) ----- */ .item { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 28px 30px; margin-bottom: 14px; box-shadow: var(--shadow-sm); transition: border-color .2s ease; /* Beim Springen zu einer offenen Frage (Engine ruft scrollIntoView) darf die Frage nicht unter der klebenden Kopf-/Fortschrittsleiste landen. */ scroll-margin-top: 140px; scroll-margin-bottom: 24px; } .item.is-answered { border-color: rgba(240, 185, 11, 0.4); } .item-num { font-size: 0.78rem; color: var(--gold); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 8px; } .item-q { font-family: var(--serif); font-size: 1.22rem; line-height: 1.4; color: var(--ink); margin-bottom: 22px; font-weight: 500; } .likert { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; } .likert.cols-2 { grid-template-columns: repeat(2, 1fr); } .likert.cols-3 { grid-template-columns: repeat(3, 1fr); } .likert.cols-4 { grid-template-columns: repeat(4, 1fr); } .likert.cols-6 { grid-template-columns: repeat(6, 1fr); } .likert.cols-7 { grid-template-columns: repeat(7, 1fr); } @media (max-width: 640px) { .likert, .likert.cols-2, .likert.cols-3, .likert.cols-4, .likert.cols-5, .likert.cols-6, .likert.cols-7 { grid-template-columns: 1fr; gap: 6px; } } .likert label { position: relative; cursor: pointer; background: rgba(255, 255, 255, 0.04); border: 1.5px solid transparent; border-radius: var(--radius-sm); padding: 14px 12px; text-align: center; font-size: 0.88rem; line-height: 1.3; color: var(--ink-soft); transition: all .15s ease; display: flex; align-items: center; justify-content: center; min-height: 64px; } .likert label:hover { background: rgba(240, 185, 11, 0.10); color: var(--ink); } .likert input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; } .likert input[type="radio"]:checked + span, .likert label.is-selected { /* fallback */ } .likert label.is-selected, .likert label:has(input:checked) { background: linear-gradient(135deg, var(--gold), #e0a800); color: #050510; border-color: var(--gold); font-weight: 600; } /* ----- MCQ (IQ items) ----- */ .mcq { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 8px; } @media (max-width: 520px) { .mcq { grid-template-columns: 1fr; } } .mcq label { cursor: pointer; background: rgba(255, 255, 255, 0.04); border: 1.5px solid transparent; border-radius: var(--radius-sm); padding: 14px 18px; display: flex; align-items: center; gap: 12px; font-size: 1rem; color: var(--ink); transition: all .15s ease; min-height: 56px; } .mcq label:hover { background: rgba(240, 185, 11, 0.10); } .mcq input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; } .mcq label .opt-letter { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: var(--bg-alt); border: 1px solid var(--line); font-family: var(--serif); font-weight: 600; font-size: 0.95rem; flex-shrink: 0; } .mcq label:has(input:checked) { background: linear-gradient(135deg, var(--gold), #e0a800); color: #050510; border-color: var(--gold); } .mcq label:has(input:checked) .opt-letter { background: #050510; color: var(--gold); border-color: #050510; } .matrix-stim { display: flex; justify-content: center; align-items: center; padding: 24px 16px 28px; background: var(--paper); border-radius: var(--radius); margin-bottom: 8px; } .matrix-stim svg { max-width: 100%; height: auto; } .iq-options-svg { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-top: 8px; } /* Mobile: 3 Spalten behalten — kleinere Kacheln passend zur Stimulus-Grösse, kein Overflow */ @media (max-width: 520px) { .iq-options-svg { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; } .iq-options-svg label { padding: 8px; border-radius: 6px; } } .iq-options-svg label { cursor: pointer; background: var(--paper); border: 1.5px solid transparent; border-radius: var(--radius-sm); padding: 12px; display: flex; align-items: center; justify-content: center; aspect-ratio: 1 / 1; transition: all .15s ease; } .iq-options-svg label:hover { border-color: rgba(240, 185, 11, 0.5); } .iq-options-svg label svg { width: 100%; height: 100%; } .iq-options-svg input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; } .iq-options-svg label:has(input:checked) { background: var(--paper); border-color: var(--gold); box-shadow: 0 0 0 2px var(--gold), 0 0 18px rgba(240, 185, 11, 0.35); } .iq-options-svg label:has(input:checked) svg { filter: none; } /* ----- Action row ----- */ .actions-row { display: flex; justify-content: space-between; gap: 14px; margin-top: 36px; padding-top: 24px; border-top: 1px solid var(--line); } .actions-row .right { display: flex; gap: 12px; } /* ====================== RESULT PAGE ============================= */ .result-shell { padding: 50px 0 80px; } .result-card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 56px 60px; box-shadow: var(--shadow-md); margin-bottom: 30px; position: relative; } @media (max-width: 640px) { .result-card { padding: 32px 24px; } } .result-card:before { content: ""; position: absolute; top: 0; left: 60px; right: 60px; height: 3px; background: linear-gradient(90deg, var(--sage), var(--gold)); border-radius: 0 0 4px 4px; } .result-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 28px; padding-bottom: 22px; border-bottom: 1px solid var(--line); flex-wrap: wrap; gap: 12px; } .result-head h1 { font-size: 2.2rem; margin: 0; } .result-head .meta-info { font-size: 0.92rem; color: var(--ink-mute); text-align: right; } .score-big { display: flex; align-items: baseline; gap: 14px; margin: 18px 0 8px; min-width: 0; } .score-big .value { font-family: var(--serif); font-size: 4rem; line-height: 1; color: var(--ink); font-weight: 500; } /* mehrteilige Kennzahlen (BFI-2: fuenf T-Werte) kleiner, damit sie einzeilig bleiben */ .score-big .value.is-long { font-size: 2.1rem; letter-spacing: -0.01em; } .score-big .unit { font-size: 1rem; color: var(--ink-mute); } /* minmax(0, …): ohne das kann eine breite Kennzahl (z. B. BFI-2 "45/40/40/55/38") die erste Spalte aufblaehen, bis fuer die Grafik 0 px uebrig bleiben. */ .score-row { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 50px; align-items: center; } @media (max-width: 720px) { .score-row { grid-template-columns: minmax(0, 1fr); gap: 22px; } } .gauge { position: relative; aspect-ratio: 2 / 1; max-width: 360px; } .gauge svg { width: 100%; height: 100%; } .gauge.gauge-custom { aspect-ratio: auto; max-width: 380px; } .gauge.gauge-custom svg { height: auto; } .interpretation { background: var(--bg-alt); border-radius: var(--radius); padding: 24px 28px; margin: 24px 0; border-left: 3px solid var(--gold); } .interpretation h3 { margin-top: 0; } .interpretation p { font-size: 1rem; color: var(--ink-soft); margin-bottom: 8px; } .interpretation p:last-child { margin-bottom: 0; } .subscale-list { display: grid; gap: 16px; margin: 24px 0; } .subscale { border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 22px; background: var(--white); } .subscale-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; } .subscale-head strong { font-family: var(--serif); font-size: 1.15rem; font-weight: 500; } .subscale-head .val { color: var(--ink-soft); font-size: 0.95rem; font-variant-numeric: tabular-nums; } .subscale-bar { height: 6px; background: var(--bg-alt); border-radius: 3px; overflow: hidden; } .subscale-bar > div { height: 100%; background: linear-gradient(90deg, var(--sage), var(--gold)); transition: width .4s; } .subscale .note { font-size: 0.85rem; color: var(--ink-mute); margin-top: 8px; } .result-disclaimer { margin-top: 30px; padding: 22px 26px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-alt); font-size: 0.9rem; color: var(--ink-soft); } .result-disclaimer strong { color: var(--ink); } .print-bar { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 12px; } .print-bar .btn { min-width: 180px; justify-content: center; } .no-print { /* used to hide things while printing */ } /* ====================== TEST META CHIPS ========================= */ .test-tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 18px; } .test-tag { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.12em; padding: 4px 10px; border-radius: 999px; background: var(--bg-alt); color: var(--ink-soft); border: 1px solid var(--line); font-weight: 600; } .test-tag.tag-gold { background: rgba(240,185,11,0.10); color: var(--gold); border-color: var(--gold-soft); } .test-tag.tag-sage { background: rgba(255,213,79,0.08); color: var(--sage); border-color: rgba(255,213,79,0.22); } /* ====================== UTILITIES =============================== */ .center { text-align: center; } .muted { color: var(--ink-mute); } .small { font-size: 0.88rem; } .divider { height: 1px; background: var(--line); margin: 40px 0; border: none; } .spacer-sm { height: 16px; } .spacer-md { height: 32px; } .spacer-lg { height: 60px; } /* ====================== PATIENTENCODE-FELD ====================== */ .code-field { margin: 24px 0 6px; padding: 22px 24px; background: var(--bg-alt); border: 1px solid var(--line); border-left: 3px solid var(--gold); border-radius: var(--radius); } .code-field label { display: block; font-family: var(--sans); font-weight: 600; font-size: 0.92rem; letter-spacing: 0.02em; color: var(--ink); margin-bottom: 8px; } .code-field input[type="text"] { width: 100%; max-width: 320px; padding: 12px 16px; font-family: var(--sans); font-size: 1.02rem; background: var(--white); border: 1.5px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); transition: border-color .15s, box-shadow .15s; letter-spacing: 0.04em; } .code-field input[type="text"]::placeholder { color: var(--ink-mute); letter-spacing: 0; } .code-field input[type="text"]:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(240, 185, 11, 0.22); } /* ====================== CRISIS BOX =============================== */ .crisis-box { margin-top: 30px; padding: 22px 26px; background: linear-gradient(180deg, rgba(240, 185, 11, 0.10) 0%, rgba(240, 185, 11, 0.04) 100%); border: 1px solid var(--gold-soft); border-left: 4px solid var(--gold); border-radius: var(--radius); } .crisis-box h4 { color: var(--ink); margin: 0 0 10px; font-family: var(--sans); font-size: 0.92rem; text-transform: uppercase; letter-spacing: 0.12em; } .crisis-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 6px; font-size: 0.95rem; color: var(--ink); } .crisis-list li { padding-left: 16px; position: relative; } .crisis-list li:before { content: ""; position: absolute; left: 0; top: 0.7em; width: 8px; height: 1.5px; background: var(--gold); } /* ====================== PRINT HEADER / FOOTER =================== */ .print-header { display: none; } .print-footer { display: none; } .print-header .print-brand { display: flex; align-items: center; gap: 10px; font-family: var(--serif); font-size: 1.05rem; color: var(--ink); } .print-header .print-brand .brand-mark { width: 22px; height: 22px; border-radius: 50%; box-shadow: none; } .print-header .print-meta { font-size: 0.82rem; color: var(--ink-mute); } .print-footer { font-size: 0.78rem; color: var(--ink-mute); text-align: center; padding-top: 16px; border-top: 1px solid var(--line); margin-top: 36px; } /* ====================== IQ-TESTMODUS ============================ Waehrend des IQ-Tests soll eine Aufgabe komplett auf den Schirm passen — 40 Aufgaben x scrollen waere sonst muehsam und fehleranfaellig. Die Klasse setzt iq.js beim Start (und beim Fortsetzen). */ .iq-testing .site-footer { display: none; } .iq-testing .test-shell { padding-top: 14px; padding-bottom: 14px; } .iq-testing #itemEl { margin-bottom: 12px; padding: 20px 26px; } .iq-testing #itemStimulus { margin: 8px 0 12px !important; } .iq-testing .matrix-stim { padding: 4px 0 6px; } .iq-testing #finishHint { margin: 6px 0 0; font-size: 0.78rem; line-height: 1.4; } .iq-testing #actionsRow { margin-top: 4px; } /* Ab 900px nebeneinander: Aufgabe links, Antworten rechts */ @media (min-width: 900px) { .iq-testing .container-narrow { max-width: 1060px; } .iq-testing #itemEl { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-areas: "kopf kopf" "frage frage" "stim opts"; column-gap: 40px; align-items: center; } .iq-testing #itemNum { grid-area: kopf; } .iq-testing #itemQuestion { grid-area: frage; } .iq-testing #itemStimulus { grid-area: stim; margin: 0 !important; } .iq-testing #itemOptions { grid-area: opts; margin-top: 0; } /* Aufgaben ohne Grafik (Zahlenreihen, verbale Analogien) haben nichts fuer die linke Spalte — dort einspaltig, sonst klafft daneben eine leere Flaeche. */ .iq-testing #itemEl:has(#itemStimulus:empty) { grid-template-columns: minmax(0, 1fr); grid-template-areas: "kopf" "frage" "opts"; max-width: 680px; } /* Kopf-, Fortschritts- und Buttonleiste sind hoehenkonstant (zusammen rund 495px). Der Rest steht Stimulus UND Antworten zur Verfuegung — beide werden gedeckelt, sonst treibt mal die Grafik, mal das Antwortraster die Seite ueber den Schirm. */ .iq-testing { --iq-frei: calc(100vh - 500px); } .iq-testing #itemStimulus { max-height: var(--iq-frei); } .iq-testing .matrix-stim svg { max-height: var(--iq-frei); width: auto; } .iq-testing .iq-options-svg { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: calc((var(--iq-frei) - 10px) / 2); max-width: 460px; margin-inline: auto; } .iq-testing .iq-options-svg label { aspect-ratio: auto; height: 100%; padding: 8px; } } /* Schmale Schirme: einspaltig. Hier ist die Hoehe knapp, also weg mit allem, was nicht zur Aufgabe gehoert — der Fusshinweis und die Domaenenangabe stehen ohnehin schon im Intro bzw. in der Auswertung. */ @media (max-width: 899px) { /* Einspaltig stehen Grafik und Antwortraster UNTEREINANDER, teilen sich also die Restflaeche. Die Aufgabengrafik bekommt den groesseren Anteil — sie muss im Detail erkennbar sein, die Antwortkacheln nur antippbar. */ .iq-testing { --iq-rest: calc(100vh - 480px); --iq-frei: calc(var(--iq-rest) * 0.58); } .iq-testing #itemOptions { max-height: calc(var(--iq-rest) * 0.42); } .iq-testing #finishHint { display: none; } /* "Show results" kostet mobil eine ganze Button-Zeile. iq.js blendet #btnNext auf der letzten Aufgabe aus — bis dahin genuegen Zurueck/Ueberspringen/Weiter. */ .iq-testing #actionsRow:has(#btnNext:not([hidden])) #btnFinish { display: none; } .iq-testing #itemNum { font-size: 0.72rem; line-height: 1.3; } .iq-testing #itemQuestion { font-size: 1rem; line-height: 1.35; margin-bottom: 6px; } .iq-testing #itemEl { padding: 10px 14px; margin-bottom: 6px; } .iq-testing #itemStimulus { margin: 4px 0 6px !important; max-height: var(--iq-frei); } .iq-testing .matrix-stim { padding: 0; } .iq-testing .matrix-stim svg { max-height: var(--iq-frei); width: auto; } /* Antwortkacheln an die freie Hoehe koppeln statt an die Spaltenbreite, sonst waechst das Raster mit der Bildschirmbreite aus dem Schirm heraus. */ .iq-testing .iq-options-svg { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: calc((var(--iq-rest) * 0.42 - 6px) / 2); gap: 6px; } .iq-testing .iq-options-svg label { aspect-ratio: auto; height: 100%; padding: 4px; } .iq-testing #progressWrap { padding-top: 6px; padding-bottom: 6px; } /* Buttonleiste kompakt, sonst frisst sie ein Drittel des Schirms */ .iq-testing #actionsRow { gap: 6px; margin-top: 0; } .iq-testing #actionsRow .btn { padding: 9px 14px; font-size: 0.85rem; } .iq-testing #actionsRow .right { gap: 6px; } } /* Flache Schirme (iPhone SE & Co. im Hochformat): Textantworten wieder zweispaltig — die IQ-Antworten sind kurz (Zahlen, einzelne Woerter), einspaltig verschenkt hier die Hoehe, die der Weiter-Button braucht. */ @media (max-width: 899px) and (max-height: 760px) { .iq-testing .mcq { grid-template-columns: repeat(2, 1fr); gap: 6px; } .iq-testing .mcq label { min-height: 42px; padding: 7px 10px; font-size: 0.88rem; gap: 8px; } .iq-testing .mcq label .opt-letter { width: 22px; height: 22px; font-size: 0.8rem; } .iq-testing #actionsRow .btn { padding: 7px 11px; font-size: 0.8rem; } .iq-testing #itemNum { font-size: 0.68rem; } } /* ====================== ACCESSIBILITY / FOCUS =================== */ *:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 3px; } .likert label:focus-within { box-shadow: 0 0 0 2px var(--gold); } .mcq label:focus-within { box-shadow: 0 0 0 2px var(--gold); } .iq-options-svg label:focus-within { box-shadow: 0 0 0 2px var(--gold); } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; } html { scroll-behavior: auto; } } /* ====================== MOBILE PORTRAIT (≤520px) ================ Korrekturen für Smartphone-Hochformat — gilt global. ================================================================ */ @media (max-width: 520px) { /* ---- Container & Body Rhythm ---- */ .container, .container-narrow { padding: 0 16px; } body { font-size: 16px; line-height: 1.6; } /* ---- Headlines passend skalieren ---- */ h1 { font-size: 1.85rem; line-height: 1.2; } h2 { font-size: 1.4rem; line-height: 1.2; } h3 { font-size: 1.15rem; } /* ---- Hero ---- */ .hero { padding: 34px 0 22px; } .hero p.lead { font-size: 1.02rem; } /* ---- Buttons im btn-row breit (besser tippbar) ---- */ .btn-row { flex-direction: column; gap: 10px; align-items: stretch; } .btn-row .btn { width: 100%; justify-content: center; } .btn-lg { padding: 14px 22px; font-size: 1rem; } /* ---- Site Header / Footer ---- */ .nav { padding: 14px 0; } .brand { font-size: 1.2rem; } .site-footer { padding: 36px 0 32px; margin-top: 40px; } .site-footer .container { flex-direction: column; gap: 14px; align-items: flex-start; } .site-footer small { font-size: 0.82rem; } /* ---- Cards / Method / Disclaimer ---- */ .tests { padding: 36px 0 50px; } .tests-head { margin-bottom: 32px; } .card-body { padding: 22px 22px 24px; } .method { padding: 50px 0; } .disclaimer { padding: 36px 0; } .disclaimer-box { padding: 22px 22px; } /* ============= TEST PAGES ============= */ .test-shell { padding: 24px 0 50px; } .test-progress { padding: 12px 0 14px; margin-bottom: 24px; top: 57px; } /* kompakter Mobile-Header */ .test-intro { padding: 26px 20px; border-radius: 14px; } .test-intro h1 { font-size: 1.75rem; } .section-banner { padding: 18px 20px; margin: 22px 0 18px; } .section-banner h2 { font-size: 1.2rem; } .section-banner p { font-size: 0.9rem; } .item { padding: 20px 18px; } .item-q { font-size: 1.08rem; line-height: 1.45; margin-bottom: 18px; } /* Actions-Row vertikal stapeln (Zurück oben, Weiter unten) */ .actions-row { flex-direction: column; gap: 10px; margin-top: 26px; padding-top: 20px; } .actions-row .right { width: 100%; flex-direction: column; gap: 10px; } /* IQ-Test (3 Buttons sichtbar): Next zuoberst, dann Show results, Skip zuunterst */ .actions-row .right #btnSkip { order: 3; } .actions-row .btn { width: 100%; justify-content: center; } /* Code-Field */ .code-field { padding: 18px 18px; } .code-field input[type="text"] { max-width: 100%; } /* ============= RESULT PAGE — der eigentliche Fix ============= */ .result-shell { padding: 26px 0 50px; } .result-card { padding: 24px 18px; border-radius: 14px; } .result-card:before { left: 24px; right: 24px; } /* Header: stapeln, links bündig */ .result-head { flex-direction: column; align-items: flex-start; gap: 10px; padding-bottom: 18px; margin-bottom: 20px; } .result-head h1 { font-size: 1.7rem; line-height: 1.15; } .result-head .meta-info { text-align: left; font-size: 0.85rem; line-height: 1.55; } /* Score */ .score-row { gap: 16px; } .score-big { gap: 10px; margin: 12px 0 6px; flex-wrap: wrap; align-items: baseline; } .score-big .value { font-size: 2.8rem; } .score-big .unit { font-size: 0.92rem; } .gauge { max-width: 100%; margin: 0 auto; } /* Interpretation / Disclaimer / Crisis */ .interpretation, .result-disclaimer, .crisis-box { padding: 18px 18px; margin-left: 0; margin-right: 0; } .interpretation { margin: 18px 0; } .interpretation h3 { font-size: 1.1rem; } .crisis-list { font-size: 0.9rem; } /* Subskalen — Label und Wert untereinander statt nebeneinander */ .subscale { padding: 14px 16px; } .subscale-head { flex-direction: column; align-items: flex-start; gap: 2px; margin-bottom: 10px; } .subscale-head strong { font-size: 1.02rem; line-height: 1.3; } .subscale-head .val { font-size: 0.86rem; } .subscale .note { font-size: 0.82rem; line-height: 1.5; } /* IQ-Verteilungs­diagramm — horizontal scrollbar, damit Achsen lesbar bleiben */ #distributionWrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-left: -4px; margin-right: -4px; padding: 0 4px 4px; } #distributionWrap svg { min-width: 520px; width: 100%; } /* Print-Bar — Buttons vertikal */ .print-bar { flex-direction: column; gap: 10px; margin-top: 18px; } .print-bar .btn { width: 100%; min-width: 0; } } /* ====================== PRINT STYLES (erweitert) =============== */ @media print { :root { --bg: #FFFFFF; --bg-alt: #FBFAF7; --ink: #14142b; --ink-soft: #3a3a52; --ink-mute: #6a6a85; --white: #FFFFFF; --line: #d8d8e2; --gold: #a67c00; --gold-soft: #e6d9a8; --sage: #a67c00; --sage-soft: #f2ead0; --paper: #FFFFFF; --shadow-sm: none; --shadow-md: none; --shadow-lg: none; } body { background: #FFFFFF !important; background-image: none !important; font-size: 10.5pt; color: #14142b; } .site-header, .site-footer, .no-print, .print-bar { display: none !important; } /* Layout container */ .result-shell { padding: 0; } .result-card { box-shadow: none; border: none; padding: 0; margin: 0; page-break-inside: auto; } .result-card:before { display: none; } /* Print header / footer */ .print-header { display: flex; justify-content: space-between; align-items: center; padding-bottom: 14px; border-bottom: 1.5px solid #14142b; margin-bottom: 22px; } .brand-text strong { background: none; -webkit-background-clip: initial; background-clip: initial; color: #14142b; } .interpretation { background: #FBFAF7; border-left-color: #a67c00; } .crisis-box { background: #FCF8EC !important; } .section-banner { background: #FBFAF7; color: #14142b; border: 1px solid #d8d8e2; } .section-banner h2 { color: #14142b; } .print-footer { display: block; } /* Header / Datum / Code */ .result-head { border-bottom: 1px solid #cdc6b8; padding-bottom: 14px; page-break-after: avoid; } .result-head h1 { font-size: 22pt; line-height: 1.1; } .result-head .meta-info { font-size: 9.5pt; line-height: 1.5; } .result-head .meta-info strong { font-weight: 600; } /* Scores */ .score-big .value { font-size: 36pt; } .gauge { max-width: 280px; } .score-row { gap: 24px; } /* Blocks */ .interpretation, .subscale, .crisis-box, .result-disclaimer { page-break-inside: avoid; box-shadow: none; } .interpretation { border-left-width: 3px; } .subscale { border: 1px solid #cdc6b8; } .subscale-bar { background: #eee; } .subscale-bar > div { background: #14142b; } .crisis-box { background: #FCF8EC !important; border: 1px solid #e6d9a8; border-left: 3px solid #a67c00; } .result-disclaimer { background: #FBFAF7; border: 1px solid #ddd; } /* Glockenkurve etc. */ #distributionWrap svg, .gauge svg { print-color-adjust: exact; -webkit-print-color-adjust: exact; } h1, h2, h3, h4 { page-break-after: avoid; color: #14142b; } h3 { font-size: 13pt; margin-top: 18pt; } ul, ol { page-break-inside: avoid; } a { color: #14142b; text-decoration: none; } @page { margin: 18mm 16mm 20mm 16mm; size: A4 portrait; } } ============================================================================== === FILE: dashboard/brainscreener/assets/js/adhs.js ============================================================================== // ADHS-Test - Controller (Rendering, Navigation, Persistenz, Auswertung) (function () { const D = window.ADHS_DATA; // UI-Strings: deutsche Defaults, übersetzte Datendateien liefern D.ui mit. const UI = Object.assign({ question: "Frage", answersCount: (a, t) => `${a} / ${t} Antworten`, sectionLabels: { A: "Abschnitt 1 von 3 · ASRS Part A", B: "Abschnitt 2 von 3 · ASRS Part B", W: "Abschnitt 3 von 3 · WURS-K" }, resetConfirm: "Wirklich alle bisherigen Antworten löschen und neu starten?", }, (D && D.ui) || {}); const STORAGE_KEY = "brainscreener.adhs.answers.v1"; const CODE_KEY = "brainscreener.adhs.code.v1"; const RESULT_KEY = "brainscreener.adhs.result.v1"; const intro = document.getElementById("intro"); const form = document.getElementById("adhsForm"); const progressWrap = document.getElementById("progressWrap"); const progressFill = document.getElementById("progressFill"); const progressText = document.getElementById("progressText"); const progressCount = document.getElementById("progressCount"); const actionsRow = document.getElementById("actionsRow"); const btnNext = document.getElementById("btnNext"); const btnBack = document.getElementById("btnBack"); const btnSubmit = document.getElementById("btnSubmit"); const missingNote = document.getElementById("missingNote"); const sectionEls = { A: { banner: document.querySelector('[data-section="A"]'), items: document.getElementById("sectionA") }, B: { banner: document.querySelector('[data-section="B"]'), items: document.getElementById("sectionB") }, W: { banner: document.querySelector('[data-section="W"]'), items: document.getElementById("sectionW") }, }; const TOTAL_ITEMS = D.ASRS.length + D.WURSK.length; let answers = loadAnswers(); let currentSection = "A"; document.getElementById("wurskIntro").textContent = D.WURSK_INTRO; // ---------- Storage ---------- function loadAnswers() { try { return JSON.parse(sessionStorage.getItem(STORAGE_KEY) || "{}"); } catch { return {}; } } function saveAnswers() { try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(answers)); } catch {} } // ---------- Rendering ---------- function buildLikertHTML(itemId, scale) { return scale.map((opt) => ` `).join(""); } function itemHTML(item, idx, scale) { return `
      ${UI.question} ${idx}
      ${item.text}
      ${buildLikertHTML(item.id, scale)}
      `; } function renderAll() { const partA = D.ASRS.filter(i => i.partA); const partB = D.ASRS.filter(i => !i.partA); sectionEls.A.items.innerHTML = partA.map((it, i) => itemHTML(it, i + 1, D.ASRS_LIKERT)).join(""); sectionEls.B.items.innerHTML = partB.map((it, i) => itemHTML(it, i + 1, D.ASRS_LIKERT)).join(""); sectionEls.W.items.innerHTML = D.WURSK.map((it, i) => itemHTML(it, i + 1, D.WURS_LIKERT)).join(""); form.addEventListener("change", onAnyChange); } function onAnyChange(e) { const input = e.target; if (input && input.type === "radio") { const id = input.name; const val = parseInt(input.value, 10); answers[id] = val; saveAnswers(); const itemEl = input.closest(".item"); if (itemEl) itemEl.classList.add("is-answered"); updateProgress(); hideMissing(); } } function hideMissing() { missingNote.hidden = true; } function updateProgress() { const answered = Object.keys(answers).length; const pct = Math.round((answered / TOTAL_ITEMS) * 100); progressFill.style.width = pct + "%"; progressCount.textContent = UI.answersCount(answered, TOTAL_ITEMS); progressText.textContent = UI.sectionLabels[currentSection]; } // ---------- Navigation ---------- function showSection(sec) { currentSection = sec; for (const key of Object.keys(sectionEls)) { const isActive = key === sec; sectionEls[key].banner.hidden = !isActive; sectionEls[key].items.hidden = !isActive; } btnBack.hidden = (sec === "A"); btnNext.hidden = (sec === "W"); btnSubmit.hidden = (sec !== "W"); updateProgress(); window.scrollTo({ top: 0, behavior: "smooth" }); } function sectionItemIds(sec) { if (sec === "A") return D.ASRS.filter(i => i.partA).map(i => i.id); if (sec === "B") return D.ASRS.filter(i => !i.partA).map(i => i.id); return D.WURSK.map(i => i.id); } function isSectionComplete(sec) { const ids = sectionItemIds(sec); return ids.every((id) => typeof answers[id] === "number"); } function focusFirstUnanswered(sec) { const ids = sectionItemIds(sec); for (const id of ids) { if (typeof answers[id] !== "number") { const el = form.querySelector(`.item[data-id="${id}"]`); if (el) { el.scrollIntoView({ behavior: "smooth", block: "center" }); el.style.outline = "2px solid var(--gold)"; setTimeout(() => { el.style.outline = ""; }, 1400); } break; } } } btnNext.addEventListener("click", () => { if (!isSectionComplete(currentSection)) { missingNote.hidden = false; focusFirstUnanswered(currentSection); return; } if (currentSection === "A") showSection("B"); else if (currentSection === "B") showSection("W"); }); btnBack.addEventListener("click", () => { if (currentSection === "W") showSection("B"); else if (currentSection === "B") showSection("A"); }); btnSubmit.addEventListener("click", () => { if (!isSectionComplete("W")) { missingNote.hidden = false; focusFirstUnanswered("W"); return; } const result = D.evaluate(answers); const probandCode = (sessionStorage.getItem(CODE_KEY) || "").trim(); const payload = { result, answers, probandCode, ts: new Date().toISOString(), }; try { sessionStorage.setItem(RESULT_KEY, JSON.stringify(payload)); } catch {} testInProgress = false; // unlock beforeunload // Sprachversion beibehalten: /brainscreener/adhs -> /brainscreener/adhd-result.html usw. location.href = location.pathname.replace(/[^/]*$/, "") + "adhd-result.html"; }); // ---------- beforeunload Warnung ---------- let testInProgress = false; window.addEventListener("beforeunload", (e) => { if (testInProgress && Object.keys(answers).length > 0 && Object.keys(answers).length < TOTAL_ITEMS) { e.preventDefault(); e.returnValue = ""; return ""; } }); // ---------- Reset ---------- // In-Page-Dialog statt window.confirm(): native Dialoge werden in manchen // In-App-Browsern (Telegram/X) stillschweigend geblockt. function showConfirm(message, okLabel, onOk) { let m = document.getElementById("bsConfirmModal"); if (!m) { m = document.createElement("div"); m.id = "bsConfirmModal"; m.setAttribute("role", "dialog"); m.setAttribute("aria-modal", "true"); m.style.cssText = "position:fixed;inset:0;z-index:2000;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(0,0,0,0.45);"; m.innerHTML = `

      `; document.body.appendChild(m); } m.querySelector("#bsConfirmMsg").textContent = message; const ok = m.querySelector("#bsConfirmOk"); const cancel = m.querySelector("#bsConfirmCancel"); ok.textContent = okLabel; cancel.textContent = UI.confirmCancel || "Cancel"; m.style.display = "flex"; const close = () => { m.style.display = "none"; ok.onclick = cancel.onclick = m.onclick = null; }; cancel.onclick = close; m.onclick = (e) => { if (e.target === m) close(); }; ok.onclick = () => { close(); onOk(); }; ok.focus(); } const btnReset = document.getElementById("btnReset"); if (Object.keys(answers).length > 0) { btnReset.hidden = false; btnReset.addEventListener("click", () => { showConfirm(UI.resetConfirm, UI.confirmResetOk || "Delete answers", () => { sessionStorage.removeItem(STORAGE_KEY); sessionStorage.removeItem(CODE_KEY); sessionStorage.removeItem(RESULT_KEY); answers = {}; location.reload(); }); }); } // ---------- Start ---------- const probandInput = document.getElementById("probandCode"); // restore code if previously entered const savedCode = sessionStorage.getItem(CODE_KEY) || ""; if (probandInput && savedCode) probandInput.value = savedCode; if (probandInput) { probandInput.addEventListener("input", () => { try { sessionStorage.setItem(CODE_KEY, probandInput.value); } catch {} }); } document.getElementById("btnStart").addEventListener("click", () => { if (probandInput) { try { sessionStorage.setItem(CODE_KEY, probandInput.value || ""); } catch {} } intro.hidden = true; form.hidden = false; actionsRow.hidden = false; progressWrap.hidden = false; testInProgress = true; renderAll(); showSection("A"); }); // Falls man wieder zur Seite kommt und Antworten existieren -> direkt fortsetzen if (Object.keys(answers).length > 0) { intro.hidden = true; form.hidden = false; actionsRow.hidden = false; progressWrap.hidden = false; testInProgress = true; renderAll(); // springe zur ersten Sektion mit Luecken if (!isSectionComplete("A")) showSection("A"); else if (!isSectionComplete("B")) showSection("B"); else showSection("W"); } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/charakter-result.js ============================================================================== // Charakterprofil — Ergebnis-Renderer (eigenes Layout, analog zu adhs-result / iq-result). // Liest sessionStorage[brainscreener.charakter.result.v1] und nutzt window.TEST_DATA.archetypes. (function () { const D = window.TEST_DATA; if (!D) { console.error("[charakter-result] TEST_DATA fehlt"); return; } const RESULT_KEY = "brainscreener.charakter.result.v1"; let payload = window.BS_PRINT ? BS_PRINT.loadPayload(RESULT_KEY) : null; if (!payload) { try { payload = JSON.parse(sessionStorage.getItem(RESULT_KEY) || "null"); } catch { payload = null; } } if (D.meta && D.meta.pageTitle) document.title = D.meta.pageTitle; const root = document.querySelector(".result-shell .container-narrow"); if (!payload) { const NU = (D.ui || {}); root.innerHTML = `

      ${NU.noResultTitle || "No result found"}

      ${NU.noResultText || "Please take the test first to receive a report."}

      ${NU.toTest || "Go to the test"}

      `; return; } const A = D.archetypes; const DIMS = D.dims; const { ts, probandCode } = payload; // Sprachneutrale Antworten in der Sprache dieser Seite neu auswerten // (ermöglicht Drucken der Auswertung in einer anderen Sprache). const result = (payload.answers && typeof D.evaluate === "function") ? D.evaluate(payload.answers) : payload.result; const { scores, order, dominant, balanced } = result; const LOCALE = document.documentElement.lang || "de-CH"; // ---- Datum / Code ---- const date = ts ? new Date(ts) : new Date(); setText("dateStr", date.toLocaleDateString(LOCALE, { day: "2-digit", month: "long", year: "numeric" }) + " · " + date.toLocaleTimeString(LOCALE, { hour: "2-digit", minute: "2-digit" })); const code = (probandCode || "").trim(); if (code) { const row = document.getElementById("codeRow"); if (row) row.hidden = false; setText("codeStr", code); } setText("verfahrensRef", D.meta.sources); // UI-Strings: deutsche Defaults; übersetzte charakter-data.js liefert D.resultUi mit. const RUI = Object.assign({ balancedTrait: "Ausgewogenes Profil", balancedName: "Ein ausgeglichenes Mischverhältnis", balancedIntro: "Ihr Profil ist bemerkenswert ausgewogen — kein Zug ragt deutlich heraus. Je nach Situation zeigen Sie verschiedene Seiten. Vermutlich erkennen Sie sich unten in mehreren Typen wieder.", domIntro: (dom, domPct, sec, secPct) => `Jeder Mensch trägt von allen vier Zügen etwas in sich — am stärksten zeigt sich bei Ihnen ${dom.name} (${domPct} %). ${dom.tagline} ` + `Danach folgt am ehesten ${sec.name} (${secPct} %). ` + `Das heisst nicht, dass Sie „so sind“ — es zeigt nur, welche Tendenz bei Ihnen am ehesten durchscheint.`, badgeTop: "ragt heraus", badgeDominant: "Ihr stärkster Zug", colExamples: "So zeigt es sich im Alltag", colStrengths: "Stärken", colTips: "Tipps & woran Sie arbeiten können", wheelBalanced: "ausgewogen", wheelDominant: "stärkster Zug", }, D.resultUi || {}); // ---- Hero (dominanter Zug + Intro) ---- if (balanced) { setText("domTrait", RUI.balancedTrait); setText("domName", RUI.balancedName); setHTML("domIntro", RUI.balancedIntro); } else { const dom = A[dominant]; const sec = A[order[1]]; setText("domTrait", dom.trait); setText("domName", dom.name); setHTML("domIntro", RUI.domIntro(dom, scores[dominant].pct, sec, scores[order[1]].pct)); } // ---- Farbrad ---- const wheel = document.getElementById("charWheel"); if (wheel) wheel.innerHTML = wheelSVG(); // ---- Balken (nach Ausprägung absteigend) ---- const bars = document.getElementById("charBars"); if (bars) { bars.innerHTML = order.map((k, i) => { const a = A[k], pct = scores[k].pct; const badge = (i === 0 && !balanced) ? `${RUI.badgeTop}` : ""; return `
      ${a.name} ${a.trait} ${badge} ${pct} %
      `; }).join(""); } // ---- Typ-Detailkarten (dominanter Zug zuerst) ---- const types = document.getElementById("charTypes"); if (types) { types.innerHTML = order.map((k, i) => { const a = A[k], pct = scores[k].pct; const isDom = (i === 0 && !balanced); const badge = isDom ? `${RUI.badgeDominant}` : ""; const li = (arr) => arr.map((x) => `
    • ${x}
    • `).join(""); return `

      ${a.name}

      ${a.trait} · ${pct} % ${badge}

      ${a.tagline}

      ${a.desc}

      ${RUI.colExamples}

        ${li(a.examples)}

      ${RUI.colStrengths}

        ${li(a.strengths)}

      ${RUI.colTips}

      `; }).join(""); } // ---- Print ---- const btnPrint = document.getElementById("btnPrint"); if (btnPrint) { if (window.BS_PRINT) BS_PRINT.attachPrint(btnPrint, RESULT_KEY); else btnPrint.addEventListener("click", () => window.print()); } // ---------- helpers ---------- function setText(id, v) { const el = document.getElementById(id); if (el && v != null) el.textContent = String(v); } function setHTML(id, v) { const el = document.getElementById(id); if (el && v != null) el.innerHTML = v; } function wheelSVG() { const cx = 80, cy = 80, r = 58, sw = 24; const C = 2 * Math.PI * r; const total = DIMS.reduce((s, d) => s + scores[d].pct, 0) || 1; let offset = 0, segs = ""; DIMS.forEach((d) => { const len = (scores[d].pct / total) * C; if (len > 0.5) { segs += ``; } offset += len; }); const centerTop = balanced ? "≈" : scores[order[0]].pct + "%"; const centerSub = balanced ? RUI.wheelBalanced : RUI.wheelDominant; const centerColor = balanced ? "var(--ink)" : A[order[0]].color; return ` ${segs} ${centerTop} ${centerSub} `; } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/adhs-data.js ============================================================================== // ADHD screening: ASRS v1.1 (WHO, 18 items) + WURS-K (25 items, retrospective) // Sources / references: // - Kessler RC et al. (2005), WHO Adult ADHD Self-Report Scale (ASRS) v1.1 // - Retz-Junginger P et al. (2002), Wender Utah Rating Scale Kurzform (WURS-K) // - DSM-5-TR (APA, 2022), ICD-11 (WHO, 2022) // // Response scale 0..4 for the ASRS: 0=Never 1=Rarely 2=Sometimes 3=Often 4=Very often // Response scale 0..4 for the WURS-K: 0=Does not apply 1=Mildly 2=Moderately 3=Clearly 4=Strongly window.ADHS_DATA = (function () { const ASRS_LIKERT = [ { v: 0, label: "Never" }, { v: 1, label: "Rarely" }, { v: 2, label: "Sometimes" }, { v: 3, label: "Often" }, { v: 4, label: "Very often" }, ]; const WURS_LIKERT = [ { v: 0, label: "Does not apply" }, { v: 1, label: "Mildly" }, { v: 2, label: "Moderately" }, { v: 3, label: "Clearly" }, { v: 4, label: "Strongly" }, ]; // -------- ASRS v1.1, official English original (Kessler/WHO) ---------- // dim: "I" = inattention, "H" = hyperactivity/impulsivity // partA = screening items (1..6). Official per-item cutoff (Kessler/WHO): // Items 1,2,3: marked from "Sometimes" / "Often" / "Very often" (threshold = 2) // Items 4,5,6: marked from "Often" / "Very often" (threshold = 3) // >=4 of 6 marked: highly consistent with ADHD in adults. const ASRS = [ { id: "A1", partA: true, dim: "I", th: 2, text: "How often do you have trouble wrapping up the final details of a project, once the challenging parts have been done?" }, { id: "A2", partA: true, dim: "I", th: 2, text: "How often do you have difficulty getting things in order when you have to do a task that requires organization?" }, { id: "A3", partA: true, dim: "I", th: 2, text: "How often do you have problems remembering appointments or obligations?" }, { id: "A4", partA: true, dim: "I", th: 3, text: "When you have a task that requires a lot of thought, how often do you avoid or delay getting started?" }, { id: "A5", partA: true, dim: "H", th: 3, text: "How often do you fidget or squirm with your hands or feet when you have to sit down for a long time?" }, { id: "A6", partA: true, dim: "H", th: 3, text: "How often do you feel overly active and compelled to do things, like you were driven by a motor?" }, { id: "B7", partA: false, dim: "I", text: "How often do you make careless mistakes when you have to work on a boring or difficult project?" }, { id: "B8", partA: false, dim: "I", text: "How often do you have difficulty keeping your attention when you are doing boring or repetitive work?" }, { id: "B9", partA: false, dim: "I", text: "How often do you have difficulty concentrating on what people say to you, even when they are speaking to you directly?" }, { id: "B10", partA: false, dim: "I", text: "How often do you misplace or have difficulty finding things at home or at work?" }, { id: "B11", partA: false, dim: "I", text: "How often are you distracted by activity or noise around you?" }, { id: "B12", partA: false, dim: "H", text: "How often do you leave your seat in meetings or other situations in which you are expected to remain seated?" }, { id: "B13", partA: false, dim: "H", text: "How often do you feel restless or fidgety?" }, { id: "B14", partA: false, dim: "H", text: "How often do you have difficulty unwinding and relaxing when you have time to yourself?" }, { id: "B15", partA: false, dim: "H", text: "How often do you find yourself talking too much when you are in social situations?" }, { id: "B16", partA: false, dim: "H", text: "When you're in a conversation, how often do you find yourself finishing the sentences of the people you are talking to, before they can finish them themselves?" }, { id: "B17", partA: false, dim: "H", text: "How often do you have difficulty waiting your turn in situations when turn taking is required?" }, { id: "B18", partA: false, dim: "H", text: "How often do you interrupt others when they are busy?" }, ]; // -------- WURS-K, short version (Retz-Junginger et al. 2002), translation ---- // Introductory sentence: "As a child (aged about 8 to 10), I was / I had ..." // Scoring: sum score 0..100; established cutoff for childhood ADHD symptoms >= 30. const WURSK_INTRO = "As a child (aged between about 8 and 10 years), I was / I had ..."; const WURSK = [ { id: "W1", text: "difficulty concentrating, easily distracted" }, { id: "W2", text: "anxious, full of worries" }, { id: "W3", text: "nervous, fidgety" }, { id: "W4", text: "inattentive, dreamy" }, { id: "W5", text: "hot-tempered, quick to flare up, with angry outbursts" }, { id: "W6", text: "a rather weak pupil / slow learner" }, { id: "W7", text: "disobedient, defiant towards adults" }, { id: "W8", text: "difficulty finishing tasks" }, { id: "W9", text: "inattentive at school, daydreaming" }, { id: "W10", text: "cheerful, boisterous, excessively active" }, { id: "W11", text: "easily irritated, easy to annoy" }, { id: "W12", text: "sad or dissatisfied with myself" }, { id: "W13", text: "impatient, easily frustrated" }, { id: "W14", text: "tearful, quickly upset" }, { id: "W15", text: "poorly adjusted, had difficulties at school" }, { id: "W16", text: "headstrong, stubborn, hard to talk out of things" }, { id: "W17", text: "low self-esteem, with self-doubt" }, { id: "W18", text: "problems with authority figures (teachers, parents)" }, { id: "W19", text: "problems understanding or following rules" }, { id: "W20", text: "problems with other children, frequent conflicts" }, { id: "W21", text: "clumsy, awkward" }, { id: "W22", text: "impulsive, acted without thinking" }, { id: "W23", text: "difficulty reading or spelling" }, { id: "W24", text: "an outsider, had few friends" }, { id: "W25", text: "moody, with rapid mood swings" }, ]; // ---------- Evaluation function ---------- function evaluate(answers) { // answers: { id: 0..4 } const get = (id) => (typeof answers[id] === "number" ? answers[id] : null); // ----- ASRS Part A: Markierung gem. Shaded-Zone-Logik ----- const partAItems = ASRS.filter((i) => i.partA); let partAMarks = 0; const partADetails = partAItems.map((item) => { const a = get(item.id); const threshold = item.th; // Items 1-3: th=2 (Manchmal); Items 4-6: th=3 (Oft) const marked = a !== null && a >= threshold; if (marked) partAMarks++; return { id: item.id, value: a, marked, threshold }; }); // ----- Summen-Scores ueber alle 18 ASRS-Items ----- const inattItems = ASRS.filter((i) => i.dim === "I"); const hypItems = ASRS.filter((i) => i.dim === "H"); const inattSum = inattItems.reduce((s, i) => s + (get(i.id) || 0), 0); const hypSum = hypItems.reduce((s, i) => s + (get(i.id) || 0), 0); const asrsTotal = inattSum + hypSum; // Klinisch oft genannter Cutoff für Erwachsenen-ADHS (Adler et al., DuPaul Adult ADHD RS): // Unaufmerksamkeit >= 17 von 36; Hyperaktivität/Impulsivität >= 17 von 36. const inattElevated = inattSum >= 17; const hypElevated = hypSum >= 17; // ----- WURS-K Summenscore ----- const wurskSum = WURSK.reduce((s, i) => s + (get(i.id) || 0), 0); const wurskMax = WURSK.length * 4; // = 100 // Etablierter Cutoff: >= 30 spricht für relevante kindliche ADHS-Symptomatik. const wurskElevated = wurskSum >= 30; // ----- Gesamteinordnung ----- // Konvention: Erwachsenen-ADHS-Hinweis erfordert (a) aktuelle Symptomatik UND (b) Hinweise auf Kindheit. const partAPositive = partAMarks >= 4; const overallFlag = partAPositive ? "high" : (inattElevated || hypElevated || wurskElevated) ? "moderate" : "low"; return { asrs: { partAMarks, partAPositive, partADetails, inattSum, hypSum, total: asrsTotal, inattMax: inattItems.length * 4, hypMax: hypItems.length * 4, inattElevated, hypElevated, }, wursk: { sum: wurskSum, max: wurskMax, elevated: wurskElevated, }, overall: { flag: overallFlag, partAPositive, retroPositive: wurskElevated }, }; } return { ASRS_LIKERT, WURS_LIKERT, ASRS, WURSK, WURSK_INTRO, evaluate, ui: { question: "Question", answersCount: (a, t) => `${a} / ${t} answered`, sectionLabels: { A: "Section 1 of 3 · ASRS Part A", B: "Section 2 of 3 · ASRS Part B", W: "Section 3 of 3 · WURS-K" }, resetConfirm: "Do you really want to delete all previous answers and start over?", }, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/adhs-result.js ============================================================================== // ADHD result renderer (English version) (function () { const RESULT_KEY = "brainscreener.adhs.result.v1"; let payload = window.BS_PRINT ? BS_PRINT.loadPayload(RESULT_KEY) : null; if (!payload) { try { payload = JSON.parse(sessionStorage.getItem(RESULT_KEY) || "null"); } catch { payload = null; } } if (!payload) { document.querySelector(".result-shell .container-narrow").innerHTML = `

      No result found

      Please take the test first to receive a report.

      Go to the ADHD test

      `; return; } const { ts, probandCode } = payload; // Re-evaluate the language-neutral answers in the language of this page // (allows printing the report in a different language). const result = (payload.answers && window.ADHS_DATA && typeof window.ADHS_DATA.evaluate === "function") ? window.ADHS_DATA.evaluate(payload.answers) : payload.result; const LOCALE = document.documentElement.lang || "en-CH"; const date = ts ? new Date(ts) : new Date(); document.getElementById("dateStr").textContent = date.toLocaleDateString(LOCALE, { day: "2-digit", month: "long", year: "numeric" }) + " · " + date.toLocaleTimeString(LOCALE, { hour: "2-digit", minute: "2-digit" }); // Show the examination code if one was entered const code = (probandCode || "").trim(); if (code) { document.getElementById("codeRow").hidden = false; document.getElementById("codeStr").textContent = code; } // ---- Overall classification ---- const flag = result.overall.flag; const flagMap = { high: { title: "Markedly positive screening", sub: "The symptom pattern is consistent with attention-deficit/hyperactivity disorder in adulthood.", val: "High", gauge: 0.85, text: `On ASRS Part A you marked ${result.asrs.partAMarks} of 6 items within the diagnostically relevant response range (cutoff: ≥4). Clinically, this counts as a strong indication of adult ADHD, supported by high sensitivity and specificity (>90 %) in the WHO validation study. ${result.overall.retroPositive ? "The WURS-K additionally points to relevant childhood symptoms, which further supports this finding." : "The WURS-K scores are below the cutoff – retrospective recall is, however, prone to error; a specialist medical assessment remains indicated."}`, }, moderate: { title: "Partially positive screening", sub: "There are indications of ADHD-typical symptoms, without the central cutoffs being fully reached.", val: "Moderate", gauge: 0.55, text: `Individual subscales lie within the clinically relevant range (inattention: ${result.asrs.inattSum}/${result.asrs.inattMax}; hyperactivity/impulsivity: ${result.asrs.hypSum}/${result.asrs.hypMax}; WURS-K: ${result.wursk.sum}/${result.wursk.max}). This level of symptoms may point to ADHD, but can also be caused by other factors (sleep deprivation, stress, other conditions). A specialist medical evaluation is recommended if the symptoms are burdensome in everyday life.`, }, low: { title: "Unremarkable screening", sub: "The central cutoffs are not reached. There is no strong indication of adult ADHD.", val: "Low", gauge: 0.18, text: `Both on ASRS Part A (${result.asrs.partAMarks}/6 marked) and on the subscales and the WURS-K (${result.wursk.sum}/${result.wursk.max}), the scores remain below the established cutoffs. A screening cannot, however, capture every presentation of the disorder. If you feel subjectively highly burdened, a specialist medical assessment may still be worthwhile.`, }, }; const cfg = flagMap[flag]; document.getElementById("overallTitle").textContent = stripTags(cfg.title); document.getElementById("overallSubtitle").textContent = stripTags(cfg.sub); document.getElementById("overallValue").textContent = cfg.val; document.getElementById("overallUnit").textContent = "Probability"; document.getElementById("interpretationText").innerHTML = cfg.text; // Gauge document.getElementById("gaugeWrap").innerHTML = gaugeSVG(cfg.gauge, flag); // ---- Subscales ---- const subscales = [ { label: "ASRS Part A · Screening items", raw: result.asrs.partAMarks, max: 6, threshold: 4, note: `${result.asrs.partAMarks} of 6 items within the diagnostically relevant range (cutoff ≥4). ${result.asrs.partAPositive ? "Cutoff reached." : "Cutoff not reached."}`, }, { label: "ASRS · Inattention", raw: result.asrs.inattSum, max: result.asrs.inattMax, threshold: 17, note: `Sum score: ${result.asrs.inattSum} / ${result.asrs.inattMax} (clinically relevant cutoff ≥17). ${result.asrs.inattElevated ? "Elevated." : "Within the normal range."}`, }, { label: "ASRS · Hyperactivity / impulsivity", raw: result.asrs.hypSum, max: result.asrs.hypMax, threshold: 17, note: `Sum score: ${result.asrs.hypSum} / ${result.asrs.hypMax} (clinically relevant cutoff ≥17). ${result.asrs.hypElevated ? "Elevated." : "Within the normal range."}`, }, { label: "WURS-K · Childhood symptoms (retrospective)", raw: result.wursk.sum, max: result.wursk.max, threshold: 30, note: `Sum score: ${result.wursk.sum} / ${result.wursk.max} (a cutoff ≥30 indicates relevant childhood ADHD symptoms). ${result.wursk.elevated ? "Elevated." : "Within the normal range."}`, }, ]; const subList = document.getElementById("subscaleList"); subList.innerHTML = subscales.map((s) => { const pct = Math.min(100, Math.round((s.raw / s.max) * 100)); const tPct = Math.min(100, Math.round((s.threshold / s.max) * 100)); return `
      ${s.label} ${s.raw} / ${s.max}
      ${s.note}
      `; }).join(""); // ---- Context text ---- document.getElementById("contextText").innerHTML = ` The ASRS v1.1 is a WHO instrument for the self-assessment of current ADHD symptoms in adults (reference period: 6 months). It is one of the best-validated brief instruments internationally. The WURS-K complements the picture with a retrospective assessment of childhood, since an ADHD diagnosis requires symptoms to have been present before the age of 12 years (DSM-5-TR Criterion B). `; // ---- Next steps ---- const ns = document.getElementById("nextSteps"); const nextSteps = []; if (flag === "high" || flag === "moderate") { nextSteps.push("Discuss this result with a medical or psychological professional. The document can help structure the initial consultation or further diagnostic workup."); nextSteps.push("Write down concrete example situations from everyday life, work and your school years in which symptoms were burdensome — this helps in the clinical interview."); nextSteps.push("A confirmed diagnosis requires a structured clinical interview, a thorough history and the exclusion of differential-diagnostic causes (sleep, thyroid, affective disorders)."); nextSteps.push("Print the report as a PDF and bring it to your next appointment."); } else { nextSteps.push("Nevertheless, discuss the result with your treating clinician if you were referred to this test."); nextSteps.push("If you feel subjectively burdened: other causes (e. g. sleep disorders, a depressive episode, an anxiety disorder) can produce similar symptoms and should be carefully evaluated."); nextSteps.push("Sleep, exercise and stress regulation form the foundation of cognitive performance."); } ns.innerHTML = nextSteps.map((s) => `
    • ${s}
    • `).join(""); // ---- Buttons ---- if (window.BS_PRINT) BS_PRINT.attachPrint(document.getElementById("btnPrint"), RESULT_KEY); else document.getElementById("btnPrint").addEventListener("click", () => window.print()); // ---- helpers ---- function stripTags(s) { return s.replace(/<[^>]*>/g, ""); } function gaugeSVG(value /* 0..1 */, flag) { // Halbkreis-Gauge. Hoehe aus dem Bogen ableiten: 10 px Luft oben fuer die runde // Strichkappe, 36 px unten fuer die Skalenbeschriftung (sonst faellt sie aus der viewBox). const w = 360, r = 140, cx = w / 2, cy = r + 10, h = cy + 36; const start = Math.PI; const end = 0; const ang = start + (end - start) * value; const px = cx + r * Math.cos(ang); // In SVG zeigt +y nach unten, der Bogen liegt oben — daher cy MINUS sin. const py = cy - r * Math.sin(ang); const color = flag === "high" ? "var(--danger)" : flag === "moderate" ? "var(--gold)" : "var(--sage)"; function arc(p) { const a = start + (end - start) * p; return [cx + r * Math.cos(a), cy - r * Math.sin(a)]; } const [ax, ay] = arc(value); return ` `; } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/aq50-data.js ============================================================================== // AQ-50 - Autism-Spectrum Quotient (full version, 50 items) // Sources: // - Baron-Cohen S, Wheelwright S, Skinner R, Martin J, Clubley E (2001). // The Autism-Spectrum Quotient (AQ): Evidence from Asperger Syndrome/High-Functioning // Autism, Males and Females, Scientists and Mathematicians. // J Autism Dev Disord 31(1):5-17. // - Woodbury-Smith MR, Robinson J, Wheelwright S, Baron-Cohen S (2005). // Screening adults for Asperger syndrome using the AQ: a preliminary study of // its diagnostic validity in clinical practice. J Autism Dev Disord 35(3):331-5. // - Freitag CM, Retz-Junginger P, Retz W et al. (2007). Untersuchung der deutschen // Version des Autism-Spektrum-Quotienten (AQ) bei Erwachsenen. Diagnostica 53. // // 50 items, 4-point scale (definitely agree / slightly agree / slightly disagree / // definitely disagree). Scoring: 1 point for "agree" on non-reversed items and // "disagree" on reversed items. Total 0..50. // Cutoffs: // >= 32 Baron-Cohen 2001 - clinically relevant (sens 79%, spec 98% for AS/HFA). // >= 26 Woodbury-Smith 2005 - more sensitive cutoff for outpatient practice. // 5 subscales of 10 items each: social, switching, detail, communication, imagination. window.TEST_DATA = (function () { const SCALE = { cols: 4, options: [ { v: 3, label: "Definitely agree" }, { v: 2, label: "Slightly agree" }, { v: 1, label: "Slightly disagree" }, { v: 0, label: "Definitely disagree" }, ] }; // s: subscale, r: reverse-coded const ITEMS = [ { id: "Q1", s: "social", r: true, text: "I prefer to do things with others rather than on my own." }, { id: "Q2", s: "switching", r: false, text: "I prefer to do things the same way over and over again." }, { id: "Q3", s: "imagination", r: true, text: "If I try to imagine something, I find it very easy to create a picture in my mind." }, { id: "Q4", s: "switching", r: false, text: "I frequently get so strongly absorbed in one thing that I lose sight of other things." }, { id: "Q5", s: "detail", r: false, text: "I often notice small sounds when others do not." }, { id: "Q6", s: "detail", r: false, text: "I usually notice car number plates or similar strings of information." }, { id: "Q7", s: "communication", r: false, text: "Other people frequently tell me that what I've said is impolite, even though I think it is polite." }, { id: "Q8", s: "imagination", r: true, text: "When I'm reading a story, I can easily imagine what the characters might look like." }, { id: "Q9", s: "detail", r: false, text: "I am fascinated by dates." }, { id: "Q10", s: "switching", r: true, text: "In a social group, I can easily keep track of several different people's conversations." }, { id: "Q11", s: "social", r: true, text: "I find social situations easy." }, { id: "Q12", s: "detail", r: false, text: "I tend to notice details that others do not." }, { id: "Q13", s: "social", r: false, text: "I would rather go to a library than a party." }, { id: "Q14", s: "imagination", r: true, text: "I find making up stories easy." }, { id: "Q15", s: "social", r: true, text: "I find myself drawn more strongly to people than to things." }, { id: "Q16", s: "switching", r: false, text: "I tend to have very strong interests, which I get upset about if I can't pursue." }, { id: "Q17", s: "communication", r: true, text: "I enjoy social chit-chat." }, { id: "Q18", s: "communication", r: false, text: "When I talk, it isn't always easy for others to get a word in edgeways." }, { id: "Q19", s: "detail", r: false, text: "I am fascinated by numbers." }, { id: "Q20", s: "imagination", r: false, text: "When I'm reading a story, I find it difficult to work out the characters' intentions." }, { id: "Q21", s: "imagination", r: false, text: "I don't particularly enjoy reading fiction." }, { id: "Q22", s: "social", r: false, text: "I find it hard to make new friends." }, { id: "Q23", s: "detail", r: false, text: "I notice patterns in things all the time." }, { id: "Q24", s: "imagination", r: true, text: "I would rather go to the theatre than a museum." }, { id: "Q25", s: "switching", r: true, text: "It does not upset me if my daily routine is disturbed." }, { id: "Q26", s: "communication", r: false, text: "I frequently find that I don't know how to keep a conversation going." }, { id: "Q27", s: "communication", r: true, text: "I find it easy to \"read between the lines\" when someone is talking to me." }, { id: "Q28", s: "detail", r: true, text: "I usually concentrate more on the whole picture, rather than the small details." }, { id: "Q29", s: "detail", r: true, text: "I am not very good at remembering phone numbers." }, { id: "Q30", s: "detail", r: true, text: "I don't usually notice small changes in a situation, or a person's appearance." }, { id: "Q31", s: "communication", r: true, text: "I know how to tell if someone listening to me is getting bored." }, { id: "Q32", s: "switching", r: true, text: "I find it easy to do more than one thing at once." }, { id: "Q33", s: "communication", r: false, text: "When I talk on the phone, I'm not sure when it's my turn to speak." }, { id: "Q34", s: "switching", r: true, text: "I enjoy doing things spontaneously." }, { id: "Q35", s: "communication", r: false, text: "I am often the last to understand the point of a joke." }, { id: "Q36", s: "social", r: true, text: "I find it easy to work out what someone is thinking or feeling just by looking at their face." }, { id: "Q37", s: "switching", r: true, text: "If there is an interruption, I can switch back to what I was doing very quickly." }, { id: "Q38", s: "communication", r: true, text: "I am good at social chit-chat." }, { id: "Q39", s: "communication", r: false, text: "People often tell me that I keep going on and on about the same thing." }, { id: "Q40", s: "imagination", r: true, text: "When I was young, I used to enjoy playing games involving pretending with other children." }, { id: "Q41", s: "imagination", r: false, text: "I like to collect information about categories of things (e.g. types of car, types of bird, types of train, types of plant, etc.)." }, { id: "Q42", s: "imagination", r: false, text: "I find it difficult to imagine what it would be like to be someone else." }, { id: "Q43", s: "switching", r: false, text: "I like to plan any activities I participate in carefully." }, { id: "Q44", s: "social", r: true, text: "I enjoy social occasions." }, { id: "Q45", s: "social", r: false, text: "I find it difficult to work out people's intentions." }, { id: "Q46", s: "switching", r: false, text: "New situations make me anxious." }, { id: "Q47", s: "social", r: true, text: "I enjoy meeting new people." }, { id: "Q48", s: "social", r: true, text: "I am a good diplomat." }, { id: "Q49", s: "detail", r: true, text: "I am not very good at remembering people's date of birth." }, { id: "Q50", s: "imagination", r: true, text: "I find it very easy to play games with children that involve pretending." }, ]; const SUB_LABELS = { social: "Social skill", switching: "Attention switching", detail: "Attention to detail", communication: "Communication", imagination: "Imagination", }; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); let total = 0; const subs = { social: 0, switching: 0, detail: 0, communication: 0, imagination: 0 }; for (const it of ITEMS) { const v = get(it.id); const counted = it.r ? (v <= 1) : (v >= 2); if (counted) { total++; subs[it.s]++; } } const cutoffStrict = total >= 32; const cutoffSensitive = total >= 26; // Bands based on established cutoffs: >=32 clinical (Baron-Cohen 2001), // 26-31 borderline elevated (Woodbury-Smith 2005), below that unremarkable. // The population mean is around ~16-17 — scores in that range are // normal and are NOT reported as "elevated". let flag; if (cutoffStrict) flag = "high"; else if (cutoffSensitive) flag = "moderate"; else flag = "low"; return { total, max: 50, subs, cutoffStrict, cutoffSensitive, flag }; } function renderResult(result) { const titleMap = { low: "Unremarkable AQ-50 screening", moderate: "Elevated autistic trait expression", high: "Consistent with an autistic phenotype", }; const subMap = { low: "Scores within the range of the neurotypical general population.", moderate: "Scores are above the population average — a specialist assessment may be worthwhile.", high: "Profile consistent with an autism spectrum condition; specialist diagnostic assessment is recommended.", }; const interp = ` Your AQ-50 total score is ${result.total}/50 points. For comparison: in the original validation study (Baron-Cohen 2001), the mean of the neurotypical comparison group was 16.4, while adults with Asperger syndrome/high-functioning autism averaged 35.8. ${result.cutoffStrict ? `The strict cutoff of ≥ 32 (Baron-Cohen 2001) is met — sensitivity approx. 79 %, specificity approx. 98 %.` : (result.cutoffSensitive ? `The more sensitive cutoff of ≥ 26 (Woodbury-Smith et al. 2005) is met; the strict cutoff (≥ 32) is not met.` : `Neither of the established cutoffs (≥ 26 sensitive, ≥ 32 specific) is met.`)} The five subscales below show the functional domains in which autistic traits are most pronounced in your profile. `; const subscaleEntries = [ { label: "AQ-50 total score", raw: result.total, max: 50, threshold: 32, note: `Strict cutoff: ≥ 32. ${result.cutoffStrict ? "Met." : (result.cutoffSensitive ? "More sensitive cutoff (≥ 26) met." : "Not met.")}` }, ...Object.keys(SUB_LABELS).map((k) => ({ label: `Subscale · ${SUB_LABELS[k]}`, raw: result.subs[k], max: 10, threshold: 6, note: `${result.subs[k]} of 10 items answered in the autistic direction.${result.subs[k] >= 6 ? " Markedly pronounced." : ""}`, })), ]; const context = ` The Autism Spectrum Quotient (AQ-50) is the original version by Baron-Cohen et al. (2001) and the most widely used self-report measure worldwide for autistic traits in adults of normal intelligence. It provides subscale profiles across five functional domains (social skill, attention switching, attention to detail, communication, imagination). A confirmed ASD diagnosis requires a developmental history (e.g. ADI-R) as well as standardised behavioural observation (e.g. ADOS-2). The German version was validated by Freitag, Retz-Junginger and Retz (2007). `; const next = []; if (result.flag === "high") { next.push("Arrange an appointment at a practice or specialist outpatient clinic focusing on adult autism spectrum diagnostics."); next.push("A complete diagnostic work-up includes a developmental history (ideally with a caregiver who knew you in childhood), standardised behavioural observation (ADOS-2, module 4) and differential diagnostics (ADHD, social phobia, schizoid personality disorder, attachment disorder)."); next.push("Even with a clear self-identification as \"autistic\", a professional diagnosis is helpful — it opens access to therapy, counselling and, where applicable, social benefits, and allows a differentiated distinction from comorbidities."); } else if (result.flag === "moderate") { next.push("The score indicates an above-average expression of autistic traits. If you experience subjective distress or impairment in daily life, a specialist assessment is worthwhile."); next.push("Additional specific instruments can sharpen the diagnostic picture: RAADS-R (80 items, more sensitive in women who camouflage), EQ/SQ (Empathy/Systemising), or ADOS-2."); } else { next.push("Your scores lie within the neurotypical range. If you nonetheless experience yourself as \"different\" in many areas of life, a longer instrument such as the RAADS-R may provide further insight."); } next.push("Print this report as a PDF and bring it along to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: result.total, unit: `/ 50 points`, gauge: result.total / 50, flag: result.flag, interpretationHTML: interp, subscales: subscaleEntries, contextHTML: context, nextSteps: next, }; } return { id: "aq50", meta: { title: "AQ-50 · Autism Spectrum (Adults)", pageTitle: "AQ-50 — Autism Screening · brainScreener", eyebrow: "Autism spectrum", intro: `The Autism Spectrum Quotient (AQ-50) is the original version by Baron-Cohen et al. (2001) — the most widely used international self-report measure for autistic traits in adults of normal intelligence. 50 items across five subscales. It provides a differentiated functional profile; the definitive diagnosis is made by specialised professionals using ADOS-2 / ADI-R.`, durationText: "approx. 8–12 minutes", itemsText: "50 items · 5 subscales", sources: "Baron-Cohen et al. 2001 · Woodbury-Smith et al. 2005 · Freitag et al. (dt.) 2007", testPath: "/brainscreener/aq50.html", retestPath: "/brainscreener/aq50.html", resultPath: "/brainscreener/aq50-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "AQ-50 · Self-assessment", intro: "How strongly do you agree with the following statements about yourself?", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/audit-data.js ============================================================================== // AUDIT - Alcohol Use Disorders Identification Test // Sources: // - Saunders JB, Aasland OG, Babor TF, de la Fuente JR, Grant M (1993). Development // of the Alcohol Use Disorders Identification Test (AUDIT). Addiction 88(6): 791-804. // - Babor TF, Higgins-Biddle JC, Saunders JB, Monteiro MG (2001). AUDIT: Guidelines for // Use in Primary Care. WHO, 2nd edition. // - WHO/Addiction Switzerland (Sucht Schweiz): standard alcohol screener for primary care. // // 10 items with different scales: // Item 1: 5-point frequency scale // Item 2: 5-point scale for quantity per drinking occasion // Items 3-8: 5-point scale "Never..Daily" // Items 9-10: 3-point scale "No / Yes, but not in the last year / Yes, during the last year" (0/2/4) // // Cutoffs (WHO 2001): // 0-7 low risk // 8-15 hazardous drinking (counselling recommended) // 16-19 harmful drinking (brief intervention) // >=20 probable dependence (urgent diagnostic assessment) // Women-specific cutoff: 5 (Bradley et al. 2007). window.TEST_DATA = (function () { const SCALE_FREQ = { cols: 5, options: [ { v: 0, label: "Never" }, { v: 1, label: "Monthly or less" }, { v: 2, label: "2 to 4 times a month" }, { v: 3, label: "2 to 3 times a week" }, { v: 4, label: "4 or more times a week" }, ] }; const SCALE_AMOUNT = { cols: 5, options: [ { v: 0, label: "1 or 2" }, { v: 1, label: "3 or 4" }, { v: 2, label: "5 or 6" }, { v: 3, label: "7 to 9" }, { v: 4, label: "10 or more" }, ] }; const SCALE_PROBLEM = { cols: 5, options: [ { v: 0, label: "Never" }, { v: 1, label: "Less than monthly" }, { v: 2, label: "Monthly" }, { v: 3, label: "Weekly" }, { v: 4, label: "Daily or almost daily" }, ] }; const SCALE_YESNO = { cols: 3, options: [ { v: 0, label: "No" }, { v: 2, label: "Yes, but not in the last year" }, { v: 4, label: "Yes, during the last year" }, ] }; const ITEMS = [ { id: "A1", scale: SCALE_FREQ, text: "How often do you have a drink containing alcohol? (one standard drink = approx. 10–12 g of pure alcohol: 3 dl beer, 1 dl wine, 2 cl spirits)" }, { id: "A2", scale: SCALE_AMOUNT, text: "How many drinks containing alcohol do you have on a typical day when you are drinking?" }, { id: "A3", scale: SCALE_PROBLEM, text: "How often do you have six or more drinks on one occasion?" }, { id: "A4", scale: SCALE_PROBLEM, text: "How often during the last year have you found that you were not able to stop drinking once you had started?" }, { id: "A5", scale: SCALE_PROBLEM, text: "How often during the last year have you failed to do what was normally expected from you because of drinking?" }, { id: "A6", scale: SCALE_PROBLEM, text: "How often during the last year have you needed a first drink in the morning to get yourself going after a heavy drinking session?" }, { id: "A7", scale: SCALE_PROBLEM, text: "How often during the last year have you had a feeling of guilt or remorse after drinking?" }, { id: "A8", scale: SCALE_PROBLEM, text: "How often during the last year have you been unable to remember what happened the night before because you had been drinking?" }, { id: "A9", scale: SCALE_YESNO, text: "Have you or someone else been injured as a result of your drinking?" }, { id: "A10", scale: SCALE_YESNO, text: "Has a relative or friend or a doctor or another health worker been concerned about your drinking or suggested you cut down?" }, ]; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); const total = ITEMS.reduce((s, it) => s + get(it.id), 0); const consumption = get("A1") + get("A2") + get("A3"); const dependence = get("A4") + get("A5") + get("A6"); const harm = get("A7") + get("A8") + get("A9") + get("A10"); let flag, level; if (total <= 7) { level = "low risk"; flag = "low"; } else if (total <= 15) { level = "hazardous drinking"; flag = "moderate"; } else if (total <= 19) { level = "harmful drinking"; flag = "high"; } else { level = "probable dependence"; flag = "high"; } return { total, max: 40, level, flag, consumption, dependence, harm }; } function renderResult(result) { const interp = (() => { if (result.total <= 7) return `Your AUDIT score is ${result.total}/40 — this corresponds to the WHO category "low risk". No specific need for action; abstinent or moderate consumption.`; if (result.total <= 15) return `Your AUDIT score is ${result.total}/40 — this corresponds to the WHO category "hazardous drinking". In this range there is an increased risk of health-related and social consequences; a brief medical intervention (brief intervention) has well-documented effectiveness (Kaner et al. Cochrane Review 2018; WHO 2024).`; if (result.total <= 19) return `Your AUDIT score is ${result.total}/40 — this corresponds to the WHO category "harmful drinking". A brief intervention plus closer follow-up monitoring is recommended.`; return `Your AUDIT score is ${result.total}/40 — this corresponds to the WHO category "probable dependence". A diagnostic assessment and, where indicated, specialised addiction treatment is urgently recommended.`; })(); const subscales = [ { label: "AUDIT total score", raw: result.total, max: 40, threshold: 8, note: `Cutoff for hazardous drinking: ≥ 8. For women, often ≥ 5 (Bradley et al. 2007). Current category: ${result.level}.` }, { label: "Items 1–3 · Quantity & frequency of consumption (AUDIT-C)", raw: result.consumption, max: 12, threshold: 4, note: `AUDIT-C cutoff: ≥ 4 (men) / ≥ 3 (women). Also established as a stand-alone brief screener.` }, { label: "Items 4–6 · Dependence symptoms", raw: result.dependence, max: 12, threshold: 4, note: `Elevated scores suggest loss of control, neglect of obligations and morning drinking — core symptoms of dependence.` }, { label: "Items 7–10 · Alcohol-related problems", raw: result.harm, max: 16, threshold: 4, note: `Feelings of guilt, blackouts, injuries, feedback from others — indications of harm that has already occurred.` }, ]; const context = ` The Alcohol Use Disorders Identification Test (AUDIT) was developed by the WHO in 1989 and is the most widely used screening instrument internationally for problematic alcohol consumption. It captures not only dependence but also hazardous and harmful drinking below the diagnostic threshold. The short form AUDIT-C (items 1–3) is increasingly recommended as a first-line screener in the primary care setting (USPSTF 2018, update 2024). A confirmed diagnosis requires a clinical interview and physical findings (CDT, gamma-GT, MCV, clinical impression). `; const next = []; if (result.total >= 20) { next.push("Contact a GP practice experienced in addiction medicine, a psychiatric service or a specialised addiction counselling service promptly."); next.push("If you are physically dependent, do not stop abruptly on your own — withdrawal complications (seizures, delirium) can be life-threatening. Inpatient or medically supervised outpatient detoxification is recommended."); next.push("Evidence-based treatment: motivational interviewing + CBT + medication where indicated (naltrexone, acamprosate, nalmefene); German S3 guideline 2021, NICE CG115 update 2024."); } else if (result.total >= 16) { next.push("A medical brief intervention (10–30 minutes of structured conversation) is evidence-based and effective at this level — make an appointment with your GP."); next.push("Keep a drinking diary for 2 weeks — this is very useful for the initial consultation."); } else if (result.total >= 8) { next.push("Actively reduce your drinking days and quantities. WHO guidance on low-risk consumption (revised in 2024 in line with the Canadian guidelines): every reduction is a gain; there is no completely \"safe\" level of consumption."); next.push("If you are unsure or unable to cut down on your own, low-threshold counselling is worthwhile (GP, addiction counselling service)."); } else { next.push("Your consumption profile is in the low-risk range. Stay mindful, especially during stressful periods of life."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: result.total <= 7 ? "Unremarkable AUDIT screening" : (result.total <= 15 ? "Hazardous alcohol consumption" : (result.total <= 19 ? "Harmful alcohol consumption" : "Probable alcohol dependence")), sub: result.total <= 7 ? "Consumption in the low-risk range according to the WHO categorisation." : "A further assessment or specific counselling is recommended.", value: result.total, unit: `/ 40 points · ${result.level}`, gauge: Math.min(1, result.total / 25), flag: result.flag, interpretationHTML: interp, subscales, contextHTML: context, nextSteps: next, }; } return { id: "audit", meta: { title: "AUDIT · Alcohol Screening (WHO)", pageTitle: "AUDIT — Alcohol Screening · brainScreener", eyebrow: "Alcohol consumption", intro: `The WHO's Alcohol Use Disorders Identification Test (AUDIT) captures not only dependence but all levels of problematic alcohol consumption — from hazardous drinking to dependence. 10 items, reference period: the last year.`, durationText: "approx. 3–4 minutes", itemsText: "10 items · 3 subscales", sources: "Saunders et al. 1993 · WHO/Babor et al. 2001 · USPSTF 2024", testPath: "/brainscreener/audit.html", retestPath: "/brainscreener/audit.html", resultPath: "/brainscreener/audit-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "AUDIT · Last year", intro: "Answer the following questions honestly — with reference to the last 12 months.", items: ITEMS, scale: SCALE_FREQ, // overridden per item }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/bfi2-data.js ============================================================================== // BFI-2 - Big Five Inventory-2 (60 items, full version) // Sources: // - Soto CJ, John OP (2017). The next Big Five Inventory (BFI-2): Developing and // assessing a hierarchical model with 15 facets to enhance bandwidth, fidelity, // and predictive power. J Pers Soc Psychol 113(1): 117-143. // - Danner D, Rammstedt B, Bluemke M, Lechner C, Berres S, Knopf T, Soto CJ, John OP // (2019). Das Big Five Inventory 2 (BFI-2): Deutsche Adaptation. Diagnostica 65(3). // - Soto CJ, John OP (2024). The BFI-2: Updated psychometric properties and // cross-cultural evidence. // // 60 items, 5-point Likert. 5 domains of 12 items each, 15 facets of 4 items each. // Domain norms (Danner et al. 2019, German general population, N>4,600): // E: M=3.32 SD=0.69 | A: M=3.57 SD=0.55 | C: M=3.62 SD=0.65 // N: M=2.62 SD=0.79 | O: M=3.74 SD=0.62 window.TEST_DATA = (function () { const SCALE = { cols: 5, options: [ { v: 1, label: "Disagree strongly" }, { v: 2, label: "Disagree a little" }, { v: 3, label: "Neutral; no opinion" }, { v: 4, label: "Agree a little" }, { v: 5, label: "Agree strongly" }, ] }; // d: Domain (E/A/C/N/O), f: Facet, r: reverse-coded const ITEMS = [ { id: "B1", d: "E", f: "sociability", r: false, text: "I am someone who is outgoing, sociable." }, { id: "B2", d: "A", f: "compassion", r: false, text: "I am someone who is compassionate, has a soft heart." }, { id: "B3", d: "C", f: "organization", r: true, text: "I am someone who tends to be disorganized." }, { id: "B4", d: "N", f: "anxiety", r: true, text: "I am someone who is relaxed, handles stress well." }, { id: "B5", d: "O", f: "aesthetic", r: true, text: "I am someone who has few artistic interests." }, { id: "B6", d: "E", f: "assertiveness", r: false, text: "I am someone who has an assertive personality." }, { id: "B7", d: "A", f: "respectfulness", r: false, text: "I am someone who is respectful, treats others with respect." }, { id: "B8", d: "C", f: "productiveness", r: true, text: "I am someone who tends to be lazy." }, { id: "B9", d: "N", f: "depression", r: true, text: "I am someone who stays optimistic after experiencing a setback." }, { id: "B10", d: "O", f: "intellectual", r: false, text: "I am someone who is curious about many different things." }, { id: "B11", d: "E", f: "energy", r: true, text: "I am someone who rarely feels excited or eager." }, { id: "B12", d: "A", f: "trust", r: true, text: "I am someone who tends to find fault with others." }, { id: "B13", d: "C", f: "responsibility", r: false, text: "I am someone who is dependable, steady." }, { id: "B14", d: "N", f: "volatility", r: false, text: "I am someone who is moody, has up and down mood swings." }, { id: "B15", d: "O", f: "creative", r: false, text: "I am someone who is inventive, finds clever ways to do things." }, { id: "B16", d: "E", f: "sociability", r: true, text: "I am someone who tends to be quiet." }, { id: "B17", d: "A", f: "compassion", r: true, text: "I am someone who feels little sympathy for others." }, { id: "B18", d: "C", f: "organization", r: false, text: "I am someone who is systematic, likes to keep things in order." }, { id: "B19", d: "N", f: "anxiety", r: false, text: "I am someone who can be tense." }, { id: "B20", d: "O", f: "aesthetic", r: false, text: "I am someone who is fascinated by art, music, or literature." }, { id: "B21", d: "E", f: "assertiveness", r: false, text: "I am someone who is dominant, acts as a leader." }, { id: "B22", d: "A", f: "respectfulness", r: true, text: "I am someone who starts arguments with others." }, { id: "B23", d: "C", f: "productiveness", r: true, text: "I am someone who has difficulty getting started on tasks." }, { id: "B24", d: "N", f: "depression", r: true, text: "I am someone who feels secure, comfortable with self." }, { id: "B25", d: "O", f: "intellectual", r: true, text: "I am someone who avoids intellectual, philosophical discussions." }, { id: "B26", d: "E", f: "energy", r: true, text: "I am someone who is less active than other people." }, { id: "B27", d: "A", f: "trust", r: false, text: "I am someone who has a forgiving nature." }, { id: "B28", d: "C", f: "responsibility", r: true, text: "I am someone who can be somewhat careless." }, { id: "B29", d: "N", f: "volatility", r: true, text: "I am someone who is emotionally stable, not easily upset." }, { id: "B30", d: "O", f: "creative", r: true, text: "I am someone who has little creativity." }, { id: "B31", d: "E", f: "sociability", r: true, text: "I am someone who is sometimes shy, introverted." }, { id: "B32", d: "A", f: "compassion", r: false, text: "I am someone who is helpful and unselfish with others." }, { id: "B33", d: "C", f: "organization", r: false, text: "I am someone who keeps things neat and tidy." }, { id: "B34", d: "N", f: "anxiety", r: false, text: "I am someone who worries a lot." }, { id: "B35", d: "O", f: "aesthetic", r: false, text: "I am someone who values art and beauty." }, { id: "B36", d: "E", f: "assertiveness", r: true, text: "I am someone who finds it hard to influence people." }, { id: "B37", d: "A", f: "respectfulness", r: true, text: "I am someone who is sometimes rude to others." }, { id: "B38", d: "C", f: "productiveness", r: false, text: "I am someone who is efficient, gets things done." }, { id: "B39", d: "N", f: "depression", r: false, text: "I am someone who often feels sad." }, { id: "B40", d: "O", f: "intellectual", r: false, text: "I am someone who is complex, a deep thinker." }, { id: "B41", d: "E", f: "energy", r: false, text: "I am someone who is full of energy." }, { id: "B42", d: "A", f: "trust", r: true, text: "I am someone who is suspicious of others' intentions." }, { id: "B43", d: "C", f: "responsibility", r: false, text: "I am someone who is reliable, can always be counted on." }, { id: "B44", d: "N", f: "volatility", r: true, text: "I am someone who keeps their emotions under control." }, { id: "B45", d: "O", f: "creative", r: true, text: "I am someone who has difficulty imagining things." }, { id: "B46", d: "E", f: "sociability", r: false, text: "I am someone who is talkative." }, { id: "B47", d: "A", f: "compassion", r: true, text: "I am someone who can be cold and uncaring." }, { id: "B48", d: "C", f: "organization", r: true, text: "I am someone who leaves a mess, doesn't clean up." }, { id: "B49", d: "N", f: "anxiety", r: true, text: "I am someone who rarely feels anxious or afraid." }, { id: "B50", d: "O", f: "aesthetic", r: true, text: "I am someone who thinks poetry and plays are boring." }, { id: "B51", d: "E", f: "assertiveness", r: true, text: "I am someone who prefers to have others take charge." }, { id: "B52", d: "A", f: "respectfulness", r: false, text: "I am someone who is polite, courteous to others." }, { id: "B53", d: "C", f: "productiveness", r: false, text: "I am someone who is persistent, works until the task is finished." }, { id: "B54", d: "N", f: "depression", r: false, text: "I am someone who tends to feel depressed, blue." }, { id: "B55", d: "O", f: "intellectual", r: true, text: "I am someone who has little interest in abstract ideas." }, { id: "B56", d: "E", f: "energy", r: false, text: "I am someone who shows a lot of enthusiasm." }, { id: "B57", d: "A", f: "trust", r: false, text: "I am someone who assumes the best about people." }, { id: "B58", d: "C", f: "responsibility", r: true, text: "I am someone who sometimes behaves irresponsibly." }, { id: "B59", d: "N", f: "volatility", r: false, text: "I am someone who is temperamental, gets emotional easily." }, { id: "B60", d: "O", f: "creative", r: false, text: "I am someone who is original, comes up with new ideas." }, ]; const DOMAINS = { E: { name: "Extraversion", short: "E", m: 3.32, sd: 0.69, color: "#C9A86B", high: "outgoing, energetic, dominant, socially active", low: "reserved, quiet, more focused on a few close relationships" }, A: { name: "Agreeableness", short: "A", m: 3.57, sd: 0.55, color: "#A9B8A3", high: "warm-hearted, trusting, cooperative, willing to compromise", low: "critical, direct, competitive, less willing to compromise" }, C: { name: "Conscientiousness", short: "C", m: 3.62, sd: 0.65, color: "#1F3A3D", high: "organized, goal-directed, disciplined, reliable", low: "spontaneous, flexible, less structured, open-ended in approach" }, N: { name: "Negative Emotionality", short: "N", m: 2.62, sd: 0.79, color: "#B5564A", high: "emotionally sensitive, easily unsettled, prone to worry", low: "emotionally stable, even-tempered, resilient to stress" }, O: { name: "Open-Mindedness", short: "O", m: 3.74, sd: 0.62, color: "#7F6FA8", high: "curious, creative, broadly interested, aesthetically sensitive", low: "pragmatic, conventional, focused on familiar domains" }, }; const FACET_LABELS = { sociability: "Sociability", assertiveness: "Assertiveness", energy: "Energy Level", compassion: "Compassion", respectfulness: "Respectfulness", trust: "Trust", organization: "Organization", productiveness: "Productiveness", responsibility: "Responsibility", anxiety: "Anxiety", depression: "Depression", volatility: "Emotional Volatility", aesthetic: "Aesthetic Sensitivity", intellectual: "Intellectual Curiosity", creative: "Creative Imagination", }; // Facet norms (US standard, Soto & John 2017, for approximate benchmarking) const FACET_NORMS = { sociability: 3.18, assertiveness: 3.21, energy: 3.45, compassion: 3.93, respectfulness: 3.97, trust: 3.28, organization: 3.30, productiveness: 3.46, responsibility: 4.04, anxiety: 3.04, depression: 2.55, volatility: 2.77, aesthetic: 3.30, intellectual: 3.79, creative: 3.68, }; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 3); const scoreItem = (it) => it.r ? (6 - get(it.id)) : get(it.id); const domains = {}; for (const d of Object.keys(DOMAINS)) { const items = ITEMS.filter((i) => i.d === d); const sum = items.reduce((s, it) => s + scoreItem(it), 0); const mean = sum / items.length; const T = Math.round(50 + 10 * (mean - DOMAINS[d].m) / DOMAINS[d].sd); let level; if (T < 35) level = "very low"; else if (T < 45) level = "low"; else if (T < 56) level = "average"; else if (T < 65) level = "high"; else level = "very high"; domains[d] = { mean, T, level }; } const facets = {}; for (const f of Object.keys(FACET_LABELS)) { const items = ITEMS.filter((i) => i.f === f); const sum = items.reduce((s, it) => s + scoreItem(it), 0); const mean = sum / items.length; const norm = FACET_NORMS[f]; const diff = mean - norm; let level; if (diff < -0.8) level = "well below the norm"; else if (diff < -0.3) level = "slightly below the norm"; else if (diff < 0.3) level = "within the normal range"; else if (diff < 0.8) level = "slightly above the norm"; else level = "well above the norm"; facets[f] = { mean, level, domain: items[0].d }; } return { domains, facets }; } function profileSVG(domains) { const labels = ["E","A","C","N","O"]; const w = 380, h = 220, padX = 44, padY = 28, barH = 24, gap = 10; const barAreaW = w - padX * 2; const tToX = (t) => padX + Math.max(0, Math.min(1, (t - 20) / 60)) * barAreaW; const bars = labels.map((d, i) => { const y = padY + i * (barH + gap); const x = tToX(domains[d].T); const filled = x - padX; return ` ${d} T=${domains[d].T} `; }).join(""); return ` T-scores (M=50, SD=10) — dashed line: German population mean ${bars} 20 50 80 `; } function renderResult(result) { const customSVG = profileSVG(result.domains); const interp = ` Your BFI-2 profile shows your individual standing on the five domains and 15 facets of personality. The domain scores are expressed as T-scores (mean = 50, standard deviation = 10) relative to the German norm sample (Danner et al. 2019, N > 4,600). T-scores between 40 and 60 correspond to the range covering about 68 % of people; scores below 35 or above 65 are statistically unusual. Trait levels are not an indicator of pathology — they describe enduring personality characteristics. `; // Domain subscales (with T-scores) + all 15 facets const domainSubs = Object.keys(DOMAINS).map((k) => { const v = result.domains[k]; const isHigh = v.T >= 56; const note = `T = ${v.T} (mean ${v.mean.toFixed(2)} / 5). Level: ${v.level}. ` + (isHigh ? `Tends to be ${DOMAINS[k].high}.` : (v.T < 45 ? `Tends to be ${DOMAINS[k].low}.` : `Within the average range.`)); return { label: `Domain · ${DOMAINS[k].name} (${DOMAINS[k].short})`, raw: v.T, max: 80, threshold: 50, valueLabel: `T = ${v.T} · ${v.level}`, note, }; }); // Facets grouped by domain const facetSubs = []; for (const d of Object.keys(DOMAINS)) { const facetsInDomain = Object.keys(FACET_LABELS).filter(f => result.facets[f].domain === d); for (const f of facetsInDomain) { const v = result.facets[f]; facetSubs.push({ label: `Facet · ${FACET_LABELS[f]} (${DOMAINS[d].short})`, raw: Math.round(v.mean * 20), max: 100, threshold: Math.round(FACET_NORMS[f] * 20), valueLabel: `M = ${v.mean.toFixed(2)} / 5 · ${v.level}`, note: `Population mean (US norm, Soto & John 2017): ${FACET_NORMS[f].toFixed(2)}.`, }); } } const subscaleEntries = [...domainSubs, ...facetSubs]; const context = ` The Big Five Inventory-2 (BFI-2) is the scientifically current full-length instrument for the hierarchical assessment of personality within the Big Five model: five domains (Extraversion, Agreeableness, Conscientiousness, Negative Emotionality, Open-Mindedness) plus three facets per domain (15 in total). It supersedes the older NEO-FFI and BFI and is available open source (Soto & John, UC Berkeley). The German adaptation (Danner et al. 2019) shows very good internal consistencies (α 0.83–0.91 per domain, α 0.70–0.83 per facet) and is the scientific reference version in the German-speaking region. Big Five scores are relatively stable across the lifespan (correlation 0.6–0.8 over 10 years). `; const next = []; if (result.domains.N.T >= 65) { next.push("High Negative Emotionality (T ≥ 65) is associated with an elevated risk of stress, anxiety and depressive episodes. If you experience subjective distress, supplementary assessment with PHQ-9 / GAD-7 / WHODAS is advisable."); } if (result.facets.depression && result.facets.depression.mean >= 3.5) { next.push("The \"Depression\" facet is markedly elevated — although the BFI is not a diagnostic tool, an additional PHQ-9 assessment is worthwhile for gauging severity."); } next.push("Big Five profiles are well suited to career guidance, couples assessment and coaching — they help you use strengths more deliberately and anticipate sources of friction."); next.push("A single self-rating reflects your self-image — an outside perspective (e.g. a partner or supervisor) often yields a clearer overall picture (self-/other-rating correlation approx. 0.4–0.6)."); next.push("Print this report as a PDF to compare your profile over time or discuss it with a professional."); const d = result.domains; return { title: "Your Big Five Personality Profile", sub: "A dimensional profile across five domains and 15 facets — not an indicator of pathology.", value: `${d.E.T}/${d.A.T}/${d.C.T}/${d.N.T}/${d.O.T}`, unit: "T-scores E/A/C/N/O", gauge: null, customGaugeHTML: customSVG, hideCrisis: true, flag: "low", interpretationHTML: interp, subscales: subscaleEntries, contextHTML: context, nextSteps: next, }; } return { id: "bfi2", meta: { title: "BFI-2 · Personality Profile (Big Five, 60 items)", pageTitle: "BFI-2 — Personality · brainScreener", eyebrow: "Personality · Big Five", intro: `The Big Five Inventory-2 (BFI-2) is the scientifically current full-length instrument (Soto & John 2017) for the hierarchical assessment of personality — 5 domains plus 15 facets (3 per domain). 60 items, German validation by Danner et al. 2019. Not a test of pathology: the result describes your individual personality profile with a high level of differentiation.`, durationText: "approx. 10–14 minutes", itemsText: "60 items · 5 domains · 15 facets", sources: "Soto & John 2017 · Danner et al. (dt.) 2019", testPath: "/brainscreener/bfi2.html", retestPath: "/brainscreener/bfi2.html", resultPath: "/brainscreener/bfi2-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "BFI-2 · Self-Description", intro: "To what extent do you agree with the following statements about yourself? Please answer all items spontaneously.", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/charakter-data.js ============================================================================== // Character profile - Dark Tetrad (brainscreener, in-house instrument) — English version // Model: four "dark" character traits as continuous, subclinical // expressions of normal personality (everyone carries a bit of each). // // Dimensions (with clear, direct type names): // N - Narcissism -> "The Narcissist" (gold) // M - Machiavellianism -> "The Manipulator" (blue/teal) // P - Psychopathy -> "The Psychopath" (red) [subclinical: fearlessness, impulsivity; also "sociopath"] // S - Sadism -> "The Provocateur" (anthracite) [everyday form: provocation, dark humour] // // Background / loosely based on (items are our own, freely worded): // - Paulhus & Williams (2002): The Dark Triad of Personality. // - Jones & Paulhus (2014): SD3 - Short Dark Triad. // - Jonason & Webster (2010): Dirty Dozen. // - Buckels, Jones & Paulhus (2013): Everyday Sadism. // - Moshagen, Hilbig & Zettler (2018): The Dark Core / D factor. // // IMPORTANT: This is NOT a clinical instrument and NOT a diagnosis. It is a // judgement-free self-reflection profile of normal character tendencies. // // Response scale 1..5 (agreement). Reverse items are re-keyed in evaluate() (6 - raw value). window.TEST_DATA = (function () { const SCALE = { cols: 5, options: [ { v: 1, label: "Strongly disagree" }, { v: 2, label: "Somewhat disagree" }, { v: 3, label: "Neither agree nor disagree" }, { v: 4, label: "Somewhat agree" }, { v: 5, label: "Strongly agree" }, ], }; // Items deliberately MIXED (not grouped by dimension) to reduce response // tendencies. dim = dimension, reverse = reverse-keyed item. const ITEMS = [ { id: "N1", dim: "N", text: "I like being the centre of attention and enjoy it when others notice me." }, { id: "M1", dim: "M", text: "I plan my moves ahead in order to reach my goal." }, { id: "P1", dim: "P", text: "In stressful or dangerous situations I stay remarkably calm." }, { id: "S1", dim: "S", text: "I enjoy provocative arguments where the sparks really fly." }, { id: "N2", dim: "N", text: "I know that I am better than most people at many things." }, { id: "M2", dim: "M", text: "You should not reveal everything you know or plan to do." }, { id: "P2", dim: "P", text: "I like taking risks that others prefer to avoid." }, { id: "S2", dim: "S", text: "Dark humour and a bit of schadenfreude make me laugh." }, { id: "N3", dim: "N", text: "I expect my achievements to be recognised and appreciated." }, { id: "M3", dim: "M", text: "Anyone who really wants to get somewhere sometimes has to play tactics." }, { id: "P3", dim: "P", text: "I live in the here and now and rarely dwell on consequences." }, { id: "S3", dim: "S", text: "I enjoy needling people with cheeky remarks to see how they react." }, { id: "N4", dim: "N", text: "Compliments and admiration noticeably do me good." }, { id: "M4", dim: "M", text: "I am good at judging how to win people over." }, { id: "P4", dim: "P", text: "Nervousness or anxiety are almost unknown to me." }, { id: "S4", dim: "S", text: "I make sure people clearly feel it when they have done something wrong." }, { id: "N5", dim: "N", text: "Deep down I feel destined for greater things." }, { id: "M5", dim: "M", text: "It is wise to keep information back for the right moment." }, { id: "P5", dim: "P", text: "I make decisions quickly and act immediately." }, { id: "S5", dim: "S", text: "I actually find a bit of friction and confrontation appealing." }, { id: "N6", dim: "N", reverse: true, text: "I do not like talking about my own successes." }, { id: "M6", dim: "M", reverse: true, text: "I always lay all my cards on the table." }, { id: "P6", dim: "P", reverse: true, text: "Before I act, I weigh the consequences carefully." }, { id: "S6", dim: "S", reverse: true, text: "If someone feels uncomfortable, I back off immediately." }, { id: "N7", dim: "N", text: "I find it hard to simply let criticism stand." }, { id: "M7", dim: "M", text: "When in doubt, the result matters more than how you get there." }, { id: "P7", dim: "P", text: "Routine and doing the same thing over and over bore me quickly." }, { id: "S7", dim: "S", text: "Secretly I enjoy seeing someone who deserves it being shown up." }, ]; // ---------- Archetypes (content for the report) ---------- const ARCHETYPES = { N: { key: "N", name: "The Narcissist", trait: "Narcissism", color: "#F0B90B", tagline: "You radiate self-confidence and enjoy the big stage.", desc: "The Narcissist believes in himself, wants to be seen and thrives on recognition. Behind the self-assurance there is often a fine sense of how one comes across — and a strong need for affirmation.", examples: [ "You like steering conversations towards yourself and talk vividly about your successes.", "Praise and admiration give you a noticeable lift.", "You feel at ease in leadership or limelight roles.", "Criticism hits you harder than you admit on the outside.", ], strengths: [ "Charisma and self-confidence that carry others along.", "The courage to show yourself and take on responsibility.", "Infectious enthusiasm — you can win people over to a cause.", ], tips: [ "Practise active listening: ask three questions before you talk about yourself.", "Share the stage — praise you pass on comes back amplified.", "Build self-worth from within (your own values, your own standards), independent of applause.", "Seek honest feedback and sit with the first impulse to defend yourself.", ], }, M: { key: "M", name: "The Manipulator", trait: "Machiavellianism", color: "#4FA3B8", tagline: "You pull the strings in the background and keep a cool overview.", desc: "The Manipulator acts with foresight, calculation and considerable insight into people. He does not reveal everything and deploys others precisely where they are useful to him — a strength that can, however, cost trust in relationships.", examples: [ "You plan several steps ahead and keep your goal in sight.", "You do not reveal everything you know or intend.", "In negotiations you stay calm and matter-of-fact.", "You quickly size up how to win people over.", ], strengths: [ "Overview, planning and a cool head in a crisis.", "Negotiating skill and a feel for group dynamics.", "You rarely get side-tracked — the goal stays in focus.", ], tips: [ "Deliberately risk transparency where trust matters more than an advantage.", "Maintain a few relationships entirely without ulterior motives — simply because they do you good.", "See extending trust as an investment, not a risk.", "Ask yourself: am I serving only the outcome right now — or also the person in front of me?", ], }, P: { key: "P", name: "The Psychopath", trait: "Psychopathy / sociopathy", color: "#ff5a4f", tagline: "You stay ice-cold where others hesitate — fear and remorse are foreign to you.", desc: "The Psychopath is fearless, cool and decisive. He lives in the moment, seeks the thrill and is hardly slowed down by guilt. What is meant here is a normal, subclinical character tendency (courage, low anxiety, impulsivity, little emotional resonance) — expressly not a clinical diagnosis.", examples: [ "When others panic, you stay calm and able to act.", "You take risks that others find too daring.", "You decide fast and execute immediately.", "Routine and repetition bore you quickly.", ], strengths: [ "Courage and strong nerves, especially under pressure.", "Decisiveness — you act while others are still hesitating.", "A composure that calms the people around you too.", ], tips: [ "Sleep on big decisions for a night — give the consequences time.", "Before risky moves, briefly run through the worst-case scenario.", "Channel the craving for thrills deliberately (sport, projects) instead of suppressing it.", "Ask a trusted person for an outside view before you charge ahead.", ], }, S: { key: "S", name: "The Provocateur", trait: "Sadism (everyday form)", color: "#9aa0b5", tagline: "You can dish it out — friction, dark humour and schadenfreude appeal to you.", desc: "The Provocateur likes to stir things up and can seriously dish it out: pointed remarks, dark humour, a certain pleasure in watching others squirm. This ranges from harmless teasing to making people distinctly feel that they have done something wrong. What is meant is the everyday form — not the infliction of real suffering. This is exactly where mindfulness pays off, because the line between teasing and demeaning is thin.", examples: [ "You enjoy heated arguments where things really get going.", "Dark humour and a little schadenfreude — you cannot suppress a grin.", "You make people distinctly feel it when they have done something wrong — sometimes more than once.", "Sharp, quick-witted comments come to you easily.", ], strengths: [ "Directness and quick wit — you say out loud what others do not dare to.", "You can withstand tension and conflict instead of dodging them.", "Breaking taboos as a source of humour and creativity.", ], tips: [ "Watch for the point where teasing turns into putting someone down — constant criticism wears people down more than you think.", "Rule of thumb: someone who hears a hundred times that they do everything wrong will eventually believe it. Praise about three times as often as you criticise.", "Separate criticism of the issue (helps) from criticism of the person (hurts) — criticise the behaviour, not the human being.", "Before a jab, ask yourself: do I want to help right now — or to wound?", "Channel the appetite for friction into debate, sport, gaming or art.", ], }, }; const DIMS = ["N", "M", "P", "S"]; // ---------- Scoring ---------- function evaluate(answers) { const raw = (id) => (typeof answers[id] === "number" ? answers[id] : 3); const itemScore = (it) => { const v = raw(it.id); return it.reverse ? (6 - v) : v; }; const scores = {}; DIMS.forEach((d) => { const items = ITEMS.filter((it) => it.dim === d); const sum = items.reduce((s, it) => s + itemScore(it), 0); const n = items.length; const min = n * 1, max = n * 5; const pct = Math.round(((sum - min) / (max - min)) * 100); const mean = Math.round((sum / n) * 100) / 100; scores[d] = { raw: sum, n, min, max, pct, mean }; }); // Order by strength (descending); ties broken by fixed dimension order const order = [...DIMS].sort((a, b) => { if (scores[b].pct !== scores[a].pct) return scores[b].pct - scores[a].pct; return DIMS.indexOf(a) - DIMS.indexOf(b); }); const spread = scores[order[0]].pct - scores[order[order.length - 1]].pct; return { scores, order, dominant: order[0], spread, balanced: spread <= 12, }; } return { id: "charakter", archetypes: ARCHETYPES, dims: DIMS, meta: { title: "Character profile · Dark Tetrad", pageTitle: "Character profile — Dark Tetrad · brainScreener", eyebrow: "Personality · Dark character traits", intro: `This instrument draws your personal character profile along the four scientifically described "dark" character traits — the Dark Tetrad. Everyone carries a bit of all four; the test shows which trait stands out most in you. There is no "good" or "bad" — for each trait you receive strengths, typical behaviours and concrete tips. And we do not talk around it: the four types are called what they are called — plain language instead of sugar-coating. It is expressly not a judgement of you as a person.`, durationText: "approx. 6–8 minutes", itemsText: "28 statements · 4 dimensions", sources: "Dark Tetrad · based on Paulhus & Williams 2002, Jones & Paulhus 2014 (SD3), Buckels et al. 2013", testPath: "/brainscreener/character.html", retestPath: "/brainscreener/character.html", resultPath: "/brainscreener/character-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, resultUi: { balancedTrait: "Balanced profile", balancedName: "A balanced mix", balancedIntro: "Your profile is remarkably balanced — no single trait clearly stands out. Depending on the situation, you show different sides of yourself. You will probably recognise yourself in several of the types below.", domIntro: (dom, domPct, sec, secPct) => `Everyone carries something of all four traits — what shows most strongly in you is ${dom.name} (${domPct} %). ${dom.tagline} ` + `The runner-up is ${sec.name} (${secPct} %). ` + `This does not mean that you "are like that" — it only shows which tendency shines through most in you.`, badgeTop: "stands out", badgeDominant: "Your strongest trait", colExamples: "How it shows in everyday life", colStrengths: "Strengths", colTips: "Tips & what you can work on", wheelBalanced: "balanced", wheelDominant: "strongest trait", }, sections: [ { id: "main", title: "Your character profile · 28 statements", intro: "How much does each statement apply to you? Answer spontaneously and honestly — there are no right or wrong answers.", items: ITEMS, scale: SCALE, }, ], evaluate, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/eat26-data.js ============================================================================== // EAT-26 - Eating Attitudes Test (26 items) // Sources: // - Garner DM, Olmsted MP, Bohr Y, Garfinkel PE (1982). The Eating Attitudes Test: // psychometric features and clinical correlates. Psychol Med. 12(4):871-8. // - Garner DM (2007). EAT-26: Self-Test. Eating Disorder Information Resource. // - Berger U, Wick K, Brix C et al. (2011). Screening of disordered eating: German EAT-26. // // 26 items, 6-point scale. Scoring: // "Always" = 3, "Usually" = 2, "Often" = 1, "Sometimes/Rarely/Never" = 0. // Item 25 is REVERSE: "Always/Usually/Often" = 0, "Sometimes" = 1, "Rarely" = 2, "Never" = 3. // Total cutoff: >= 20 = clinically relevant, further assessment indicated. // Subscale cutoffs (Garner 2007): Diet >= 10, Bulimia >= 4, Oral Control >= 4. window.TEST_DATA = (function () { const SCALE = { cols: 6, options: [ { v: 5, label: "Always" }, { v: 4, label: "Usually" }, { v: 3, label: "Often" }, { v: 2, label: "Sometimes" }, { v: 1, label: "Rarely" }, { v: 0, label: "Never" }, ], }; // Standard scoring: v 5→3, 4→2, 3→1, 2/1/0→0 function score(v) { return v === 5 ? 3 : v === 4 ? 2 : v === 3 ? 1 : 0; } // Reverse scoring for item 25: 5/4/3→0, 2→1, 1→2, 0→3 function scoreReverseExact(v) { return v === 2 ? 1 : v === 1 ? 2 : v === 0 ? 3 : 0; } const ITEMS = [ { id: "E1", sub: "diet", text: "Am terrified about being overweight." }, { id: "E2", sub: "oral", text: "Avoid eating when I am hungry." }, { id: "E3", sub: "bulimia", text: "Find myself preoccupied with food." }, { id: "E4", sub: "bulimia", text: "Have gone on eating binges where I feel that I may not be able to stop." }, { id: "E5", sub: "oral", text: "Cut my food into small pieces." }, { id: "E6", sub: "diet", text: "Aware of the calorie content of foods that I eat." }, { id: "E7", sub: "diet", text: "Particularly avoid food with a high carbohydrate content (i. e. bread, rice, potatoes, etc.)." }, { id: "E8", sub: "oral", text: "Feel that others would prefer if I ate more." }, { id: "E9", sub: "bulimia", text: "Vomit after I have eaten." }, { id: "E10", sub: "diet", text: "Feel extremely guilty after eating." }, { id: "E11", sub: "diet", text: "Am preoccupied with a desire to be thinner." }, { id: "E12", sub: "diet", text: "Think about burning up calories when I exercise." }, { id: "E13", sub: "oral", text: "Other people think that I am too thin." }, { id: "E14", sub: "diet", text: "Am preoccupied with the thought of having fat on my body." }, { id: "E15", sub: "oral", text: "Take longer than others to eat my meals." }, { id: "E16", sub: "diet", text: "Avoid foods with sugar in them." }, { id: "E17", sub: "diet", text: "Eat diet foods." }, { id: "E18", sub: "bulimia", text: "Feel that food controls my life." }, { id: "E19", sub: "oral", text: "Display self-control around food." }, { id: "E20", sub: "oral", text: "Feel that others pressure me to eat." }, { id: "E21", sub: "bulimia", text: "Give too much time and thought to food." }, { id: "E22", sub: "diet", text: "Feel uncomfortable after eating sweets." }, { id: "E23", sub: "diet", text: "Engage in dieting behavior." }, { id: "E24", sub: "diet", text: "Like my stomach to be empty." }, { id: "E25", sub: "bulimia", text: "Enjoy trying new rich foods.", reverse: true }, { id: "E26", sub: "diet", text: "Have the impulse to vomit after meals." }, ]; const SUB_LABELS = { diet: "Dieting", bulimia: "Bulimia & Food Preoccupation", oral: "Oral Control", }; const SUB_CUTOFFS = { diet: 10, bulimia: 4, oral: 4 }; const SUB_MAX = { diet: 39, bulimia: 18, oral: 21 }; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); let total = 0; const subs = { diet: 0, bulimia: 0, oral: 0 }; for (const it of ITEMS) { const raw = get(it.id); const s = it.reverse ? scoreReverseExact(raw) : score(raw); total += s; subs[it.sub] += s; } const cutoffReached = total >= 20; const subFlags = {}; for (const k of Object.keys(subs)) subFlags[k] = subs[k] >= SUB_CUTOFFS[k]; let flag; if (total >= 30 || subs.bulimia >= 4) flag = "high"; else if (cutoffReached) flag = "moderate"; else if (Object.values(subFlags).some(Boolean)) flag = "moderate"; else flag = "low"; return { total, max: 78, subs, subFlags, cutoffReached, flag }; } function renderResult(result) { const titleMap = { low: "Unremarkable eating behaviour screening", moderate: "Indications of disordered eating", high: "Consistent with clinically relevant eating disorder symptoms", }; const subMap = { low: "The scores are below the clinical cutoff (≥ 20).", moderate: "An assessment by a physician or a service specialising in eating disorders is recommended.", high: "A prompt specialist medical assessment is strongly recommended.", }; const interp = ` Your EAT-26 total score is ${result.total} of 78 points. ${result.cutoffReached ? `The established cutoff of ≥ 20 (Garner et al. 1982, confirmed in Berger et al. 2011 for the German version) has been reached — this corresponds to a clinically relevant risk of disordered eating and should lead to a specialist medical assessment.` : `The established cutoff of ≥ 20 has not been reached.`} ${result.subFlags.bulimia ? ` The Bulimia subscale is elevated — this calls for particular attention to binge eating, vomiting, and excessive preoccupation with food.` : ""} ${result.subFlags.diet ? ` The Dieting subscale is elevated — restrictive eating behaviour and a drive for thinness are clearly pronounced.` : ""} `; const subscaleEntries = [ { label: "EAT-26 total score", raw: result.total, max: 78, threshold: 20, note: `Cutoff for further assessment: ≥ 20. ${result.cutoffReached ? "Cutoff reached." : "Cutoff not reached."}` }, ...Object.keys(SUB_LABELS).map((k) => ({ label: `Subscale · ${SUB_LABELS[k]}`, raw: result.subs[k], max: SUB_MAX[k], threshold: SUB_CUTOFFS[k], note: `Cutoff: ≥ ${SUB_CUTOFFS[k]}. ${result.subFlags[k] ? "Elevated." : "Within the normal range."}`, })), ]; const context = ` The Eating Attitudes Test (EAT-26) is the most widely used self-report screening instrument for eating disorders worldwide. It dimensionally assesses drive for thinness, binge eating, and oral control — but not a specific diagnosis (anorexia, bulimia, binge eating disorder). A confirmed diagnosis requires a clinical interview (e. g. EDE or SIAB-EX) as well as body weight/BMI, gynaecological, and somatic findings. Reference period: the past 6 months. `; const next = []; if (result.flag === "high") { next.push("Arrange an appointment promptly with a service specialising in eating disorders."); next.push("In the case of acute medical risk (e. g. low BMI < 17.5, electrolyte imbalance, cardiac arrhythmia), a somatic assessment is urgently needed."); next.push("Evidence-based, effective depending on the diagnosis: CBT-E (Fairburn), MANTRA, family-based treatment (FBT for adolescents), and for BED also SSRIs/lisdexamfetamine (German S3 guideline 2018 / NICE NG69 2024)."); } else if (result.flag === "moderate") { next.push("An assessment by a physician or a service specialising in eating disorders is recommended, especially if your weight or eating behaviour is distressing you or your weight has changed significantly."); next.push("Watch for warning signs: binge eating with loss of control, vomiting, excessive exercise, restrictive eating patterns, pronounced preoccupation with body and weight."); } else { next.push("The scores are in the largely unremarkable range. Stay attentive should your eating behaviour change."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: result.total, unit: `/ 78 points`, gauge: Math.min(1, result.total / 40), flag: result.flag, interpretationHTML: interp, subscales: subscaleEntries, contextHTML: context, nextSteps: next, }; } return { id: "eat26", meta: { title: "EAT-26 · Eating Disorder Screening", pageTitle: "EAT-26 — Eating Disorder Screening · brainScreener", eyebrow: "Eating disorders", intro: `The Eating Attitudes Test (EAT-26) is the most widely used self-report screener for eating disorder symptoms worldwide. 26 items, three subscales (Dieting, Bulimia, Oral Control). It is no substitute for a diagnosis, but it is well established as an early warning tool.`, durationText: "approx. 5–7 minutes", itemsText: "26 items · 3 subscales", sources: "Garner, Olmsted, Bohr & Garfinkel 1982 · Garner 2007 · Berger et al. (dt.) 2011", testPath: "/brainscreener/eat26.html", retestPath: "/brainscreener/eat26.html", resultPath: "/brainscreener/eat26-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "EAT-26 · Past 6 months", intro: "How often do the following statements apply to you?", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/gad7-data.js ============================================================================== // GAD-7 - Generalized Anxiety Disorder 7-Item Scale // Sources: // - Spitzer RL, Kroenke K, Williams JBW, Loewe B. A brief measure for assessing // generalized anxiety disorder: the GAD-7. Arch Intern Med. 2006;166(10):1092-7. // - Loewe B et al., Validation and standardization of the GAD-7 in the general // German population, J Affect Disord. 2008;114(1-3):163-73. // - NICE NG222 (2022, update 2024): GAD-7 as first-line instrument for generalised anxiety. // - DSM-5-TR criteria for GAD (APA 2022). // // Response scale 0..3 for all 7 items, reference period: last 2 weeks. // Cutoffs (manual / Spitzer 2006): // 0-4 minimal, 5-9 mild, 10-14 moderate, 15-21 severe. // Clinically relevant cutoff for GAD: >= 10 (sens. 89%, spec. 82%). // Cutoff >= 8 additionally indicates possible panic disorder / social phobia / PTSD. window.TEST_DATA = (function () { const SCALE = { cols: 4, options: [ { v: 0, label: "Not at all" }, { v: 1, label: "Several days" }, { v: 2, label: "More than half the days" }, { v: 3, label: "Nearly every day" }, ], }; const ITEMS = [ { id: "G1", text: "Feeling nervous, anxious or on edge" }, { id: "G2", text: "Not being able to stop or control worrying" }, { id: "G3", text: "Worrying too much about different things" }, { id: "G4", text: "Trouble relaxing" }, { id: "G5", text: "Being so restless that it is hard to sit still" }, { id: "G6", text: "Becoming easily annoyed or irritable" }, { id: "G7", text: "Feeling afraid as if something awful might happen" }, ]; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); const total = ITEMS.reduce((s, it) => s + get(it.id), 0); let severity, flag; if (total <= 4) { severity = "minimal"; flag = "low"; } else if (total <= 9) { severity = "mild"; flag = "low"; } else if (total <= 14) { severity = "moderate"; flag = "moderate"; } else { severity = "severe"; flag = "high"; } return { total, max: 21, severity, flag, cutoffReached: total >= 10, panicHint: total >= 8, }; } function renderResult(result) { const titleMap = { low: result.total <= 4 ? "Unremarkable screening" : "Mild anxiety symptoms", moderate: "Moderate anxiety symptoms", high: "Severe anxiety symptoms", }; const subMap = { low: result.total <= 4 ? "No indications of a clinically relevant anxiety disorder." : "Symptoms are present but remain below the clinical cutoff — monitoring is advisable.", moderate: "The total score falls within the range that suggests a specialist assessment.", high: "The picture is consistent with an anxiety disorder requiring treatment.", }; const interp = ` Your GAD-7 total score is ${result.total} of 21 points — a ${result.severity} level of severity. ${result.cutoffReached ? `The established cutoff of ≥ 10 has been reached; validation studies report a sensitivity of approx. 89 % and specificity of approx. 82 % for generalised anxiety disorder at this threshold (Spitzer et al. 2006; Plummer et al. meta-analysis 2016; NICE NG222).` : (result.panicHint ? `The GAD cutoff of 10 has not been reached, but the score is ≥ 8 — in this range, validation studies show additional indications of panic disorder, social phobia or PTSD symptoms (Kroenke et al. 2007).` : `The cutoff of ≥ 10 has not been reached. If the distress persists over several weeks, a specialist assessment is nevertheless advisable.`)} `; const subscales = [ { label: "GAD-7 total score", raw: result.total, max: 21, threshold: 10, note: `Cutoff for clinically relevant GAD: ≥ 10. ${result.cutoffReached ? "Cutoff reached." : "Cutoff not reached."} Severity: ${result.severity}.`, }, ]; const context = ` The Generalized Anxiety Disorder Scale (GAD-7) is the most widely used self-report measure internationally for assessing generalised anxiety symptoms and is considered the sister instrument of the PHQ-9. It was developed in 2006 by Spitzer, Kroenke & Williams and, despite its focus on GAD, also serves as a good initial screener for panic disorder, social phobia and PTSD (Kroenke et al. 2007). NICE NG222 (2022, update 2024) recommends it as the first-line instrument in primary care. `; const next = []; if (result.flag === "high") { next.push("Arrange an appointment promptly with your general practitioner or directly with a psychiatric / psychotherapeutic practice."); next.push("A confirmed diagnosis requires a clinical interview and the exclusion of organic causes (e. g. hyperthyroidism, caffeine/substances, cardiac arrhythmia)."); next.push("Evidence-based treatments for GAD: cognitive behavioural therapy (CBT), and in more severe cases SSRIs/SNRIs (grade A recommendation, NICE / German S3 guideline 2021)."); } else if (result.flag === "moderate") { next.push("A specialist or psychotherapeutic assessment is recommended, particularly if the symptoms have persisted for more than 6 months (DSM-5-TR duration criterion for GAD)."); next.push("Consider accompanying progress monitoring — the GAD-7 is a standardised instrument well suited for this purpose."); } else { if (result.panicHint) next.push("Your score is below the GAD cutoff, but within a range that may additionally indicate panic or social phobia symptoms. A differentiated assessment is advisable if you feel distressed."); next.push("The scores are in the largely unremarkable range. Stay attentive in case the symptoms change."); next.push("Sleep, exercise, reducing caffeine/alcohol and structured breathing/relaxation exercises are effective everyday measures."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: result.total, unit: `/ 21 points · ${result.severity}`, gauge: result.total / 21, flag: result.flag, interpretationHTML: interp, subscales, contextHTML: context, nextSteps: next, }; } return { id: "gad7", meta: { title: "GAD-7 · Anxiety Screening", pageTitle: "GAD-7 — Anxiety Screening · brainScreener", eyebrow: "Generalised Anxiety Disorder", intro: `This instrument is the Generalized Anxiety Disorder Scale (GAD-7) — the most widely used self-report test worldwide for assessing generalised anxiety symptoms. Seven items, reference period: last 2 weeks.`, durationText: "approx. 2–3 minutes", itemsText: "7 items", sources: "Spitzer, Kroenke & Williams 2006 · Löwe et al. (dt.) 2008 · NICE NG222 (2024)", testPath: "/brainscreener/gad7.html", retestPath: "/brainscreener/gad7.html", resultPath: "/brainscreener/gad7-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "GAD-7 · Last 2 weeks", intro: "Over the last 2 weeks, how often have you been bothered by the following problems?", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/iq-data.js ============================================================================== // IQ Test - Item bank and scoring (English version) // Structure based on CHC theory (Cattell-Horn-Carroll): // Gf - Fluid intelligence (matrix reasoning) // Gq - Quantitative reasoning (number series) // Gc - Crystallized intelligence (verbal analogies) // Gf/Gc - Logical reasoning (syllogisms, inference) // 40 items, increasing difficulty, normed IQ estimate (M=100, SD=15). window.IQ_DATA = (function () { const COLOR = { INK: "#1F3A3D", SAGE: "#A9B8A3", GOLD: "#C9A86B", LIGHT: "#DCD7CD" }; // -------------------- SVG Primitive -------------------- function svgWrap(inner, viewBox = "0 0 100 100") { return `${inner}`; } function dot(cx, cy, r = 6, color = COLOR.INK) { return ``; } function dotsLine(n, color = COLOR.INK) { const spacing = 14; const startX = 50 - ((n - 1) * spacing) / 2; let out = ""; for (let i = 0; i < n; i++) out += dot(startX + i * spacing, 50, 5, color); return out; } function shape(kind, fill = "none", { cx = 50, cy = 50, size = 1, rot = 0, color = COLOR.INK, sw = 3 } = {}) { const r = 24 * size, s = 42 * size; const fillAttr = fill === "full" ? `fill="${color}"` : fill === "half" ? `fill="${color}" fill-opacity="0.45" stroke="${color}" stroke-width="${sw}"` : `fill="none" stroke="${color}" stroke-width="${sw}"`; if (kind === "circle") return ``; if (kind === "square") { const x = cx - s / 2, y = cy - s / 2; return ``; } if (kind === "triangle") { const p1 = `${cx},${cy - r}`; const p2 = `${cx - r * 0.866},${cy + r * 0.55}`; const p3 = `${cx + r * 0.866},${cy + r * 0.55}`; return ``; } if (kind === "diamond") { const x = cx - r / 1.3, y = cy - r / 1.3, ss = r * 1.55; return ``; } if (kind === "hex") { const pts = []; for (let i = 0; i < 6; i++) { const a = (Math.PI / 3) * i - Math.PI / 2; pts.push(`${cx + r * Math.cos(a)},${cy + r * Math.sin(a)}`); } return ``; } return ""; } function arrow(rot = 0, color = COLOR.INK) { return ` `; } function compoundDots(n, kind = "circle") { // n shapes arranged horizontally, fitted to viewBox 0..100 const spacing = n <= 1 ? 0 : Math.min(26, 84 / (n - 1)); const size = n >= 6 ? 0.26 : n >= 5 ? 0.3 : 0.35; const startX = 50 - ((n - 1) * spacing) / 2; let out = ""; for (let i = 0; i < n; i++) { out += shape(kind, "full", { cx: startX + i * spacing, cy: 50, size }); } return out; } function positionDot(corner) { // dot in one of 8 outer positions around a centered square frame const positions = { "N": [50, 22], "NE": [78, 22], "E": [78, 50], "SE": [78, 78], "S": [50, 78], "SW": [22, 78], "W": [22, 50], "NW": [22, 22], "C": [50, 50], }; const [cx, cy] = positions[corner] || [50, 50]; return `${dot(cx, cy, 7)}`; } function cell(inner) { return svgWrap(inner); } // -------------------- 3x3 Grid renderer -------------------- function gridSVG(cells) { // cells: array of 9 inner-SVG strings; cells[8] is the missing one -> "?" const size = 105, gap = 8, total = 3 * size + 2 * gap; // 331 let inner = ""; for (let i = 0; i < 9; i++) { const r = Math.floor(i / 3), c = i % 3; const x = c * (size + gap), y = r * (size + gap); const isMissing = (i === 8); const bg = isMissing ? `` : ``; inner += bg; if (isMissing) { inner += `?`; } else { // embed an inner svg inner += `${cells[i]}`; } } return `${inner}`; } function optionSVG(inner) { return svgWrap(inner); } // -------------------- Matrix items -------------------- const M = []; // matrix items // M1: Dots count progression (+1 per cell within each row, +1 per row) M.push({ id: "M1", type: "matrix", domain: "Gf", level: 1, cells: [ dotsLine(1), dotsLine(2), dotsLine(3), dotsLine(2), dotsLine(3), dotsLine(4), dotsLine(3), dotsLine(4), null, ], options: [dotsLine(3), dotsLine(4), dotsLine(5), dotsLine(6), dotsLine(2), dotsLine(7)], answer: 2, }); // M2: Latin square of shapes (each row & column contains circle/square/triangle exactly once) const sC = shape("circle", "full"), sS = shape("square", "full"), sT = shape("triangle", "full"); M.push({ id: "M2", type: "matrix", domain: "Gf", level: 1, cells: [ sC, sS, sT, sS, sT, sC, sT, sC, null, ], options: [sC, sS, sT, shape("diamond", "full"), shape("hex", "full"), shape("triangle", "none")], answer: 1, }); // M3: Fill progression: each row keeps shape, fill goes none->half->full M.push({ id: "M3", type: "matrix", domain: "Gf", level: 1, cells: [ shape("circle", "none"), shape("circle", "half"), shape("circle", "full"), shape("square", "none"), shape("square", "half"), shape("square", "full"), shape("triangle", "none"), shape("triangle", "half"), null, ], options: [ shape("triangle", "none"), shape("triangle", "half"), shape("triangle", "full"), shape("circle", "full"), shape("square", "full"), shape("diamond", "full"), ], answer: 2, }); // M4: Shape rotates 45 degrees across each row M.push({ id: "M4", type: "matrix", domain: "Gf", level: 2, cells: [ shape("triangle", "full", { rot: 0 }), shape("triangle", "full", { rot: 45 }), shape("triangle", "full", { rot: 90 }), shape("triangle", "full", { rot: 90 }), shape("triangle", "full", { rot: 135 }), shape("triangle", "full", { rot: 180 }), shape("triangle", "full", { rot: 180 }), shape("triangle", "full", { rot: 225 }), null, ], options: [ shape("triangle", "full", { rot: 0 }), shape("triangle", "full", { rot: 90 }), shape("triangle", "full", { rot: 180 }), shape("triangle", "full", { rot: 270 }), shape("triangle", "full", { rot: 315 }), shape("triangle", "none", { rot: 270 }), ], answer: 3, }); // M5: Dot position rotates 45 degrees clockwise per cell // Sequence: N, NE, E, SE, S, SW, W, NW, then ?=N const rotSeq = ["N","NE","E","SE","S","SW","W","NW"]; M.push({ id: "M5", type: "matrix", domain: "Gv", level: 2, cells: rotSeq.map((p) => positionDot(p)).concat([null]), options: [positionDot("N"), positionDot("E"), positionDot("S"), positionDot("W"), positionDot("C"), positionDot("NE")], answer: 0, }); // M6: Count progression: row 1: 1, 2, 3 circles; row 2: 2, 3, 4 squares; row 3: 3, 4, ? triangles M.push({ id: "M6", type: "matrix", domain: "Gf", level: 2, cells: [ compoundDots(1, "circle"), compoundDots(2, "circle"), compoundDots(3, "circle"), compoundDots(2, "square"), compoundDots(3, "square"), compoundDots(4, "square"), compoundDots(3, "triangle"), compoundDots(4, "triangle"), null, ], options: [ compoundDots(3, "triangle"), compoundDots(4, "triangle"), compoundDots(5, "triangle"), compoundDots(6, "triangle"), compoundDots(5, "circle"), compoundDots(5, "square"), ], answer: 2, }); // M7: Two attributes: shape (rows) x fill (cols) M.push({ id: "M7", type: "matrix", domain: "Gf", level: 2, cells: [ shape("hex", "none"), shape("hex", "half"), shape("hex", "full"), shape("diamond", "none"), shape("diamond", "half"), shape("diamond", "full"), shape("circle", "none"), shape("circle", "half"), null, ], options: [ shape("circle", "full"), shape("circle", "half"), shape("circle", "none"), shape("diamond", "full"), shape("hex", "full"), shape("square", "full"), ], answer: 0, }); // M8: Arrow rotates 90 degrees per cell, sequence: 0,90,180,270,... // Row 1: 0, 90, 180; Row 2: 90, 180, 270; Row 3: 180, 270, ? M.push({ id: "M8", type: "matrix", domain: "Gv", level: 2, cells: [ arrow(0), arrow(90), arrow(180), arrow(90), arrow(180), arrow(270), arrow(180), arrow(270), null, ], options: [arrow(0), arrow(45), arrow(90), arrow(135), arrow(180), arrow(270)], answer: 0, }); // M9: Size progression: small, medium, large per row; shape changes per row M.push({ id: "M9", type: "matrix", domain: "Gf", level: 3, cells: [ shape("circle", "full", { size: 0.4 }), shape("circle", "full", { size: 0.7 }), shape("circle", "full", { size: 1.0 }), shape("square", "full", { size: 0.4 }), shape("square", "full", { size: 0.7 }), shape("square", "full", { size: 1.0 }), shape("triangle", "full", { size: 0.4 }), shape("triangle", "full", { size: 0.7 }), null, ], options: [ shape("triangle", "full", { size: 0.4 }), shape("triangle", "full", { size: 0.7 }), shape("triangle", "full", { size: 1.0 }), shape("triangle", "none", { size: 1.0 }), shape("circle", "full", { size: 1.0 }), shape("square", "full", { size: 1.0 }), ], answer: 2, }); // M10: Complex - shape + small inner shape both rotate through sequence // Outer: circle / square / triangle (Latin square) // Inner small dot color: ink / sage / gold (also Latin square but shifted) function compound(outer, innerColor) { return shape(outer, "none") + dot(50, 50, 7, innerColor); } M.push({ id: "M10", type: "matrix", domain: "Gf", level: 3, cells: [ compound("circle", COLOR.INK), compound("square", COLOR.SAGE), compound("triangle", COLOR.GOLD), compound("square", COLOR.GOLD), compound("triangle", COLOR.INK), compound("circle", COLOR.SAGE), compound("triangle", COLOR.SAGE), compound("circle", COLOR.GOLD), null, ], // each row contains each (shape, color) such that row=(c,s,t) permutation and col contains each color // Pattern: outer cycles through (circle, square, triangle) shifted by row; color cycles too // Row 1: c-ink, s-sage, t-gold // Row 2: s-gold, t-ink, c-sage // Row 3: t-sage, c-gold, ?-? // Cells: // - outer shapes used: row 3 already has triangle, circle -> missing: square // - colors used: row 3 already has sage, gold -> missing: ink // So: square + ink dot options: [ compound("square", COLOR.INK), compound("square", COLOR.GOLD), compound("triangle", COLOR.INK), compound("circle", COLOR.INK), compound("square", COLOR.SAGE), compound("triangle", COLOR.GOLD), ], answer: 0, }); // -------------------- Number series (Gq) -------------------- const N = []; function addNumber(id, level, q, options, answerIdx) { N.push({ id, type: "numeric", domain: "Gq", level, question: q, options, answer: answerIdx }); } addNumber("N1", 1, "2, 4, 6, 8, ?", ["9", "10", "12", "14"], 1); addNumber("N2", 1, "3, 6, 12, 24, ?", ["36", "42", "48", "60"], 2); addNumber("N3", 1, "1, 4, 9, 16, ?", ["20", "23", "25", "32"], 2); addNumber("N4", 2, "1, 1, 2, 3, 5, 8, ?", ["10", "11", "13", "16"], 2); addNumber("N5", 2, "2, 5, 11, 23, ?", ["35", "41", "47", "53"], 2); addNumber("N6", 2, "81, 27, 9, 3, ?", ["0", "1", "2", "3"], 1); addNumber("N7", 2, "1, 3, 6, 10, 15, ?", ["18", "20", "21", "22"], 2); addNumber("N8", 3, "7, 14, 28, 56, ?", ["84", "98", "112", "120"], 2); addNumber("N9", 3, "5, 8, 13, 20, 29, ?", ["35", "38", "40", "42"], 2); addNumber("N10", 3, "2, 3, 5, 7, 11, ?", ["12", "13", "15", "17"], 1); addNumber("N11", 3, "1, 8, 27, 64, ?", ["100", "120", "125", "128"], 2); addNumber("N12", 4, "4, 9, 19, 39, 79, ?", ["129", "139", "159", "199"], 2); // -------------------- Verbal analogies (Gc) -------------------- const V = []; function addVerbal(id, level, q, options, answerIdx) { V.push({ id, type: "verbal", domain: "Gc", level, question: q, options, answer: answerIdx }); } addVerbal("V1", 1, "Hand : finger = foot : ?", ["Leg", "Toe", "Shoe", "Ankle"], 1); addVerbal("V2", 1, "Day : sun = night : ?", ["Star", "Darkness", "Moon", "Sleep"], 2); addVerbal("V3", 1, "Book : library = painting : ?", ["Artist", "Studio", "Gallery", "Exhibition"], 2); addVerbal("V4", 2, "Doctor : patient = teacher : ?", ["School", "Student", "Book", "Class"], 1); addVerbal("V5", 2, "Island : sea = oasis : ?", ["Sand", "Palm tree", "Desert", "Water"], 2); addVerbal("V6", 2, "Step : to walk = leap : ?", ["to leap", "to fall", "to fly", "to run"], 0); addVerbal("V7", 2, "Architect : building = composer : ?", ["Concert", "Music", "Symphony", "Orchestra"], 2); addVerbal("V8", 3, "Gram : mass = second : ?", ["Clock", "Hour", "Minute", "Time"], 3); addVerbal("V9", 3, "Word : sentence = note : ?", ["Song", "Tone", "Melody", "Instrument"], 2); addVerbal("V10", 3, "Drop : rain = grain : ?", ["Flour", "Sand", "Bread", "Field"], 1); // -------------------- Logical reasoning -------------------- const L = []; function addLogic(id, level, q, options, answerIdx) { L.push({ id, type: "logical", domain: "Gf", level, question: q, options, answer: answerIdx }); } addLogic("L1", 1, "All dogs are mammals. Bello is a dog. What necessarily follows?", [ "Bello is a mammal.", "All mammals are dogs.", "Bello barks.", "Bello has fur.", ], 0); addLogic("L2", 2, "If it rains, the road is wet. The road is wet. What necessarily follows?", [ "It is raining.", "It is not raining.", "It may be raining, but it does not have to be.", "It has rained.", ], 2); addLogic("L3", 2, "Some politicians are lawyers. All lawyers have a university degree. What necessarily follows?", [ "All politicians have a university degree.", "Some politicians have a university degree.", "Anyone with a university degree is a politician or a lawyer.", "Some lawyers are not politicians.", ], 1); addLogic("L4", 2, "A is taller than B. C is shorter than B. D is taller than A. Who is the shortest?", ["A", "B", "C", "D"], 2); addLogic("L5", 3, "Five people each shake hands with each other exactly once. How many handshakes are there?", ["8", "9", "10", "12"], 2); addLogic("L6", 3, "The following is true: “If Anna lies, then Ben lies too.” Ben is telling the truth. What necessarily follows?", [ "Anna lies.", "Anna is telling the truth.", "Both lie.", "Nothing can be concluded.", ], 1); addLogic("L7", 3, "A cube has 6 faces. How many edges does it have?", ["6", "8", "12", "16"], 2); addLogic("L8", 4, "Three cards lie side by side: one red, one green, one blue. The following holds: the red one lies to the left of the green one. The blue one lies between the other two. In what order (from left to right) do they lie?", ["red, blue, green", "blue, red, green", "red, green, blue", "green, blue, red"], 0); // -------------------- Assemble the item bank -------------------- // Order: mixed, increasing difficulty const ITEMS = []; // All items are sorted by level, then balanced by domain const allByLevel = [...M, ...N, ...V, ...L].sort((a, b) => a.level - b.level); // For better UX: balanced interleave per level ITEMS.push(...allByLevel); const TOTAL = ITEMS.length; // -------------------- Scoring -------------------- function evaluate(answers) { // answers: { itemId: chosenIndex } const byDomain = { Gf: { right: 0, total: 0 }, Gq: { right: 0, total: 0 }, Gc: { right: 0, total: 0 }, Gv: { right: 0, total: 0 } }; let correct = 0; const perItem = []; for (const it of ITEMS) { const chosen = answers[it.id]; const ok = chosen === it.answer; if (ok) correct++; const dom = byDomain[it.domain] || (byDomain[it.domain] = { right: 0, total: 0 }); dom.total += 1; if (ok) dom.right += 1; perItem.push({ id: it.id, ok, chosen: chosen ?? null, answer: it.answer, domain: it.domain, level: it.level }); } // IQ estimate: z-based with the assumptions mean=22, SD=6 for 40 items. // This calibration is representative of a mixed test of medium difficulty // and yields plausible values on the standard score scale (M=100, SD=15). const M_RAW = 22; const SD_RAW = 6; const z = (correct - M_RAW) / SD_RAW; let iq = Math.round(100 + 15 * z); iq = Math.max(60, Math.min(150, iq)); // Standard error of measurement (SEM) ~ 5 IQ points; 95% CI ~ +-10 points const ciLow = Math.max(55, iq - 10); const ciHigh = Math.min(155, iq + 10); // Percentile from z const pct = Math.round(normalCdf(z) * 100); // Classification according to common convention let band; if (iq < 70) band = "Well below average"; else if (iq < 80) band = "Below average"; else if (iq < 90) band = "Low average"; else if (iq <= 109) band = "Average"; else if (iq <= 119) band = "High average"; else if (iq <= 129) band = "Above average"; else band = "Well above average"; return { correct, total: TOTAL, iq, ciLow, ciHigh, percentile: pct, band, byDomain, perItem, }; } // Approximation of the standard normal distribution (Abramowitz/Stegun) function normalCdf(z) { const p = 0.2316419; const b1 = 0.319381530, b2 = -0.356563782, b3 = 1.781477937, b4 = -1.821255978, b5 = 1.330274429; const t = 1 / (1 + p * Math.abs(z)); const pdf = Math.exp(-z * z / 2) / Math.sqrt(2 * Math.PI); const cdf = 1 - pdf * (b1 * t + b2 * t ** 2 + b3 * t ** 3 + b4 * t ** 4 + b5 * t ** 5); return z >= 0 ? cdf : 1 - cdf; } const ui = { itemOf: (i, n) => `Task ${i} of ${n}`, answeredOf: (a, n) => `${a} / ${n} answered`, qMatrix: "Which figure completes the pattern?", qNumeric: "Which number logically continues the series?", qVerbal: "Which completion fits best?", optionLabel: (letter) => `Option ${letter}`, finishConfirm: (a, n) => `You have answered ${a} of ${n} tasks. Score the test anyway?`, resetConfirm: "Do you really want to clear all previous answers and start over?", confirmFinishOk: "Score anyway", confirmResetOk: "Delete answers", confirmCancel: "Cancel", domainLabel: { Gf: "Matrix reasoning · Fluid intelligence", Gq: "Number series · Quantitative reasoning", Gc: "Verbal analogy · Crystallized intelligence", Gv: "Visuospatial · Pattern recognition" }, }; return { ITEMS, TOTAL, evaluate, gridSVG, optionSVG, ui }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/iq-result.js ============================================================================== // IQ-Result Renderer (English version) (function () { const RESULT_KEY = "brainscreener.iq.result.v1"; let payload = window.BS_PRINT ? BS_PRINT.loadPayload(RESULT_KEY) : null; if (!payload) { try { payload = JSON.parse(sessionStorage.getItem(RESULT_KEY) || "null"); } catch { payload = null; } } if (!payload) { document.querySelector(".result-shell .container-narrow").innerHTML = `

      No result found

      Please take the test first to obtain a report.

      Go to the IQ test

      `; return; } const { ts, durationSec, probandCode } = payload; // Re-score the language-neutral answers in the language of this page // (allows printing the report in a different language). const result = (payload.answers && window.IQ_DATA && typeof window.IQ_DATA.evaluate === "function") ? window.IQ_DATA.evaluate(payload.answers) : payload.result; const LOCALE = document.documentElement.lang || "en-GB"; const date = ts ? new Date(ts) : new Date(); document.getElementById("dateStr").textContent = date.toLocaleDateString(LOCALE, { day: "2-digit", month: "long", year: "numeric" }) + " · " + date.toLocaleTimeString(LOCALE, { hour: "2-digit", minute: "2-digit" }); const code = (probandCode || "").trim(); if (code) { document.getElementById("codeRow").hidden = false; document.getElementById("codeStr").textContent = code; } // ---- Main IQ value ---- document.getElementById("iqValue").textContent = result.iq; document.getElementById("bandLabel").textContent = result.band; document.getElementById("bandHint").textContent = bandHint(result.band); const ci = `95% confidence interval: ${result.ciLow}–${result.ciHigh} · Percentile: ${result.percentile} · Raw score: ${result.correct} / ${result.total}` + (durationSec ? ` · Completion time: ${Math.floor(durationSec / 60)}:${String(durationSec % 60).padStart(2, "0")} min` : ""); document.getElementById("ciText").textContent = ci; // Gauge (IQ scale 60..145, normed) document.getElementById("gaugeWrap").innerHTML = iqGauge(result.iq); // Interpretation document.getElementById("interpretationText").innerHTML = ` Your estimated IQ score of ${result.iq} falls in the “${result.band}” range. Statistically, this corresponds to a percentile of ${result.percentile} — i.e. about ${result.percentile}% of the general population obtain the same or a lower score. Taking the standard error of measurement into account, your “true” score lies with 95 % probability between ${result.ciLow} and ${result.ciHigh}. `; // ---- Subscales / Domain Profile ---- // Unter dieser Itemzahl ist ein Domaenenwert nicht interpretierbar const MIN_DOMAIN_ITEMS = 5; const domainNames = { Gf: "Fluid intelligence (matrix reasoning, logical reasoning)", Gq: "Quantitative reasoning (number series)", Gc: "Crystallized intelligence (verbal analogies)", Gv: "Visuospatial reasoning (position patterns)", }; const subList = document.getElementById("subscaleList"); const domains = Object.keys(result.byDomain).filter((k) => result.byDomain[k].total > 0); subList.innerHTML = domains.map((k) => { const d = result.byDomain[k]; const pct = Math.round((d.right / d.total) * 100); return `
      ${domainNames[k] || k} ${d.right} / ${d.total} · ${pct} %
      ${d.total < MIN_DOMAIN_ITEMS ? `
      Only ${d.total} items — not statistically meaningful on its own.
      ` : ""}
      `; }).join(""); // ---- Distribution chart ---- document.getElementById("distributionWrap").innerHTML = distributionSVG(result.iq); // ---- Context ---- document.getElementById("contextText").innerHTML = ` Intelligence tests do not measure a person's worth, but a specific kind of cognitive performance at the present point in time. Your condition on the day (sleep, concentration, anxiety, medication) noticeably influences the result. A short online test with 40 items cannot replace a professional assessment (e.g. the WAIS-IV with 10–15 subtests), but it is well suited as a first orientation. Please discuss the result with a qualified professional (e.g. the physician or psychologist treating you), especially if the profile shows marked differences across the domains. `; // ---- Buttons ---- if (window.BS_PRINT) BS_PRINT.attachPrint(document.getElementById("btnPrint"), RESULT_KEY); else document.getElementById("btnPrint").addEventListener("click", () => window.print()); // ---- helpers ---- function bandHint(band) { return { "Well below average": "Performance level clearly below the average of the general population in the area assessed.", "Below average": "Performance level in the range occupied by approx. 7–16% of the population.", "Low average": "Just below the average range.", "Average": "Middle range, in which about half of the population falls.", "High average": "Upper part of the average range, roughly the top 25%.", "Above average": "Clearly above-average level, roughly the top 9%.", "Well above average": "Very high level, above the 97th percentile (in the range of giftedness cut-offs).", }[band] || ""; } function iqGauge(iq) { // Hoehe aus dem Bogen ableiten: 10 px Luft oben fuer die runde Strichkappe, // 36 px unten fuer die Skalenbeschriftung (sonst faellt sie aus der viewBox). const w = 360, r = 140, cx = w / 2, cy = r + 10, h = cy + 36; // IQ scale 55..145 (90 IQ points) on a semicircle const min = 55, max = 145; const value = Math.max(0, Math.min(1, (iq - min) / (max - min))); const start = Math.PI, end = 0; function arc(p) { const a = start + (end - start) * p; // In SVG zeigt +y nach unten, der Bogen liegt oben — daher cy MINUS sin. return [cx + r * Math.cos(a), cy - r * Math.sin(a)]; } const [px, py] = arc(value); const color = iq < 85 ? "var(--danger)" : iq < 115 ? "var(--sage)" : "var(--gold)"; // background arc return ` `; } function distributionSVG(iq) { // Bell curve, marker on the IQ const w = 720, h = 220, padL = 30, padR = 30, padT = 10, padB = 38; const minIQ = 55, maxIQ = 145; const xFor = (v) => padL + ((v - minIQ) / (maxIQ - minIQ)) * (w - padL - padR); const phi = (z) => Math.exp(-z * z / 2) / Math.sqrt(2 * Math.PI); const yScale = (h - padT - padB) / phi(0); // build path let d = ""; for (let v = minIQ; v <= maxIQ; v += 0.5) { const z = (v - 100) / 15; const x = xFor(v); const y = (h - padB) - phi(z) * yScale; d += (v === minIQ ? "M" : "L") + x.toFixed(1) + " " + y.toFixed(1) + " "; } // fill area const fillPath = `${d} L ${xFor(maxIQ)} ${h - padB} L ${xFor(minIQ)} ${h - padB} Z`; // marker const mx = xFor(iq); const myTop = (h - padB) - phi((iq - 100) / 15) * yScale; const ticks = [70, 85, 100, 115, 130]; const tickHTML = ticks.map((t) => { const tx = xFor(t); return ` ${t} `; }).join(""); const bands = [ { from: 55, to: 70, label: "Well below avg.", color: "var(--gold-soft)" }, { from: 70, to: 85, label: "Below avg.", color: "var(--gold-soft)" }, { from: 85, to: 115, label: "Average", color: "var(--sage-soft)" }, { from: 115, to: 130, label: "Above avg.", color: "var(--gold-soft)" }, { from: 130, to: 145, label: "Well above avg.", color: "var(--gold-soft)" }, ]; const bandRects = bands.map((b) => { const x1 = xFor(b.from), x2 = xFor(b.to); return ``; }).join(""); return ` ${bandRects} IQ ${iq} ${tickHTML} `; } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/mdq-data.js ============================================================================== // MDQ - Mood Disorder Questionnaire // Sources: // - Hirschfeld RMA, Williams JB, Spitzer RL, Calabrese JR et al. (2000). Development // and validation of a screening instrument for bipolar spectrum disorder: the // Mood Disorder Questionnaire. Am J Psychiatry 157(11):1873-5. // - Hu C et al. (2020). Meta-analysis of the MDQ for bipolar spectrum disorders. // - DSM-5-TR criteria for Bipolar I / II / Bipolar Spectrum (APA 2022). // // 13 yes/no items on lifetime manic/hypomanic symptoms + 2 follow-up questions: // Question 14: did several symptoms occur AT THE SAME TIME? (yes/no) // Question 15: severity of the problems these caused (0-3) // Positive-screen algorithm (Hirschfeld 2000): // >= 7/13 yes AND question 14 = yes AND question 15 >= 2 (moderate/serious). window.TEST_DATA = (function () { const YN = { cols: 2, options: [ { v: 1, label: "Yes" }, { v: 0, label: "No" }, ] }; const SEVERITY = { cols: 4, options: [ { v: 0, label: "No problem" }, { v: 1, label: "Minor problem" }, { v: 2, label: "Moderate problem" }, { v: 3, label: "Serious problem" }, ] }; const SYMPTOMS = [ { id: "M1", text: "...you felt so good or so hyper that other people thought you were not your normal self or you were so hyper that you got into trouble?" }, { id: "M2", text: "...you were so irritable that you shouted at people or started fights or arguments?" }, { id: "M3", text: "...you felt much more self-confident than usual?" }, { id: "M4", text: "...you got much less sleep than usual and found you didn't really miss it?" }, { id: "M5", text: "...you were much more talkative or spoke much faster than usual?" }, { id: "M6", text: "...thoughts raced through your head or you couldn't slow your mind down?" }, { id: "M7", text: "...you were so easily distracted by things around you that you had trouble concentrating or staying on track?" }, { id: "M8", text: "...you had much more energy than usual?" }, { id: "M9", text: "...you were much more active or did many more things than usual?" }, { id: "M10", text: "...you were much more social or outgoing than usual — for example, you telephoned friends in the middle of the night?" }, { id: "M11", text: "...you were much more interested in sex than usual?" }, { id: "M12", text: "...you did things that were unusual for you or that other people might have thought were excessive, foolish, or risky?" }, { id: "M13", text: "...spending money got you or your family into trouble?" }, ].map(i => ({ ...i, scale: YN })); const FOLLOWUP = [ { id: "M14", scale: YN, text: "If you checked YES to more than one of the above, have several of these ever happened during the same period of time?" }, { id: "M15", scale: SEVERITY, text: "How much of a problem did any of these cause you — like being unable to work; having family, money, or legal troubles; getting into arguments or fights?" }, ]; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); const yesCount = SYMPTOMS.filter(s => get(s.id) === 1).length; const concurrent = get("M14") === 1; const severity = get("M15"); const positive = yesCount >= 7 && concurrent && severity >= 2; let flag; if (positive) flag = "high"; else if (yesCount >= 7 || (yesCount >= 5 && concurrent)) flag = "moderate"; else flag = "low"; return { yesCount, concurrent, severity, positive, flag }; } function renderResult(result) { const titleMap = { low: "Unremarkable MDQ screening", moderate: "Partially elevated screening", high: "MDQ-positive · consistent with the bipolar spectrum", }; const subMap = { low: "The three MDQ criteria are not met.", moderate: "Some MDQ criteria are met — a specialist assessment is recommended.", high: "All three MDQ criteria are met — a specialist bipolar assessment is recommended.", }; const interp = ` You answered "Yes" to ${result.yesCount} of 13 symptoms, co-occurrence (question 14): ${result.concurrent ? "yes" : "no"}, severity (question 15): ${["no problem","minor problem","moderate problem","serious problem"][result.severity]}. ${result.positive ? `This means the MDQ algorithm is met (≥ 7 symptoms, co-occurring, ≥ moderate). In validation studies, the MDQ shows a sensitivity of about 73 % and a specificity of about 90 % for Bipolar I (Hirschfeld 2000, Hu et al. meta-analysis 2020). For Bipolar II / the bipolar spectrum, sensitivity is lower.` : `This means the full MDQ algorithm is not met. However, a negative screening does not rule out a bipolar disorder — particularly Bipolar II — since the MDQ captures hypomanic symptoms less reliably.`} `; const subscales = [ { label: "Symptom count (items 1–13)", raw: result.yesCount, max: 13, threshold: 7, note: `Cutoff criterion A: ≥ 7 symptoms answered "Yes". ${result.yesCount >= 7 ? "Met." : "Not met."}` }, { label: "Co-occurrence (question 14)", raw: result.concurrent ? 1 : 0, max: 1, threshold: 1, valueLabel: result.concurrent ? "Yes" : "No", note: `Criterion B: symptoms occurred during the same period of time. ${result.concurrent ? "Met." : "Not met."}` }, { label: "Functional impairment (question 15)", raw: result.severity, max: 3, threshold: 2, valueLabel: ["no problem","minor problem","moderate problem","serious problem"][result.severity], note: `Criterion C: ≥ "moderate". ${result.severity >= 2 ? "Met." : "Not met."}` }, ]; const context = ` The Mood Disorder Questionnaire (MDQ) is the most widely used self-rating instrument for bipolar spectrum screening worldwide. It asks about symptoms of mania/hypomania occurring at any point in life and applies three criteria: symptom count ≥ 7, co-occurrence, and moderate to serious impairment. The MDQ is sensitive for Bipolar I but less sensitive for Bipolar II and the bipolar spectrum — a negative screening therefore does not rule out a bipolar disorder. A confirmed diagnosis requires a clinical interview (e.g. SCID-5, MINI 7). `; const next = []; if (result.flag === "high") { next.push("Arrange an appointment with a psychiatric practice or a specialist bipolar outpatient clinic. A bipolar diagnosis is highly relevant for treatment — antidepressants without a mood stabiliser can induce switches in bipolar depression."); next.push("A detailed history of the episodes (duration, sleep patterns, level of functioning) is central to the diagnosis. Keep a record of episodes with their duration and triggers."); next.push("Evidence-based options depending on the diagnosis: lithium, valproate, quetiapine, lurasidone, lamotrigine (German S3 guideline on bipolar disorders 2024, NICE CG185)."); } else if (result.flag === "moderate") { next.push("Even though the full algorithm is not met, a specialist assessment is worthwhile if bipolar disorder is suspected — Bipolar II is frequently missed."); next.push("The Hypomania Checklist HCL-32 (Angst 2005) can be a useful addition, as it captures hypomania more sensitively than the MDQ."); } else { next.push("The MDQ is negative. If mood symptoms persist, a specialist assessment is still advisable, particularly for differential diagnosis (unipolar depression, personality, ADHD)."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: result.yesCount, unit: `/ 13 symptoms${result.positive ? " · algorithm +" : ""}`, gauge: Math.min(1, (result.yesCount/13 * 0.6) + (result.concurrent ? 0.2 : 0) + (result.severity / 3 * 0.2)), flag: result.flag, interpretationHTML: interp, subscales, contextHTML: context, nextSteps: next, }; } return { id: "mdq", meta: { title: "MDQ · Bipolar Screening", pageTitle: "MDQ — Bipolar Screening · brainScreener", eyebrow: "Bipolar spectrum", intro: `The Mood Disorder Questionnaire (MDQ) is the most widely used self-report screen for possible manic / hypomanic episodes worldwide. Reference period: your entire life so far.`, durationText: "approx. 3–4 minutes", itemsText: "13 + 2 items", sources: "Hirschfeld et al. 2000 · Hu et al. 2020 · DSM-5-TR", testPath: "/brainscreener/mdq.html", retestPath: "/brainscreener/mdq.html", resultPath: "/brainscreener/mdq-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "MDQ · Lifetime symptoms", intro: "Has there ever been a period of time when you were not your usual self and ...", items: SYMPTOMS, scale: YN, }, { id: "followup", title: "MDQ · Follow-up questions", intro: "Please answer two final questions about the overall picture.", items: FOLLOWUP, scale: YN, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/ocir-data.js ============================================================================== // OCI-R - Obsessive-Compulsive Inventory Revised // Sources: // - Foa EB, Huppert JD, Leiberg S, Langner R, Kichic R, Hajcak G, Salkovskis PM (2002). // The Obsessive-Compulsive Inventory: development and validation of a short version. // Psychol Assess 14(4): 485-96. // - Goenner S, Leonhart R, Ecker W (2008). The Obsessive-Compulsive Inventory-Revised // (OCI-R): validation of the German version. J Anxiety Disord 22(4): 734-49. // - Abramovitch A, Abramowitz JS, McKay D (2020). The OCI-R: A critical review and // recommended revisions. J Anxiety Disord 76:102307. // // 18 items, scale 0..4. Reference period: past month. // 6 subscales of 3 items each: // Washing: 5, 11, 17 Checking: 2, 8, 14 Ordering: 3, 9, 15 // Obsessing: 6, 12, 18 Hoarding: 1, 7, 13 Neutralising: 4, 10, 16 // Cutoffs: // Total >= 21 (Foa et al. 2002, classic cutoff). Sensitivity ~74%, specificity ~75%. // Alternative more recent recommendation: >= 14 (more sensitive, less specific). window.TEST_DATA = (function () { const SCALE = { cols: 5, options: [ { v: 0, label: "Not at all" }, { v: 1, label: "A little" }, { v: 2, label: "Moderately" }, { v: 3, label: "A lot" }, { v: 4, label: "Extremely" }, ], }; const ITEMS = [ { id: "O1", sub: "hoarding", text: "I have saved up so many things that they get in the way." }, { id: "O2", sub: "checking", text: "I check things more often than necessary." }, { id: "O3", sub: "ordering", text: "I get upset if objects are not arranged properly." }, { id: "O4", sub: "neutralising",text: "I feel compelled to count while I am doing things." }, { id: "O5", sub: "washing", text: "I find it difficult to touch an object when I know it has been touched by strangers or certain people." }, { id: "O6", sub: "obsessing", text: "I find it difficult to control my own thoughts." }, { id: "O7", sub: "hoarding", text: "I collect things I don't need." }, { id: "O8", sub: "checking", text: "I repeatedly check doors, windows, drawers, etc." }, { id: "O9", sub: "ordering", text: "I get upset if others change the way I have arranged things." }, { id: "O10", sub: "neutralising",text: "I feel I have to repeat certain numbers." }, { id: "O11", sub: "washing", text: "I sometimes have to wash or clean myself simply because I feel contaminated." }, { id: "O12", sub: "obsessing", text: "I am upset by unpleasant thoughts that come into my mind against my will." }, { id: "O13", sub: "hoarding", text: "I avoid throwing things away because I am afraid I might need them later." }, { id: "O14", sub: "checking", text: "I repeatedly check gas and water taps and light switches after turning them off." }, { id: "O15", sub: "ordering", text: "I need things to be arranged in a particular order." }, { id: "O16", sub: "neutralising",text: "I feel that there are good and bad numbers." }, { id: "O17", sub: "washing", text: "I wash my hands more often and longer than necessary." }, { id: "O18", sub: "obsessing", text: "I frequently get nasty thoughts and have difficulty in getting rid of them." }, ]; const SUBSCALE_LABELS = { washing: "Washing / contamination", checking: "Checking", ordering: "Ordering / symmetry", obsessing: "Obsessing", hoarding: "Hoarding", neutralising: "Mental neutralising", }; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); const total = ITEMS.reduce((s, i) => s + get(i.id), 0); const subs = {}; for (const key of Object.keys(SUBSCALE_LABELS)) { subs[key] = ITEMS.filter(i => i.sub === key).reduce((s, i) => s + get(i.id), 0); } const cutoffReached = total >= 21; const sensitiveCutoff = total >= 14; let flag; if (total >= 30) flag = "high"; else if (cutoffReached) flag = "moderate"; else if (sensitiveCutoff) flag = "moderate"; else flag = "low"; return { total, max: 72, subs, cutoffReached, sensitiveCutoff, flag }; } function renderResult(result) { const titleMap = { low: "Unremarkable OCD screening", moderate: "Indications of obsessive-compulsive symptoms", high: "Consistent with clinically relevant obsessive-compulsive symptoms", }; const subMap = { low: "The scores are below the clinically established cutoff.", moderate: "The score suggests a specialist assessment is advisable.", high: "The profile is consistent with obsessive-compulsive disorder; prompt specialist assessment is recommended.", }; const interp = ` Your OCI-R total score is ${result.total} of 72 points. ${result.cutoffReached ? `The classic cutoff of ≥ 21 (Foa et al. 2002) is reached — sensitivity approx. 74 %, specificity approx. 75 % for obsessive-compulsive disorder.` : (result.sensitiveCutoff ? `The standard cutoff of ≥ 21 is not reached, but the more sensitive cutoff of ≥ 14 (Abramovitch et al. 2020) is. A specialist assessment is worthwhile if the symptoms are distressing.` : `Neither of the established cutoffs (≥ 14 sensitive; ≥ 21 specific) is reached.`)} The six subscales below show in which direction the obsessive-compulsive symptoms are most pronounced. `; const subscaleEntries = Object.keys(SUBSCALE_LABELS).map((key) => ({ label: `Subscale · ${SUBSCALE_LABELS[key]}`, raw: result.subs[key], max: 12, threshold: 6, note: `${result.subs[key]} of 12 points.${result.subs[key] >= 6 ? " Clinically notable (≥ 6 as the subscale cutoff)." : ""}`, })); subscaleEntries.unshift({ label: "OCI-R total score", raw: result.total, max: 72, threshold: 21, note: `Classic cutoff: ≥ 21. ${result.cutoffReached ? "Reached." : "Not reached."}`, }); const context = ` The Obsessive-Compulsive Inventory-Revised (OCI-R) is a brief, internationally established self-report measure for the dimensional assessment of obsessive-compulsive symptoms. It covers six symptom dimensions and is more sensitive than the original OCI of 1998. The German validation (Goenner et al. 2008) demonstrates good psychometric properties. Reference period: past month. A definitive diagnosis requires a clinical interview (e.g. the Y-BOCS symptom checklist). `; const next = []; if (result.flag === "high") { next.push("Arrange an appointment promptly with a psychotherapy practice specialising in obsessive-compulsive disorder."); next.push("Evidence-based and effective: cognitive behavioural therapy with exposure and response prevention (ERP), supplemented by an SSRI where appropriate (grade A recommendation, German S3 guideline 2022, NICE CG31 update 2024)."); } else if (result.flag === "moderate") { next.push("A specialist medical or psychotherapeutic assessment is recommended, particularly if the obsessions or compulsions take up more than one hour per day or noticeably restrict everyday life (DSM-5-TR time criterion)."); next.push("Take note of which subscale is most pronounced for you — this helps in the initial therapeutic consultation."); } else { next.push("The scores lie in the largely unremarkable range. Stay alert if symptoms change."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: result.total, unit: `/ 72 points`, gauge: result.total / 72, flag: result.flag, interpretationHTML: interp, subscales: subscaleEntries, contextHTML: context, nextSteps: next, }; } return { id: "ocir", meta: { title: "OCI-R · OCD Screening", pageTitle: "OCI-R — OCD Screening · brainScreener", eyebrow: "Obsessive-Compulsive Disorder", intro: `The Obsessive-Compulsive Inventory-Revised (OCI-R) is an internationally recognised brief self-report test for the dimensional assessment of obsessive-compulsive symptoms — reference period: past month. 18 items across six symptom domains (washing, checking, ordering, obsessing, hoarding, neutralising).`, durationText: "approx. 4–5 minutes", itemsText: "18 items · 6 subscales", sources: "Foa et al. 2002 · Gönner, Leonhart & Ecker (dt.) 2008 · Abramovitch et al. 2020", testPath: "/brainscreener/ocir.html", retestPath: "/brainscreener/ocir.html", resultPath: "/brainscreener/ocir-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "OCI-R · Past month", intro: "How much have the following experiences distressed or bothered you during the past month?", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/pcl5-data.js ============================================================================== // PCL-5 - PTSD Checklist for DSM-5 // Sources: // - Weathers FW, Litz BT, Keane TM, Palmieri PA, Marx BP, Schnurr PP (2013). // The PTSD Checklist for DSM-5 (PCL-5). National Center for PTSD (public domain). // - Krueger-Gottschalk A, Knaevelsrud C, Roehr S, Renneberg B, Friedrich M et al. (2017). // The German version of the PCL-5: psychometric properties. BMC Psychiatry 17:379. // - DSM-5-TR (APA 2022) criteria for PTSD. // // 20 items, scale 0..4 ("Not at all"..."Extremely"). Reference period: past month. // Subscales per DSM-5 (symptom clusters): // B (Intrusion): Items 1-5 // C (Avoidance): Items 6-7 // D (Negative Cognitions/Mood): Items 8-14 // E (Arousal/Reactivity): Items 15-20 // Total cutoff: // >= 31 per Weathers et al.; the current meta-analysis Bovin et al. 2024 supports 31-33 // in civilian populations. We use 33 as the conservative cutoff. // Probable-PTSD algorithm (DSM-5): // >= 1 B item (1-5) rated >= 2 // >= 1 C item (6-7) rated >= 2 // >= 2 D items (8-14) rated >= 2 // >= 2 E items (15-20) rated >= 2 window.TEST_DATA = (function () { const SCALE = { cols: 5, options: [ { v: 0, label: "Not at all" }, { v: 1, label: "A little bit" }, { v: 2, label: "Moderately" }, { v: 3, label: "Quite a bit" }, { v: 4, label: "Extremely" }, ], }; const ITEMS = [ { id: "T1", cluster: "B", text: "Repeated, disturbing, and unwanted memories of the stressful experience?" }, { id: "T2", cluster: "B", text: "Repeated, disturbing dreams of the stressful experience?" }, { id: "T3", cluster: "B", text: "Suddenly feeling or acting as if the stressful experience were actually happening again (as if you were actually back there reliving it)?" }, { id: "T4", cluster: "B", text: "Feeling very upset when something reminded you of the stressful experience?" }, { id: "T5", cluster: "B", text: "Having strong physical reactions when something reminded you of the stressful experience (for example, heart pounding, trouble breathing, sweating)?" }, { id: "T6", cluster: "C", text: "Avoiding memories, thoughts, or feelings related to the stressful experience?" }, { id: "T7", cluster: "C", text: "Avoiding external reminders of the stressful experience (for example, people, places, conversations, activities, objects, or situations)?" }, { id: "T8", cluster: "D", text: "Trouble remembering important parts of the stressful experience?" }, { id: "T9", cluster: "D", text: "Having strong negative beliefs about yourself, other people, or the world (for example, having thoughts such as: I am bad, there is something seriously wrong with me, no one can be trusted, the world is completely dangerous)?" }, { id: "T10", cluster: "D", text: "Blaming yourself or someone else for the stressful experience or what happened after it?" }, { id: "T11", cluster: "D", text: "Having strong negative feelings such as fear, horror, anger, guilt, or shame?" }, { id: "T12", cluster: "D", text: "Loss of interest in activities that you used to enjoy?" }, { id: "T13", cluster: "D", text: "Feeling distant or cut off from other people?" }, { id: "T14", cluster: "D", text: "Trouble experiencing positive feelings (for example, being unable to feel happiness or have loving feelings for people close to you)?" }, { id: "T15", cluster: "E", text: "Irritable behavior, angry outbursts, or acting aggressively?" }, { id: "T16", cluster: "E", text: "Taking too many risks or doing things that could cause you harm?" }, { id: "T17", cluster: "E", text: "Being “superalert” or watchful or on guard?" }, { id: "T18", cluster: "E", text: "Feeling jumpy or easily startled?" }, { id: "T19", cluster: "E", text: "Having difficulty concentrating?" }, { id: "T20", cluster: "E", text: "Trouble falling or staying asleep?" }, ]; const CUTOFF = 33; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); const total = ITEMS.reduce((s, it) => s + get(it.id), 0); const sumCluster = (c) => ITEMS.filter(i => i.cluster === c).reduce((s, i) => s + get(i.id), 0); const B = sumCluster("B"), C = sumCluster("C"), D = sumCluster("D"), E = sumCluster("E"); const countAtLeast2 = (cluster) => ITEMS.filter(i => i.cluster === cluster && get(i.id) >= 2).length; const cB = countAtLeast2("B"), cC = countAtLeast2("C"), cD = countAtLeast2("D"), cE = countAtLeast2("E"); const dsmAlgo = cB >= 1 && cC >= 1 && cD >= 2 && cE >= 2; const cutoff = total >= CUTOFF; let flag; if (dsmAlgo && cutoff) flag = "high"; else if (cutoff || (cB >= 1 && cC >= 1 && (cD + cE) >= 2)) flag = "moderate"; else if (total >= 20) flag = "moderate"; else flag = "low"; return { total, max: 80, clusterScores: { B, C, D, E }, clusterMax: { B: 20, C: 8, D: 28, E: 24 }, clusterCountsAtLeast2: { B: cB, C: cC, D: cD, E: cE }, dsmAlgorithm: dsmAlgo, cutoff: CUTOFF, cutoffReached: cutoff, flag, }; } function renderResult(result) { const titleMap = { low: "Unremarkable PTSD screening", moderate: "Indications of PTSD symptoms", high: "Consistent with PTSD per DSM-5", }; const subMap = { low: "The scores reach neither the total-score cutoff nor the DSM-5 algorithm.", moderate: "Individual symptom clusters are elevated — a specialist assessment is recommended.", high: "Both the total-score cutoff and the DSM-5 symptom structure are met.", }; const cs = result.clusterScores, cm = result.clusterMax; const interp = ` Your PCL-5 total score is ${result.total} of 80 points. ${result.cutoffReached ? `The conservative cutoff of ≥ ${result.cutoff} (Bovin et al. 2016/2024, German validation Krüger-Gottschalk et al. 2017) has been reached.` : `The cutoff of ≥ ${result.cutoff} has not been reached.`} ${result.dsmAlgorithm ? ` In addition, you meet the DSM-5 symptom algorithm (≥ 1 intrusion, ≥ 1 avoidance, ≥ 2 cognition/mood and ≥ 2 arousal symptoms rated ≥ “moderately”).` : ` The DSM-5 symptom algorithm is not fully met.`} A definitive PTSD diagnosis additionally requires the explicit presence of a Criterion A trauma and a clinical interview (e.g. CAPS-5). `; const subscales = [ { label: "PCL-5 total score", raw: result.total, max: 80, threshold: result.cutoff, note: `Cutoff for clinically probable PTSD: ≥ ${result.cutoff}. ${result.cutoffReached ? "Cutoff reached." : "Cutoff not reached."}`, }, { label: "Cluster B · Intrusion (re-experiencing)", raw: cs.B, max: cm.B, threshold: 4, note: `Symptoms rated ≥ “moderately”: ${result.clusterCountsAtLeast2.B}/5. DSM-5 requires at least 1.`, }, { label: "Cluster C · Avoidance", raw: cs.C, max: cm.C, threshold: 2, note: `Symptoms rated ≥ “moderately”: ${result.clusterCountsAtLeast2.C}/2. DSM-5 requires at least 1.`, }, { label: "Cluster D · Negative cognitions / mood", raw: cs.D, max: cm.D, threshold: 6, note: `Symptoms rated ≥ “moderately”: ${result.clusterCountsAtLeast2.D}/7. DSM-5 requires at least 2.`, }, { label: "Cluster E · Arousal / reactivity", raw: cs.E, max: cm.E, threshold: 6, note: `Symptoms rated ≥ “moderately”: ${result.clusterCountsAtLeast2.E}/6. DSM-5 requires at least 2.`, }, ]; const context = ` The PTSD Checklist for DSM-5 (PCL-5) is the gold-standard self-report measure for post-traumatic stress disorder and maps all 20 DSM-5-TR symptoms 1:1. It was developed in 2013 by the US National Center for PTSD, is in the public domain and, since the Krüger-Gottschalk validation (2017), is also well established in German-speaking countries. Reference period: past month. A confirmed diagnosis requires the presence of a Criterion A trauma and a structured clinical interview (e.g. CAPS-5). `; const next = []; if (result.flag === "high") { next.push("Arrange an appointment promptly with a psychotherapy or psychiatric practice specialising in trauma-related disorders."); next.push("Evidence-based treatments for PTSD: trauma-focused CBT (e.g. CPT, PE), EMDR (grade A recommendation; German S3 guideline DeGPT 2019, NICE NG116 update 2024)."); next.push("Bring this report to your first appointment — it structures the clinical history and can be continued as a progress measure."); } else if (result.flag === "moderate") { next.push("A specialist or trauma-therapy assessment is recommended, particularly if the symptoms have persisted for more than one month or interfere with daily life."); next.push("Note the importance of the reference period: if the trauma occurred less than 4 weeks ago, an acute stress reaction is possible (ICD-11 6B40)."); } else { next.push("The scores are in the largely unremarkable range. Stay alert if new stressful experiences occur."); next.push("Even with a low PCL-5 score, distress after a trauma may be present — if daily life is affected, seeing a professional is advisable."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: result.total, unit: `/ 80 points`, gauge: result.total / 80, flag: result.flag, interpretationHTML: interp, subscales, contextHTML: context, nextSteps: next, }; } return { id: "pcl5", meta: { title: "PCL-5 · Trauma/PTSD screening", pageTitle: "PCL-5 — Trauma/PTSD screening · brainScreener", eyebrow: "Post-traumatic stress disorder", intro: `The PTSD Checklist for DSM-5 (PCL-5) is the global gold standard in PTSD self-report assessment. 20 items covering all DSM-5-TR symptoms, reference period: past month. Note: answer the questions with reference to a specific stressful experience from your past. If you have not had such an experience, this test is not indicated for you.`, durationText: "approx. 5–7 minutes", itemsText: "20 items", sources: "Weathers et al. 2013 · Krüger-Gottschalk et al. (dt.) 2017 · DSM-5-TR (APA 2022)", testPath: "/brainscreener/pcl5.html", retestPath: "/brainscreener/pcl5.html", resultPath: "/brainscreener/pcl5-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "PCL-5 · Past month", intro: "In the past month, how much were you bothered by the following problems? Answer with reference to a specific stressful experience from your past.", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/phq9-data.js ============================================================================== // PHQ-9 - Patient Health Questionnaire-9 (Depression) // Sources: // - Kroenke K, Spitzer RL, Williams JB. The PHQ-9: validity of a brief depression // severity measure. J Gen Intern Med. 2001;16(9):606-13. // - Loewe B, Spitzer RL, Zipfel S, Herzog W. PHQ-D, Manual und Testunterlagen, // Pfizer 2002 (authorised German version). // - USPSTF 2023 / 2024: Screening for depression in adults (Grade B recommendation); // PHQ-9 remains the first-choice instrument in the primary-care setting. // // Response scale 0..3 for all 9 items. // Cutoffs (manual): 0-4 minimal, 5-9 mild, 10-14 moderate, 15-19 moderately severe, // 20-27 severe. Clinically relevant major depression: >= 10. window.TEST_DATA = (function () { const SCALE = { cols: 4, options: [ { v: 0, label: "Not at all" }, { v: 1, label: "Several days" }, { v: 2, label: "More than half the days" }, { v: 3, label: "Nearly every day" }, ], }; const ITEMS = [ { id: "P1", text: "Little interest or pleasure in doing things" }, { id: "P2", text: "Feeling down, depressed, or hopeless" }, { id: "P3", text: "Trouble falling or staying asleep, or sleeping too much" }, { id: "P4", text: "Feeling tired or having little energy" }, { id: "P5", text: "Poor appetite or overeating" }, { id: "P6", text: "Feeling bad about yourself — or that you are a failure or have let yourself or your family down" }, { id: "P7", text: "Trouble concentrating on things, such as reading the newspaper or watching television" }, { id: "P8", text: "Moving or speaking so slowly that other people could have noticed? Or the opposite — being so fidgety or restless that you have been moving around a lot more than usual" }, { id: "P9", text: "Thoughts that you would be better off dead, or of hurting yourself in some way" }, ]; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); const total = ITEMS.reduce((s, it) => s + get(it.id), 0); const q9 = get("P9"); let severity, flag; if (total <= 4) { severity = "minimal"; flag = "low"; } else if (total <= 9) { severity = "mild"; flag = "low"; } else if (total <= 14) { severity = "moderate"; flag = "moderate"; } else if (total <= 19) { severity = "moderately severe"; flag = "high"; } else { severity = "severe"; flag = "high"; } // DSM-5-TR major depression algorithm (PHQ-9 as criteria check): // at least 1 core symptom (P1 or P2) >=2, plus a total of >=5 items >=2. const itemsAtLeast2 = ITEMS.filter((it) => get(it.id) >= 2); const coreSymptom = get("P1") >= 2 || get("P2") >= 2; const mddAlgorithm = coreSymptom && itemsAtLeast2.length >= 5; return { total, max: 27, severity, flag, q9, mddAlgorithm, itemsAtLeast2: itemsAtLeast2.length, cutoffReached: total >= 10, }; } function renderResult(result) { const flagMap = { low: { title: result.total <= 4 ? "Unremarkable screening" : "Mild depressive symptoms", sub: result.total <= 4 ? "No indications of clinically relevant depressive symptoms." : "Mild symptoms that warrant monitoring — currently below the clinical cutoff.", }, moderate: { title: "Moderate depressive symptoms", sub: "The total score falls within the range that suggests a specialist assessment.", }, high: { title: result.total >= 20 ? "Severe depressive symptoms" : "Moderately severe depressive symptoms", sub: "The picture is consistent with major depression requiring treatment.", }, }; const cfg = flagMap[result.flag]; const interp = ` Your PHQ-9 total score is ${result.total} of 27 points — this corresponds to ${result.severity} severity. ${result.cutoffReached ? `The clinically established cutoff of ≥ 10 has been reached; in validation studies this value shows a sensitivity of approx. 88 % and a specificity of approx. 88 % for major depression (Manea et al., meta-analysis 2012; confirmed in USPSTF 2023).` : `The clinical cutoff of ≥ 10 has not been reached. If the distress persists for weeks or worsens, a specialist assessment is nevertheless advisable.`} ${result.mddAlgorithm ? ` In addition, your response pattern meets the DSM-5-TR algorithm for major depression (at least one core symptom plus ≥ 5 symptoms rated "more than half the days").` : ""} `; const subscales = [ { label: "PHQ-9 total score", raw: result.total, max: 27, threshold: 10, note: `Cutoff for a clinically relevant depressive episode: ≥ 10. ${result.cutoffReached ? "Cutoff reached." : "Cutoff not reached."} Severity: ${result.severity}.`, }, { label: "Suicidality / self-harm experiences (item 9)", raw: result.q9, max: 3, threshold: 1, note: result.q9 === 0 ? "No such thoughts reported." : `Important: You have indicated that over the last 2 weeks you experienced thoughts that you would be better off dead or of hurting yourself (frequency: ${["—","several days","more than half the days","nearly every day"][result.q9]}). Please speak with a professional promptly — see the crisis information below.`, }, { label: `Number of symptoms rated "more than half the days"`, raw: result.itemsAtLeast2, max: 9, threshold: 5, note: `${result.itemsAtLeast2} of 9 items with a value of ≥ 2. DSM-5-TR algorithm for major depression: ≥ 5 plus at least one core symptom.`, }, ]; const context = ` The Patient Health Questionnaire-9 (PHQ-9) directly maps the nine DSM-5 symptom criteria of major depression and, with more than 5,000 validation studies, is the most thoroughly researched depression self-rating instrument worldwide. The reference period is the last 2 weeks. The instrument is suitable for screening, severity assessment and monitoring the course of treatment. It does not replace a medical diagnosis, but it is recommended as a first-line instrument internationally (USPSTF 2023, NICE NG222). `; const next = []; if (result.q9 >= 1) { next.push("Important: If you are currently experiencing thoughts of death or self-harm, please contact a professional or one of the crisis services listed below without delay. In acute danger: call your local emergency number (112 / 911 / 999) immediately."); } if (result.flag === "high") { next.push("Arrange an appointment promptly with your general practitioner or directly with a psychiatric / psychotherapeutic practice. The printed result can help structure the initial consultation."); next.push("A confirmed diagnosis requires a clinical interview and the exclusion of differential-diagnostic causes (e.g. thyroid disease, sleep apnoea, substance effects, a bipolar component)."); } else if (result.flag === "moderate") { next.push("A specialist or psychotherapeutic assessment is recommended, especially if the symptoms have persisted for more than 2 weeks or interfere with everyday life."); next.push("Consider accompanying progress monitoring — the PHQ-9 is a standardised instrument for this purpose (complete it again every 2–4 weeks)."); } else { next.push("The current values are within a largely unremarkable range. Stay attentive in case the symptoms change."); next.push("Sleep, exercise, social contact and daily structure are the most effective everyday protective factors."); } next.push("Print this report as a PDF and bring it to your next medical or therapy appointment."); return { title: cfg.title, sub: cfg.sub, value: result.total, unit: `/ 27 points · ${result.severity}`, gauge: result.total / 27, flag: result.flag, interpretationHTML: interp, subscales, contextHTML: context, nextSteps: next, }; } return { id: "phq9", meta: { title: "PHQ-9 · Depression Screening", pageTitle: "PHQ-9 — Depression Screening · brainScreener", eyebrow: "Depression in adults", intro: `This instrument is the Patient Health Questionnaire-9 (PHQ-9) — the most widely used self-report questionnaire internationally for assessing depressive symptoms. It directly maps the nine DSM-5-TR symptom criteria of major depression. Reference period: last 2 weeks.`, durationText: "approx. 3–4 minutes", itemsText: "9 items", sources: "Kroenke, Spitzer & Williams 2001 · Löwe et al. (Pfizer, dt.) 2002 · USPSTF 2023", testPath: "/brainscreener/phq9.html", retestPath: "/brainscreener/phq9.html", resultPath: "/brainscreener/phq9-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "main", title: "PHQ-9 · Last 2 weeks", intro: "Over the last 2 weeks, how often have you been bothered by any of the following problems?", items: ITEMS, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/i18n/en/whodas36-data.js ============================================================================== // WHODAS 2.0 - WHO Disability Assessment Schedule 2.0 (36-item self-administered, full version) // Sources: // - WHO (2010). Measuring Health and Disability: Manual for WHO Disability Assessment // Schedule (WHODAS 2.0). World Health Organization. (Open Access) // - Uestuen TB, Chatterji S et al. (2010). Developing the WHO Disability Assessment // Schedule 2.0. Bull WHO 88(11):815-823. // - DSM-5-TR (APA 2022) recommends WHODAS 2.0 as the standard measure of functioning. // - Pavedis M, Volz HP et al. (2014) - German adaptation of WHODAS 2.0. // // 36 items, 6 domains. Reference period: last 30 days. Scale 0..4 (0=none ... 4=extreme). // Domains: // D1 Cognition: 6 items (D1.1-D1.6) // D2 Mobility: 5 items (D2.1-D2.5) // D3 Self-care: 4 items (D3.1-D3.4) // D4 Getting along with people: 5 items (D4.1-D4.5) // D5 Life activities household: 4 items (D5.1-D5.4) // D5 Life activities work: 4 items (D5.5-D5.8, only if employed / in education) // D6 Participation: 8 items (D6.1-D6.8) // Scoring (Simple Summary Method): sum / max * 100% = disability %. window.TEST_DATA = (function () { const SCALE = { cols: 5, options: [ { v: 0, label: "None" }, { v: 1, label: "Mild" }, { v: 2, label: "Moderate" }, { v: 3, label: "Severe" }, { v: 4, label: "Extreme or cannot do" }, ] }; // Section 1: Cognition const D1 = [ { id: "W1_1", domain: "cognition", text: "Concentrating on doing something for ten minutes?" }, { id: "W1_2", domain: "cognition", text: "Remembering to do important things?" }, { id: "W1_3", domain: "cognition", text: "Analysing and finding solutions to problems in day-to-day life?" }, { id: "W1_4", domain: "cognition", text: "Learning a new task, for example, learning how to get to a new place?" }, { id: "W1_5", domain: "cognition", text: "Generally understanding what people say?" }, { id: "W1_6", domain: "cognition", text: "Starting and maintaining a conversation?" }, ]; const D2 = [ { id: "W2_1", domain: "mobility", text: "Standing for long periods such as 30 minutes?" }, { id: "W2_2", domain: "mobility", text: "Standing up from sitting down?" }, { id: "W2_3", domain: "mobility", text: "Moving around inside your home?" }, { id: "W2_4", domain: "mobility", text: "Getting out of your home?" }, { id: "W2_5", domain: "mobility", text: "Walking a long distance such as a kilometre?" }, ]; const D3 = [ { id: "W3_1", domain: "selfcare", text: "Washing your whole body?" }, { id: "W3_2", domain: "selfcare", text: "Getting dressed?" }, { id: "W3_3", domain: "selfcare", text: "Eating?" }, { id: "W3_4", domain: "selfcare", text: "Staying by yourself for a few days?" }, ]; const D4 = [ { id: "W4_1", domain: "people", text: "Dealing with people you do not know?" }, { id: "W4_2", domain: "people", text: "Maintaining a friendship?" }, { id: "W4_3", domain: "people", text: "Getting along with people who are close to you?" }, { id: "W4_4", domain: "people", text: "Making new friends?" }, { id: "W4_5", domain: "people", text: "Sexual activities?" }, ]; const D5_HOME = [ { id: "W5_1", domain: "household", text: "Taking care of your household responsibilities?" }, { id: "W5_2", domain: "household", text: "Doing most important household tasks well?" }, { id: "W5_3", domain: "household", text: "Getting all the household work done that you needed to do?" }, { id: "W5_4", domain: "household", text: "Getting your household work done as quickly as needed?" }, ]; const D5_WORK = [ { id: "W5_5", domain: "work", text: "Your day-to-day work/school?" }, { id: "W5_6", domain: "work", text: "Doing your most important work/school tasks well?" }, { id: "W5_7", domain: "work", text: "Getting all the work done that you need to do?" }, { id: "W5_8", domain: "work", text: "Getting your work done as quickly as needed?" }, ]; const D6 = [ { id: "W6_1", domain: "participation", text: "How much of a problem did you have in joining in community activities (for example, festivities, religious or other activities) in the same way as anyone else can?" }, { id: "W6_2", domain: "participation", text: "How much of a problem did you have because of barriers or hindrances in the world around you?" }, { id: "W6_3", domain: "participation", text: "How much of a problem did you have living with dignity because of the attitudes and actions of others?" }, { id: "W6_4", domain: "participation", text: "How much time did you spend on your health condition, or its consequences?" }, { id: "W6_5", domain: "participation", text: "How much have you been emotionally affected by your health condition?" }, { id: "W6_6", domain: "participation", text: "How much has your health been a drain on the financial resources of you or your family?" }, { id: "W6_7", domain: "participation", text: "How much of a problem did your family have because of your health problems?" }, { id: "W6_8", domain: "participation", text: "How much of a problem did you have in doing things by yourself for relaxation or pleasure?" }, ]; const ALL_ITEMS = [...D1, ...D2, ...D3, ...D4, ...D5_HOME, ...D5_WORK, ...D6]; const DOMAIN_LABELS = { cognition: "D1 · Cognition (understanding & communicating)", mobility: "D2 · Mobility", selfcare: "D3 · Self-care", people: "D4 · Getting along with people", household: "D5 · Life activities (household)", work: "D5 · Life activities (work / school)", participation: "D6 · Participation in society", }; function evaluate(answers) { const get = (id) => (typeof answers[id] === "number" ? answers[id] : 0); // Check whether the work items are "not applicable" - heuristically, if all = 0 AND at least 1 other value > 0 const workValues = D5_WORK.map(i => get(i.id)); const workAllZero = workValues.every(v => v === 0); const otherValues = ALL_ITEMS.filter(i => i.domain !== "work").map(i => get(i.id)); const otherHasValues = otherValues.some(v => v > 0); const workNotApplicable = workAllZero && otherHasValues; const itemsForScoring = workNotApplicable ? ALL_ITEMS.filter(i => i.domain !== "work") : ALL_ITEMS; const total = itemsForScoring.reduce((s, it) => s + get(it.id), 0); const max = itemsForScoring.length * 4; const pct = Math.round((total / max) * 100); const domains = {}; for (const key of Object.keys(DOMAIN_LABELS)) { const items = ALL_ITEMS.filter(i => i.domain === key); const sum = items.reduce((s, i) => s + get(i.id), 0); const dMax = items.length * 4; domains[key] = { sum, max: dMax, pct: dMax ? Math.round(sum / dMax * 100) : 0, skipped: key === "work" && workNotApplicable, }; } let flag, level; if (pct < 10) { level = "no to minimal functional impairment"; flag = "low"; } else if (pct < 25) { level = "mild functional impairment"; flag = "low"; } else if (pct < 50) { level = "moderate functional impairment"; flag = "moderate"; } else if (pct < 75) { level = "severe functional impairment"; flag = "high"; } else { level = "extreme functional impairment"; flag = "high"; } return { total, max, pct, level, flag, domains, workNotApplicable }; } function renderResult(result) { const titleMap = { low: result.pct < 10 ? "Unimpaired level of functioning" : "Mild functional impairment", moderate: "Moderate functional impairment", high: result.pct >= 75 ? "Extreme functional impairment" : "Severe functional impairment", }; const subMap = { low: "Scores are within the population mid-range.", moderate: "Some domains are already relevantly impaired — clarifying the causes is advisable.", high: "Marked functional limitation — specialist medical assessment and, if indicated, rehabilitation/social counselling recommended.", }; const interp = ` Your WHODAS 2.0 total score is ${result.total} / ${result.max} points (= ${result.pct} % of the maximum impairment). This corresponds to ${result.level}. ${result.workNotApplicable ? `The "work / school" items were identified as not applicable and excluded from scoring (${ALL_ITEMS.filter(i=>i.domain==="work").length} items).` : ""} For comparison: in the WHO World Health Survey (general population > 60,000 adults) the median is approx. 5–10 %, the 75th percentile approx. 15 %, and the 90th percentile approx. 30 %. Scores of 25 % or above are considered clinically notable (DSM-5-TR recommendation). `; const totalSub = { label: "WHODAS 2.0 total score", raw: result.total, max: result.max, threshold: Math.round(result.max * 0.25), valueLabel: `${result.total} / ${result.max} · ${result.pct} %`, note: `Clinical cutoff approx. 25 % of the maximum impairment. Current proportion: ${result.pct} %.`, }; const domainSubs = Object.keys(DOMAIN_LABELS).map((k) => { const v = result.domains[k]; if (v.skipped) { return { label: DOMAIN_LABELS[k] + " · not assessed", raw: 0, max: v.max, threshold: null, valueLabel: "not applicable", note: "Work/school items identified as not applicable — excluded from overall scoring.", }; } return { label: DOMAIN_LABELS[k], raw: v.sum, max: v.max, threshold: Math.round(v.max * 0.25), valueLabel: `${v.sum} / ${v.max} · ${v.pct} %`, note: `${v.pct < 25 ? "In the largely unremarkable range." : v.pct < 50 ? "Moderately impaired." : "Severely impaired."}`, }; }); const context = ` The WHODAS 2.0 is the standard instrument developed by the WHO for assessing health-related functioning and participation — ICF-compliant, transdiagnostic and cross-culturally validated. The DSM-5-TR explicitly recommends the 36-item version as the standard measure of functional impairment in adult psychiatry. It does not assess a specific illness, but rather how much health problems (mental or physical) have interfered with your everyday life over the last 30 days. The full 36-item version (unlike the 12-item short form) yields clean domain profiles. `; const next = []; if (result.flag === "high") { next.push("A medical or psychotherapeutic assessment of the causes is recommended — the WHODAS indicates marked functional limitation without identifying the cause (somatic, mental, social)."); next.push("Consider social counselling or referral to a rehabilitation or vocational reintegration service."); } else if (result.flag === "moderate") { next.push("A medical or psychotherapeutic assessment is recommended, especially if the impairment has persisted for several weeks."); next.push("Identify the most severely affected domains — they are often the starting point for targeted interventions (e.g. physiotherapy for mobility, CBT for participation or emotional issues)."); } else { next.push("Scores are in the largely unremarkable range. The WHODAS is well suited to regular progress monitoring — e.g. every 3–6 months."); } next.push("Print this report as a PDF and bring it to your next appointment."); return { title: titleMap[result.flag], sub: subMap[result.flag], value: `${result.pct} %`, unit: `functional impairment (${result.total}/${result.max} points)`, gauge: Math.min(1, result.pct / 100), flag: result.flag, interpretationHTML: interp, subscales: [totalSub, ...domainSubs], contextHTML: context, nextSteps: next, hideCrisis: true, }; } return { id: "whodas36", meta: { title: "WHODAS 2.0 · Functioning & Participation (36 items)", pageTitle: "WHODAS 2.0 (36) — Functioning & Participation · brainScreener", eyebrow: "Level of functioning · ICF · DSM-5-TR", intro: `The WHODAS 2.0 (36 items) is the transdiagnostic standard instrument developed by the WHO for assessing health-related functioning and participation — recommended by the DSM-5-TR. Full version with six domain profiles, reference period: last 30 days.`, durationText: "approx. 8–12 minutes", itemsText: "36 items · 6 domains", sources: "WHO 2010 · Üstün et al. 2010 · DSM-5-TR (APA 2022) · ICF (WHO 2024)", testPath: "/brainscreener/whodas36.html", retestPath: "/brainscreener/whodas36.html", resultPath: "/brainscreener/whodas36-result.html", }, ui: { question: "Question", answersCount: "{answered} / {total} answered", sectionLabel: "Section {i} of {n} · {title}", resetConfirm: "Really delete all previous answers and restart?", locale: "en-GB", evalLabel: "Results", noResultTitle: "No result found", noResultText: "Please take the test first to receive a report.", toTest: "Go to the test", gaugeLow: "low", gaugeHigh: "high", }, sections: [ { id: "cognition", title: "D1 · Understanding and communicating", intro: "In the last 30 days, how much difficulty did you have in:", items: D1, scale: SCALE, }, { id: "mobility", title: "D2 · Getting around", intro: "Still referring to the last 30 days.", items: D2, scale: SCALE, }, { id: "selfcare", title: "D3 · Self-care", intro: "Still referring to the last 30 days.", items: D3, scale: SCALE, }, { id: "people", title: "D4 · Getting along with people", intro: "For difficulties in relationships, think of problems arising from your health condition.", items: D4, scale: SCALE, }, { id: "household", title: "D5 · Life activities (household)", intro: "Activities you carry out at home for your family or other people.", items: D5_HOME, scale: SCALE, }, { id: "work", title: "D5 · Life activities (work / school)", intro: "If you are not currently employed or in education: answer the items with reference to your most recent occupation. If you have never been employed or this does not apply to you: please select “None” throughout — the items will then be excluded from scoring.", items: D5_WORK, scale: SCALE, }, { id: "participation", title: "D6 · Participation in society", intro: "Final questions on social and societal participation.", items: D6, scale: SCALE, }, ], evaluate, renderResult, }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/iq.js ============================================================================== // IQ-Test - Controller (Item-Navigation, Timer, Persistenz) (function () { const D = window.IQ_DATA; // UI-Strings: deutsche Defaults, übersetzte Datendateien liefern D.ui mit. const UI = Object.assign({ itemOf: (i, n) => `Aufgabe ${i} von ${n}`, answeredOf: (a, n) => `${a} / ${n} beantwortet`, qMatrix: "Welche Figur vervollständigt das Muster?", qNumeric: "Welche Zahl setzt die Reihe logisch fort?", qVerbal: "Welche Ergänzung passt am besten?", optionLabel: (letter) => `Option ${letter}`, finishConfirm: (a, n) => `Sie haben ${a} von ${n} Aufgaben beantwortet. Test trotzdem auswerten?`, resetConfirm: "Wirklich alle bisherigen Antworten löschen und neu starten?", confirmFinishOk: "Trotzdem auswerten", confirmResetOk: "Antworten löschen", confirmCancel: "Abbrechen", domainLabel: { Gf: "Matrix Reasoning · Fluide Intelligenz", Gq: "Zahlenreihe · Quantitatives Denken", Gc: "Verbale Analogie · Kristalline Intelligenz", Gv: "Visuell-räumlich · Mustererkennung", }, }, (D && D.ui) || {}); const STORAGE_KEY = "brainscreener.iq.answers.v1"; const TIME_KEY = "brainscreener.iq.startTs.v1"; const CODE_KEY = "brainscreener.iq.code.v1"; const RESULT_KEY = "brainscreener.iq.result.v1"; const intro = document.getElementById("intro"); const testArea = document.getElementById("testArea"); const progressWrap = document.getElementById("progressWrap"); const progressFill = document.getElementById("progressFill"); const progressText = document.getElementById("progressText"); const timeDisplay = document.getElementById("timeDisplay"); const itemNum = document.getElementById("itemNum"); const itemQuestion = document.getElementById("itemQuestion"); const itemStimulus = document.getElementById("itemStimulus"); const itemOptions = document.getElementById("itemOptions"); const btnPrev = document.getElementById("btnPrev"); const btnNext = document.getElementById("btnNext"); const btnSkip = document.getElementById("btnSkip"); const btnFinish = document.getElementById("btnFinish"); const finishHint = document.getElementById("finishHint"); let answers = loadAnswers(); let idx = 0; let startTs = parseInt(sessionStorage.getItem(TIME_KEY) || "0", 10); let tickerId = null; function loadAnswers() { try { return JSON.parse(sessionStorage.getItem(STORAGE_KEY) || "{}"); } catch { return {}; } } function saveAnswers() { try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(answers)); } catch {} } // Item types map to their stimulus rendering function renderItem(i) { const it = D.ITEMS[i]; itemNum.textContent = `${UI.itemOf(i + 1, D.TOTAL)} · ${UI.domainLabel[it.domain] || it.domain}`; itemStimulus.innerHTML = ""; itemOptions.innerHTML = ""; if (it.type === "matrix") { itemQuestion.textContent = UI.qMatrix; itemStimulus.innerHTML = `
      ${D.gridSVG(it.cells)}
      `; // 6 SVG options const optsHTML = it.options.map((opt, oi) => ` `).join(""); itemOptions.innerHTML = `
      ${optsHTML}
      `; } else if (it.type === "numeric") { itemQuestion.textContent = UI.qNumeric; itemStimulus.innerHTML = `
      ${it.question}
      `; itemOptions.innerHTML = mcqHTML(it); } else if (it.type === "verbal") { itemQuestion.textContent = UI.qVerbal; itemStimulus.innerHTML = `
      ${it.question}
      `; itemOptions.innerHTML = mcqHTML(it); } else if (it.type === "logical") { itemQuestion.textContent = it.question; itemStimulus.innerHTML = ""; itemOptions.innerHTML = mcqHTML(it); } // Restore selection visual const radios = itemOptions.querySelectorAll('input[type="radio"]'); radios.forEach((r) => { r.addEventListener("change", () => { answers[it.id] = parseInt(r.value, 10); saveAnswers(); updateProgress(); }); }); btnPrev.disabled = (i === 0); if (i === D.TOTAL - 1) { btnNext.hidden = true; btnFinish.hidden = false; finishHint.hidden = false; } else { btnNext.hidden = false; btnFinish.hidden = false; finishHint.hidden = false; } progressText.textContent = UI.itemOf(i + 1, D.TOTAL); updateProgress(); window.scrollTo({ top: 0, behavior: "smooth" }); } function mcqHTML(it) { return `
      ${it.options.map((opt, oi) => ` `).join("")}
      `; } function updateProgress() { const answered = Object.keys(answers).length; const pct = Math.round(((idx + 1) / D.TOTAL) * 100); progressFill.style.width = pct + "%"; } function tick() { if (!startTs) return; const sec = Math.floor((Date.now() - startTs) / 1000); const m = Math.floor(sec / 60), s = sec % 60; timeDisplay.textContent = `${m}:${String(s).padStart(2, "0")} · ${UI.answeredOf(Object.keys(answers).length, D.TOTAL)}`; } // ---------- In-Page-Bestätigungsdialog ---------- // Ersetzt window.confirm(): native Dialoge werden in manchen In-App-Browsern // (Telegram/X) oder nach "Dialoge unterdrücken" stillschweigend geblockt. function ensureModal() { let m = document.getElementById("iqConfirmModal"); if (m) return m; m = document.createElement("div"); m.id = "iqConfirmModal"; m.setAttribute("role", "dialog"); m.setAttribute("aria-modal", "true"); m.style.cssText = "position:fixed;inset:0;z-index:2000;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(0,0,0,0.45);"; m.innerHTML = `

      `; document.body.appendChild(m); return m; } function showConfirm(message, okLabel, onOk) { const m = ensureModal(); m.querySelector("#iqConfirmMsg").textContent = message; const ok = m.querySelector("#iqConfirmOk"); const cancel = m.querySelector("#iqConfirmCancel"); ok.textContent = okLabel; cancel.textContent = UI.confirmCancel; m.style.display = "flex"; const close = () => { m.style.display = "none"; ok.onclick = cancel.onclick = m.onclick = null; }; cancel.onclick = close; m.onclick = (e) => { if (e.target === m) close(); }; ok.onclick = () => { close(); onOk(); }; ok.focus(); } // ---------- Navigation ---------- btnNext.addEventListener("click", () => { if (idx < D.TOTAL - 1) { idx++; renderItem(idx); } }); btnPrev.addEventListener("click", () => { if (idx > 0) { idx--; renderItem(idx); } }); btnSkip.addEventListener("click", () => { // explicit skip: ensure no answer for this item const it = D.ITEMS[idx]; delete answers[it.id]; saveAnswers(); if (idx < D.TOTAL - 1) { idx++; renderItem(idx); } }); btnFinish.addEventListener("click", () => { const answered = Object.keys(answers).length; if (answered < D.TOTAL) { showConfirm(UI.finishConfirm(answered, D.TOTAL), UI.confirmFinishOk, finishTest); return; } finishTest(); }); function finishTest() { const result = D.evaluate(answers); const probandCode = (sessionStorage.getItem(CODE_KEY) || "").trim(); const payload = { result, answers, probandCode, ts: new Date().toISOString(), durationSec: startTs ? Math.floor((Date.now() - startTs) / 1000) : null, }; try { sessionStorage.setItem(RESULT_KEY, JSON.stringify(payload)); } catch {} testInProgress = false; // Sprachversion beibehalten: /brainscreener/iq -> /brainscreener/iq-result.html usw. location.href = location.pathname.replace(/[^/]*$/, "") + "iq-result.html"; } // ---------- beforeunload Warnung ---------- let testInProgress = false; window.addEventListener("beforeunload", (e) => { const answered = Object.keys(answers).length; if (testInProgress && answered > 0 && answered < D.TOTAL) { e.preventDefault(); e.returnValue = ""; return ""; } }); // ---------- Reset ---------- const btnResetEl = document.getElementById("btnReset"); if (Object.keys(answers).length > 0) { btnResetEl.hidden = false; btnResetEl.addEventListener("click", () => { showConfirm(UI.resetConfirm, UI.confirmResetOk, () => { sessionStorage.removeItem(STORAGE_KEY); sessionStorage.removeItem(TIME_KEY); sessionStorage.removeItem(CODE_KEY); sessionStorage.removeItem(RESULT_KEY); answers = {}; startTs = 0; testInProgress = false; location.reload(); }); }); } // ---------- Start ---------- const probandInput = document.getElementById("probandCode"); const savedCode = sessionStorage.getItem(CODE_KEY) || ""; if (probandInput && savedCode) probandInput.value = savedCode; if (probandInput) { probandInput.addEventListener("input", () => { try { sessionStorage.setItem(CODE_KEY, probandInput.value); } catch {} }); } document.getElementById("btnStart").addEventListener("click", () => { if (probandInput) { try { sessionStorage.setItem(CODE_KEY, probandInput.value || ""); } catch {} } intro.hidden = true; testArea.hidden = false; progressWrap.hidden = false; testInProgress = true; // Testmodus: kompaktes Layout, damit eine Aufgabe ohne Scrollen auf den Schirm passt document.documentElement.classList.add("iq-testing"); if (!startTs) { startTs = Date.now(); sessionStorage.setItem(TIME_KEY, String(startTs)); } idx = 0; renderItem(idx); tickerId = setInterval(tick, 1000); tick(); }); // Resume if state exists if (Object.keys(answers).length > 0 && startTs) { intro.hidden = true; testArea.hidden = false; progressWrap.hidden = false; testInProgress = true; // Testmodus: kompaktes Layout, damit eine Aufgabe ohne Scrollen auf den Schirm passt document.documentElement.classList.add("iq-testing"); // find first unanswered, else last idx = 0; for (let i = 0; i < D.TOTAL; i++) { if (answers[D.ITEMS[i].id] === undefined) { idx = i; break; } if (i === D.TOTAL - 1) idx = i; } renderItem(idx); tickerId = setInterval(tick, 1000); tick(); } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/print-fallback.js ============================================================================== // Print-Fallback fuer In-App-Browser (X/Telegram/Instagram/FB …). // window.print() ist in diesen WebViews ein stiller No-Op — gleiche Kategorie wie // die geblockten nativen confirm()-Dialoge (siehe iq.js In-Page-Modal). // Strategie: // - loadPayload(key): sessionStorage zuerst, dann URL-Hash-Fallback (#r=…), damit // das Resultat den Sprung in einen echten Browser ueberlebt. Der Hash wird nie // an den Server gesendet (URL-Fragment) — alles bleibt clientseitig. // - attachPrint(btn, key): normale Browser behalten window.print(); erkannte // In-App-Browser bekommen ein In-Page-Modal mit kopierbarem Link. // Aus dem Hash werden nur die rohen answers uebernommen (result wird verworfen und // von der Seite via evaluate() neu berechnet) — kein HTML aus der URL im DOM. (function () { // Telegrams In-App-Browser tarnt sich als normales Chrome (kein "Telegram", // kein "; wv)" im UA — via debug-ua.html verifiziert 15.7.). Er injiziert aber // ein Proxy-Objekt — das ist der zuverlässige Marker. function isTelegram() { return typeof window.TelegramWebviewProxy !== "undefined" || typeof window.TelegramWebviewProxyProto !== "undefined" || typeof window.TelegramWebview !== "undefined" || /Telegram/i.test(navigator.userAgent || ""); } function isInApp() { if (isTelegram()) return true; var ua = navigator.userAgent || ""; if (/TwitterAndroid|Twitter for iPhone|FBAN|FBAV|Instagram|Line\//i.test(ua)) return true; if (/Android/.test(ua) && /; wv\)/.test(ua)) return true; // Android WebView if (/iPhone|iPad|iPod/.test(ua) && !/Safari\//i.test(ua)) return true; // iOS In-App-WebView try { // Chromium UA-Client-Hints: WebView nennt sich in der Brands-Liste var brands = (navigator.userAgentData && navigator.userAgentData.brands) || []; for (var i = 0; i < brands.length; i++) if (/WebView/i.test(brands[i].brand)) return true; } catch {} return false; } // position:sticky ist in Telegrams WebView kaputt, position:fixed funktioniert // (debug-ua.html: 🟩 klebt nicht, 🟦 klebt). Emulation nur fuer Telegram — // X/Safari/Chrome behalten ihr funktionierendes sticky. function fixSticky() { var header = document.querySelector(".site-header"); if (header) { var padBody = function () { document.body.style.paddingTop = header.offsetHeight + "px"; }; header.style.position = "fixed"; header.style.top = "0"; header.style.left = "0"; header.style.right = "0"; // TG-WebView kann kein backdrop-filter: der 88%-transparente Glas-Header // laesst dort scharfen Text durchscheinen → opak machen (nur hier). try { if (!(window.CSS && CSS.supports && (CSS.supports("backdrop-filter", "blur(1px)") || CSS.supports("-webkit-backdrop-filter", "blur(1px)")))) { header.style.background = "rgb(5, 5, 16)"; } } catch { header.style.background = "rgb(5, 5, 16)"; } padBody(); window.addEventListener("resize", padBody); } // .test-progress klebt normal via sticky unter dem Header — emulieren mit // Scroll-Toggle + Spacer (verhindert Layout-Sprung beim Umschalten). var prog = document.querySelector(".test-progress"); if (prog) { var spacer = document.createElement("div"); spacer.style.display = "none"; prog.parentNode.insertBefore(spacer, prog); var headerH = function () { return header ? header.offsetHeight : 0; }; var onScroll = function () { var anchor = spacer.style.display === "none" ? prog : spacer; var natTop = anchor.getBoundingClientRect().top + window.scrollY; if (window.scrollY + headerH() >= natTop) { if (prog.style.position !== "fixed") { spacer.style.height = prog.offsetHeight + "px"; spacer.style.display = "block"; prog.style.position = "fixed"; prog.style.top = headerH() + "px"; prog.style.left = "0"; prog.style.right = "0"; } } else if (prog.style.position === "fixed") { prog.style.position = ""; prog.style.top = ""; prog.style.left = ""; prog.style.right = ""; spacer.style.display = "none"; } }; window.addEventListener("scroll", onScroll, { passive: true }); onScroll(); } } function ready(fn) { if (document.readyState !== "loading") fn(); else document.addEventListener("DOMContentLoaded", fn); } if (isTelegram()) ready(fixSticky); function encodePayload(payload) { try { var json = JSON.stringify(payload); var b64 = btoa(unescape(encodeURIComponent(json))); return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); } catch { return null; } } function decodeHash() { var m = (location.hash || "").match(/[#&]r=([A-Za-z0-9_-]+)/); if (!m) return null; try { var b64 = m[1].replace(/-/g, "+").replace(/_/g, "/"); while (b64.length % 4) b64 += "="; var p = JSON.parse(decodeURIComponent(escape(atob(b64)))); if (!p || typeof p !== "object" || !p.answers || typeof p.answers !== "object") return null; delete p.result; // nie vorgerechnete Ergebnisse aus der URL uebernehmen return p; } catch { return null; } } function loadPayload(key) { var p = null; try { p = JSON.parse(sessionStorage.getItem(key) || "null"); } catch {} if (p) return p; p = decodeHash(); if (p) { try { sessionStorage.setItem(key, JSON.stringify(p)); } catch {} } return p; } function shareURL(key) { var p = null; try { p = JSON.parse(sessionStorage.getItem(key) || "null"); } catch {} var enc = p ? encodePayload(p) : null; return enc ? location.origin + location.pathname + "#r=" + enc : location.href; } function attachPrint(btn, key) { if (!btn) return; if (!isInApp()) { btn.addEventListener("click", function () { window.print(); }); return; } // Hash sofort setzen: das native "Open in browser"-Menue von X/TG uebergibt // die AKTUELLE URL — nur mit gesetztem Hash kommt das Resultat mit. var url = shareURL(key); try { history.replaceState(null, "", url); } catch {} btn.addEventListener("click", function () { showModal(url); }); } function ensureModal() { var m = document.getElementById("bsPrintModal"); if (m) return m; m = document.createElement("div"); m.id = "bsPrintModal"; m.setAttribute("role", "dialog"); m.setAttribute("aria-modal", "true"); m.style.cssText = "position:fixed;inset:0;z-index:2000;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(0,0,0,0.45);"; m.innerHTML = '' + '
      ' + '

      PDF printing is not available in this in-app browser.

      ' + '

      Open this page in your regular browser (Safari or Chrome) — your result travels along in the link automatically. Use the ⋮ / share menu → “Open in browser”, or copy the link below.

      ' + '
      ' + '' + '' + '
      ' + '
      ' + '' + '' + '
      ' + '
      '; document.body.appendChild(m); return m; } function showModal(url) { var m = ensureModal(); var input = m.querySelector("#bsPrintUrl"); var copy = m.querySelector("#bsPrintCopy"); var tryBtn = m.querySelector("#bsPrintTry"); var closeBtn = m.querySelector("#bsPrintClose"); input.value = url; m.style.display = "flex"; var close = function () { m.style.display = "none"; }; closeBtn.onclick = close; m.onclick = function (e) { if (e.target === m) close(); }; tryBtn.onclick = function () { close(); window.print(); }; copy.onclick = function () { var done = function () { copy.textContent = "Copied!"; setTimeout(function () { copy.textContent = "Copy link"; }, 2000); }; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(url).then(done, function () { fallbackCopy(); done(); }); } else { fallbackCopy(); done(); } function fallbackCopy() { input.focus(); input.select(); input.setSelectionRange(0, url.length); try { document.execCommand("copy"); } catch {} } }; } window.BS_PRINT = { loadPayload: loadPayload, attachPrint: attachPrint }; })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/result-engine.js ============================================================================== // Generische Result-Engine fuer alle brainscreener-Tests (ausser ADHS/IQ-Legacy). // Erwartet: // - window.TEST_DATA mit { id, meta:{title, sources, testPath, retestPath?}, renderResult(result,payload) } // - sessionStorage[`brainscreener..result.v1`] mit { result, answers, probandCode, ts, testId } // Pflicht-DOM (siehe template result.html): // #dateStr, #codeRow, #codeStr, #overallTitle, #overallSubtitle, #overallValue, #overallUnit, // #interpretationText, #gaugeWrap, #subscaleList, #contextText, #nextSteps, #btnPrint, // #verfahrensRef (optional), #resultTitle, #resultEyebrow (function () { const D = window.TEST_DATA; if (!D) { console.error("[result-engine] TEST_DATA fehlt"); return; } // UI-Strings: deutsche Defaults, übersetzte Datendateien liefern D.ui mit. const UI = Object.assign({ locale: document.documentElement.lang || "de-CH", evalLabel: "Auswertung", noResultTitle: "Kein Ergebnis gefunden", noResultText: "Bitte starten Sie den Test, um eine Auswertung zu erhalten.", toTest: "Zum Test", gaugeLow: "niedrig", gaugeHigh: "hoch", }, D.ui || {}); const RESULT_KEY = `brainscreener.${D.id}.result.v1`; let payload = window.BS_PRINT ? BS_PRINT.loadPayload(RESULT_KEY) : null; if (!payload) { try { payload = JSON.parse(sessionStorage.getItem(RESULT_KEY) || "null"); } catch {} } const root = document.querySelector(".result-shell .container-narrow"); if (!root) { console.error("[result-engine] .result-shell .container-narrow fehlt"); return; } if (!payload) { root.innerHTML = `

      ${UI.noResultTitle}

      ${UI.noResultText}

      ${UI.toTest}

      `; return; } const { ts, probandCode } = payload; // Ergebnis aus den (sprachneutralen) Antworten in der Sprache DIESER Seite neu // berechnen — so kann ein Test z. B. auf Französisch ausgefüllt und auf Deutsch // gedruckt werden. Fallback: gespeichertes Ergebnis (ältere Sessions). const result = (payload.answers && typeof D.evaluate === "function") ? D.evaluate(payload.answers) : payload.result; const r = D.renderResult(result, payload); // --- Header / Datum / Code --- const date = ts ? new Date(ts) : new Date(); const dateStr = date.toLocaleDateString(UI.locale, { day: "2-digit", month: "long", year: "numeric" }) + " · " + date.toLocaleTimeString(UI.locale, { hour: "2-digit", minute: "2-digit" }); setText("dateStr", dateStr); const code = (probandCode || "").trim(); if (code) { const row = document.getElementById("codeRow"); if (row) row.hidden = false; setText("codeStr", code); } // --- Title / Eyebrow --- if (D.meta.pageTitle) document.title = D.meta.pageTitle; setText("resultTitle", D.meta.title); setText("resultEyebrow", UI.evalLabel); setText("verfahrensRef", D.meta.sources); // --- Overall --- setText("overallTitle", r.title); setText("overallSubtitle", r.sub); setText("overallValue", r.value); // mehrteilige Werte (z. B. fuenf T-Werte) brauchen eine kleinere Schrift, // sonst verdraengen sie die Grafik daneben aus dem Grid const elValue = document.getElementById("overallValue"); if (elValue) elValue.classList.toggle("is-long", String(r.value ?? "").trim().length > 6); setText("overallUnit", r.unit); setHTML("interpretationText", r.interpretationHTML); // --- Gauge (oder benutzerdefiniertes SVG) --- const gaugeWrap = document.getElementById("gaugeWrap"); if (gaugeWrap) { if (r.customGaugeHTML) { gaugeWrap.innerHTML = r.customGaugeHTML; gaugeWrap.classList.add("gauge-custom"); } else if (r.gauge != null) { gaugeWrap.innerHTML = gaugeSVG(r.gauge, r.flag); } else { gaugeWrap.innerHTML = ""; gaugeWrap.hidden = true; } } // Krisenbox optional ausblenden if (r.hideCrisis) { document.querySelectorAll(".crisis-box").forEach((el) => el.hidden = true); } // --- Subskalen --- const subList = document.getElementById("subscaleList"); if (subList && r.subscales) { subList.innerHTML = r.subscales.map((s) => { const pct = Math.min(100, Math.max(0, Math.round((s.raw / s.max) * 100))); const tPct = s.threshold != null ? Math.min(100, Math.round((s.threshold / s.max) * 100)) : null; return `
      ${s.label} ${s.valueLabel || (s.raw + " / " + s.max)}
      ${tPct != null ? `` : ""}
      ${s.note}
      `; }).join(""); } setHTML("contextText", r.contextHTML); // --- Next steps --- const ns = document.getElementById("nextSteps"); if (ns) ns.innerHTML = (r.nextSteps || []).map((s) => `
    • ${s}
    • `).join(""); // --- Buttons --- const btnPrint = document.getElementById("btnPrint"); if (btnPrint) { if (window.BS_PRINT) BS_PRINT.attachPrint(btnPrint, RESULT_KEY); else btnPrint.addEventListener("click", () => window.print()); } const btnRetry = document.getElementById("btnRetry"); if (btnRetry && D.meta.retestPath) btnRetry.setAttribute("href", D.meta.retestPath); // ---------- helpers ---------- function setText(id, v) { const el = document.getElementById(id); if (el && v != null) el.textContent = String(v); } function setHTML(id, v) { const el = document.getElementById(id); if (el && v != null) el.innerHTML = v; } function gaugeSVG(value, flag) { const v = Math.max(0, Math.min(1, value)); // Hoehe aus dem Bogen ableiten: 10 px Luft oben fuer die runde Strichkappe, // 36 px unten fuer die Skalenbeschriftung (sonst faellt sie aus der viewBox). const w = 360, r = 140, cx = w / 2, cy = r + 10, h = cy + 36; // Winkel laeuft von 180° (links, v=0) auf 0° (rechts, v=1). // In SVG zeigt +y nach unten, der Bogen liegt oben — daher cy MINUS sin. const ang = Math.PI * (1 - v); const px = cx + r * Math.cos(ang); const py = cy - r * Math.sin(ang); const color = flag === "high" ? "var(--danger)" : flag === "moderate" ? "var(--gold)" : flag === "low" ? "var(--sage)" : "var(--sage)"; return ` `; } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/test-engine.js ============================================================================== // Generische Test-Engine fuer brainscreener. // Erwartet window.TEST_DATA mit Struktur: // { // id: "phq9", // meta: { title, eyebrow, intro, durationText, itemsText, sources, resultPath }, // sections: [ { id, title, intro?, items:[{id,text,scale?,reverse?}], scale: defaultScale } ], // evaluate(answers) -> Result-Objekt // } // Pflicht-DOM-Elemente (siehe template test.html): // #intro, #adhsForm (form), #progressWrap, #progressFill, #progressText, #progressCount, // #actionsRow, #btnNext, #btnBack, #btnSubmit, #missingNote, #btnStart, #btnReset, #probandCode (function () { const D = window.TEST_DATA; if (!D) { console.error("[test-engine] window.TEST_DATA fehlt"); return; } // UI-Strings: deutsche Defaults, übersetzte Datendateien liefern D.ui mit. const UI = Object.assign({ question: "Frage", answersCount: "{answered} / {total} Antworten", sectionLabel: "Abschnitt {i} von {n} · {title}", resetConfirm: "Wirklich alle bisherigen Antworten löschen und neu starten?", }, D.ui || {}); const fmt = (tpl, vars) => tpl.replace(/\{(\w+)\}/g, (_, k) => (vars[k] != null ? vars[k] : "")); const STORAGE_KEY = `brainscreener.${D.id}.answers.v1`; const CODE_KEY = `brainscreener.${D.id}.code.v1`; const RESULT_KEY = `brainscreener.${D.id}.result.v1`; // Fuer Result-Engine merken, welche Test-ID das aktuelle Result hat. // (result-engine liest dann sessionStorage[`brainscreener..result.v1`].) try { sessionStorage.setItem("brainscreener.lastTest", D.id); } catch {} const $ = (id) => document.getElementById(id); const intro = $("intro"); const form = $("adhsForm"); const progressWrap = $("progressWrap"); const progressFill = $("progressFill"); const progressText = $("progressText"); const progressCount= $("progressCount"); const actionsRow = $("actionsRow"); const btnNext = $("btnNext"); const btnBack = $("btnBack"); const btnSubmit = $("btnSubmit"); const missingNote = $("missingNote"); const btnStart = $("btnStart"); const btnReset = $("btnReset"); const probandInput = $("probandCode"); // Meta in das Intro injizieren const elTitle = $("testTitle"); const elEyebrow = $("testEyebrow"); const elIntro = $("testIntro"); const elDuration = $("metaDuration"); const elItems = $("metaItems"); const elSources = $("metaSources"); if (elTitle) elTitle.textContent = D.meta.title; if (elEyebrow) elEyebrow.textContent = D.meta.eyebrow; if (elIntro) elIntro.innerHTML = D.meta.intro; if (elDuration) elDuration.textContent = D.meta.durationText; if (elItems) elItems.textContent = D.meta.itemsText; if (elSources) elSources.textContent = D.meta.sources; // Page-Title im Browser-Tab if (D.meta.pageTitle) document.title = D.meta.pageTitle; // Gesamt-Itemzahl const TOTAL_ITEMS = D.sections.reduce((s, sec) => s + sec.items.length, 0); // ---------- Storage ---------- let answers = loadAnswers(); function loadAnswers() { try { return JSON.parse(sessionStorage.getItem(STORAGE_KEY) || "{}"); } catch { return {}; } } function saveAnswers() { try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(answers)); } catch {} } // ---------- Rendering ---------- let currentIdx = 0; // aktiver Section-Index function buildLikert(itemId, scale) { const cols = scale.cols || scale.options.length; const opts = scale.options.map((opt) => ` `).join(""); return `
      ${opts}
      `; } function itemHTML(item, idx, defaultScale) { const scale = item.scale || defaultScale; return `
      ${UI.question} ${idx}
      ${item.text}
      ${buildLikert(item.id, scale)}
      `; } function ensureSectionContainers() { // Wir bauen pro Section

      ..

      ..

      form.innerHTML = ""; D.sections.forEach((sec, i) => { const banner = document.createElement("div"); banner.className = "section-banner"; banner.dataset.section = sec.id; banner.innerHTML = `

      ${sec.title}

      ${sec.intro ? `

      ${sec.intro}

      ` : ""}`; banner.hidden = (i !== 0); const items = document.createElement("div"); items.dataset.itemsFor = sec.id; items.hidden = (i !== 0); form.appendChild(banner); form.appendChild(items); }); // Action-Bar wieder anhaengen (war vor renderAll() im Markup im form, wird durch innerHTML entfernt) if (actionsRow && actionsRow.parentElement !== form) { form.appendChild(actionsRow); } if (missingNote && missingNote.parentElement !== form) { form.appendChild(missingNote); } } function renderAllItems() { D.sections.forEach((sec) => { const container = form.querySelector(`[data-items-for="${sec.id}"]`); container.innerHTML = sec.items.map((it, i) => itemHTML(it, i + 1, sec.scale)).join(""); }); form.addEventListener("change", onAnyChange); } function onAnyChange(e) { const input = e.target; if (input && input.type === "radio") { const id = input.name; const val = parseInt(input.value, 10); answers[id] = val; saveAnswers(); const itemEl = input.closest(".item"); if (itemEl) itemEl.classList.add("is-answered"); updateProgress(); if (missingNote) missingNote.hidden = true; } } function updateProgress() { const answered = Object.keys(answers).length; const pct = Math.round((answered / TOTAL_ITEMS) * 100); if (progressFill) progressFill.style.width = pct + "%"; if (progressCount) progressCount.textContent = fmt(UI.answersCount, { answered, total: TOTAL_ITEMS }); if (progressText) { const sec = D.sections[currentIdx]; const label = D.sections.length > 1 ? fmt(UI.sectionLabel, { i: currentIdx + 1, n: D.sections.length, title: sec.title }) : sec.title; progressText.textContent = label; } } // ---------- Navigation ---------- function showSection(idx) { currentIdx = idx; D.sections.forEach((sec, i) => { const banner = form.querySelector(`.section-banner[data-section="${sec.id}"]`); const items = form.querySelector(`[data-items-for="${sec.id}"]`); if (banner) banner.hidden = (i !== idx); if (items) items.hidden = (i !== idx); }); if (btnBack) btnBack.hidden = (idx === 0); if (btnNext) btnNext.hidden = (idx === D.sections.length - 1); if (btnSubmit) btnSubmit.hidden = (idx !== D.sections.length - 1); updateProgress(); window.scrollTo({ top: 0, behavior: "smooth" }); } function sectionItemIds(idx) { return D.sections[idx].items.map((i) => i.id); } function isSectionComplete(idx) { return sectionItemIds(idx).every((id) => typeof answers[id] === "number"); } function focusFirstUnanswered(idx) { const ids = sectionItemIds(idx); for (const id of ids) { if (typeof answers[id] !== "number") { const el = form.querySelector(`.item[data-id="${id}"]`); if (el) { el.scrollIntoView({ behavior: "smooth", block: "center" }); el.style.outline = "2px solid var(--gold)"; setTimeout(() => { el.style.outline = ""; }, 1400); } break; } } } if (btnNext) btnNext.addEventListener("click", () => { if (!isSectionComplete(currentIdx)) { if (missingNote) missingNote.hidden = false; focusFirstUnanswered(currentIdx); return; } if (currentIdx < D.sections.length - 1) showSection(currentIdx + 1); }); if (btnBack) btnBack.addEventListener("click", () => { if (currentIdx > 0) showSection(currentIdx - 1); }); if (btnSubmit) btnSubmit.addEventListener("click", () => { if (!isSectionComplete(currentIdx)) { if (missingNote) missingNote.hidden = false; focusFirstUnanswered(currentIdx); return; } const result = D.evaluate(answers); const probandCode = (sessionStorage.getItem(CODE_KEY) || "").trim(); const payload = { result, answers, probandCode, ts: new Date().toISOString(), testId: D.id }; try { sessionStorage.setItem(RESULT_KEY, JSON.stringify(payload)); } catch {} testInProgress = false; location.href = D.meta.resultPath; }); // ---------- beforeunload ---------- let testInProgress = false; window.addEventListener("beforeunload", (e) => { if (testInProgress && Object.keys(answers).length > 0 && Object.keys(answers).length < TOTAL_ITEMS) { e.preventDefault(); e.returnValue = ""; return ""; } }); // ---------- Reset ---------- // In-Page-Dialog statt window.confirm(): native Dialoge werden in manchen // In-App-Browsern (Telegram/X) stillschweigend geblockt. function showConfirm(message, okLabel, onOk) { let m = document.getElementById("bsConfirmModal"); if (!m) { m = document.createElement("div"); m.id = "bsConfirmModal"; m.setAttribute("role", "dialog"); m.setAttribute("aria-modal", "true"); m.style.cssText = "position:fixed;inset:0;z-index:2000;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(0,0,0,0.45);"; m.innerHTML = `

      `; document.body.appendChild(m); } m.querySelector("#bsConfirmMsg").textContent = message; const ok = m.querySelector("#bsConfirmOk"); const cancel = m.querySelector("#bsConfirmCancel"); ok.textContent = okLabel; cancel.textContent = UI.confirmCancel || "Cancel"; m.style.display = "flex"; const close = () => { m.style.display = "none"; ok.onclick = cancel.onclick = m.onclick = null; }; cancel.onclick = close; m.onclick = (e) => { if (e.target === m) close(); }; ok.onclick = () => { close(); onOk(); }; ok.focus(); } if (btnReset) { if (Object.keys(answers).length > 0) { btnReset.hidden = false; } btnReset.addEventListener("click", () => { showConfirm(UI.resetConfirm, UI.confirmResetOk || "Delete answers", () => { sessionStorage.removeItem(STORAGE_KEY); sessionStorage.removeItem(CODE_KEY); sessionStorage.removeItem(RESULT_KEY); answers = {}; location.reload(); }); }); } // ---------- Code-Feld ---------- if (probandInput) { const saved = sessionStorage.getItem(CODE_KEY) || ""; if (saved) probandInput.value = saved; probandInput.addEventListener("input", () => { try { sessionStorage.setItem(CODE_KEY, probandInput.value); } catch {} }); } // ---------- Start ---------- function startTest() { if (probandInput) { try { sessionStorage.setItem(CODE_KEY, probandInput.value || ""); } catch {} } if (intro) intro.hidden = true; form.hidden = false; if (actionsRow) actionsRow.hidden = false; if (progressWrap) progressWrap.hidden = false; testInProgress = true; ensureSectionContainers(); renderAllItems(); showSection(0); } if (btnStart) btnStart.addEventListener("click", startTest); // Falls bereits Antworten vorhanden -> direkt fortsetzen if (Object.keys(answers).length > 0) { if (intro) intro.hidden = true; form.hidden = false; if (actionsRow) actionsRow.hidden = false; if (progressWrap) progressWrap.hidden = false; testInProgress = true; ensureSectionContainers(); renderAllItems(); let resumeIdx = 0; for (let i = 0; i < D.sections.length; i++) { if (!isSectionComplete(i)) { resumeIdx = i; break; } resumeIdx = i; } showSection(resumeIdx); } })(); ============================================================================== === FILE: dashboard/brainscreener/assets/js/year.js ============================================================================== // Haelt das Copyright-Jahr im Footer aktuell. // Als externe Datei, weil die CSP (script-src 'self') Inline-Skripte blockiert. (function () { var el = document.getElementById("year"); if (el) el.textContent = new Date().getFullYear(); })(); ============================================================================== === FILE: dashboard/brainscreener/audit-result.html ============================================================================== Your results — AUDIT · brainScreener
      Results

      AUDIT

      Date:
      Anonymous report · generated client-side

      Results

      Detailed profile

      What does this mean?

      Recommended next steps

        In an acute crisis

        If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

        • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
        • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
        • findahelpline.com – free, verified crisis helplines in 130+ countries
        • befrienders.org – worldwide emotional support network (Samaritans)
        Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

        Instrument used:
        ============================================================================== === FILE: dashboard/brainscreener/audit.html ============================================================================== AUDIT — Alcohol Screening · brainScreener

        • Duration
        • Items
        • Source

        Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

        Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

        Back to home page
        ============================================================================== === FILE: dashboard/brainscreener/bfi2-result.html ============================================================================== Your results — BFI-2 · brainScreener
        Results

        BFI-2

        Date:
        Anonymous report · generated client-side

        Results

        Detailed profile

        What does this mean?

        Recommended next steps

          In an acute crisis

          If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

          • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
          • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
          • findahelpline.com – free, verified crisis helplines in 130+ countries
          • befrienders.org – worldwide emotional support network (Samaritans)
          Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

          Instrument used:
          ============================================================================== === FILE: dashboard/brainscreener/bfi2.html ============================================================================== BFI-2 — Personality · brainScreener

          • Duration
          • Items
          • Source

          Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

          Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

          Back to home page
          ============================================================================== === FILE: dashboard/brainscreener/character-result.html ============================================================================== Your character profile — Dark Tetrad · brainScreener
          Results · Dark Tetrad

          Your character profile

          Date:
          Anonymous results · generated client-side

          Your personal mix

          Everyone carries a bit of all four traits. This is how they are distributed in you:

          What the individual traits mean

          With strengths, typical behaviours and concrete tips — starting with your strongest trait.

          Plain talk instead of sugar-coating. We deliberately name the four character traits directly — without euphemism. The labels are blunt and to the point, but they are not a judgement of you as a person.

          Important note · no warranty. This character profile is a non-judgemental self-reflection tool. It describes normal, everyday expressions of personality traits on a continuum — it is not a clinical diagnosis and, in particular, not a determination of a narcissistic, antisocial or any other personality disorder. Terms such as "psychopath" or "sadism" refer here exclusively to subclinical character tendencies, not to the clinical disorders. Results depend on your form on the day and on self-assessment.

          Basis:
          ============================================================================== === FILE: dashboard/brainscreener/character.html ============================================================================== Character profile — Dark Tetrad · brainScreener

          • Duration
          • Items
          • Source

          Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

          Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

          Back to home page
          ============================================================================== === FILE: dashboard/brainscreener/debug-ua.html ============================================================================== WebView Debug
          User-Agent:
          In-App-Erkennung (print-fallback-Logik):
          Viewport / Fenster:
          Print-Test:
          scroll mich … (Füller 1)
          scroll mich … (Füller 2)
          Ende — 🟩 oben sichtbar? 🟦 unten sichtbar?
          🟦 FIXED-Balken — klebt der unten?
          ============================================================================== === FILE: dashboard/brainscreener/eat26-result.html ============================================================================== Your results — EAT-26 · brainScreener
          Results

          EAT-26

          Date:
          Anonymous report · generated client-side

          Results

          Detailed profile

          What does this mean?

          Recommended next steps

            In an acute crisis

            If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

            • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
            • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
            • findahelpline.com – free, verified crisis helplines in 130+ countries
            • befrienders.org – worldwide emotional support network (Samaritans)
            Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

            Instrument used:
            ============================================================================== === FILE: dashboard/brainscreener/eat26.html ============================================================================== EAT-26 — Eating Disorder Screening · brainScreener

            • Duration
            • Items
            • Source

            Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

            Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

            Back to home page
            ============================================================================== === FILE: dashboard/brainscreener/gad7-result.html ============================================================================== Your results — GAD-7 · brainScreener
            Results

            GAD-7

            Date:
            Anonymous report · generated client-side

            Results

            Detailed profile

            What does this mean?

            Recommended next steps

              In an acute crisis

              If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

              • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
              • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
              • findahelpline.com – free, verified crisis helplines in 130+ countries
              • befrienders.org – worldwide emotional support network (Samaritans)
              Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

              Instrument used:
              ============================================================================== === FILE: dashboard/brainscreener/gad7.html ============================================================================== GAD-7 — Anxiety Screening · brainScreener

              • Duration
              • Items
              • Source

              Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

              Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

              Back to home page
              ============================================================================== === FILE: dashboard/brainscreener/index.html ============================================================================== brainScreener — Free anonymous self-tests: ADHD, IQ, depression, anxiety, trauma, personality
              Anonymous self-screening

              A curated library of scientifically grounded self-tests.

              Thirteen instruments at the current level of international research (DSM-5-TR, ICD-11, NICE, USPSTF) — fully anonymous, no registration, no data storage. From ADHD screening through depression, anxiety and trauma to the Big Five personality profile and a colour-coded character profile. Instant results as a printable PDF.

              Test library

              Ten further validated short screenings.

              Each instrument follows the language of its original manual; items, cutoffs and interpretation frameworks correspond to the currently published standards (DSM-5-TR, ICD-11, NICE, USPSTF, S3 guidelines).

              Mood & affect

              Depression, anxiety, bipolar spectrum

              Depression

              PHQ-9

              Kroenke/Spitzer 2001USPSTF 2024

              Gold standard for rating the severity of depressive symptoms. Reference period: the last 2 weeks.

              • Items9
              • Durationapprox. 3–4 min
              Start test →
              Anxiety disorder

              GAD-7

              Spitzer et al. 2006NICE NG222

              The most widely used self-rating for generalised anxiety. Also sensitive to panic disorder and social phobia.

              • Items7
              • Durationapprox. 2–3 min
              Start test →
              Bipolar spectrum

              MDQ

              Hirschfeld et al. 2000

              Screening for lifetime manic/hypomanic symptoms. Three-criteria algorithm.

              • Items13 + 2
              • Durationapprox. 3–4 min
              Start test →

              Trauma, compulsions & eating behaviour

              Stress-related disorders, OCD, disordered eating

              PTSD · DSM-5

              PCL-5

              Weathers et al. 2013DSM-5-TR

              Gold-standard self-rating for post-traumatic stress disorder. 20 items across all four DSM-5 clusters.

              • Items20
              • Durationapprox. 5–7 min
              Start test →
              Obsessive-compulsive disorder

              OCI-R

              Foa et al. 2002Gönner 2008 (Ger.)

              Dimensional assessment of obsessive-compulsive symptoms in six areas (washing, checking, ordering, obsessing, hoarding, neutralising).

              • Items18
              • Durationapprox. 4–5 min
              Start test →
              Eating disorders

              EAT-26

              Garner et al. 1982

              The world's most widely used self-screener for disordered eating. Three subscales (dieting, bulimia, oral control).

              • Items26
              • Durationapprox. 5–7 min
              Start test →

              Substance use & neurodiversity

              Alcohol screening, autism spectrum

              Alcohol use · WHO

              AUDIT

              WHO / Saunders 1993USPSTF 2024

              WHO standard for alcohol screening. Captures hazardous, harmful and dependent drinking.

              • Items10
              • Durationapprox. 3–4 min
              Start test →
              Autism spectrum

              AQ-50

              Baron-Cohen 2001Freitag 2007 (Ger.)

              Original version of the Autism Spectrum Quotient with five subscales — a differentiated functional profile for adult diagnostics.

              • Items50 · 5 subscales
              • Durationapprox. 8–12 min
              Start test →

              Personality & functioning

              Dimensional description instead of pathology

              Big Five · BFI-2 (full version)

              Personality

              Soto & John 2017Danner 2019 (Ger.)

              Current full version of the Big Five model with five domains and 15 facets. T-scores against a German normative sample (N > 4,600).

              • Items60 · 5 domains · 15 facets
              • Durationapprox. 10–14 min
              Start test →
              Level of functioning · WHO · DSM-5-TR

              WHODAS 2.0

              WHO 2010 · 36-itemDSM-5-TR standard

              Full version of the transdiagnostic standard measure of health-related functioning and participation — six ICF domains with individual profiles.

              • Items36 · 6 domains
              • Durationapprox. 8–12 min
              Start test →
              Methodology

              The current state of research, implemented cleanly.

              We reflect the 2024–2026 state of international research on adult mental health diagnostics, intelligence measurement and personality. Items, scales and cutoffs correspond to the published original instruments and their current validations.

              • Clinical standards — DSM-5-TR (APA, 2022), ICD-11 (WHO, 2022) as the reference framework for all symptom thresholds
              • Treatment guidelines — NICE (CG142, NG116, NG222, CG31), USPSTF 2023/2024, DGPPN S3 guidelines for treatment recommendations
              • Licensing — all instruments used are freely usable (public domain, WHO licence, CC licence, author permission)
              • Translations — established validations (Löwe, Krüger-Gottschalk, Gönner, Danner and others)
              • IQ norming — standard score scale with 95% confidence interval, CHC theory
              • Data protection — calculation is client-side (JavaScript), none of your answers are transmitted
              Notes

              Important for interpreting your result.

              Please read these notes carefully before you start.

              No substitute for medical diagnostics

              The instruments offered here are screening tools. They provide indications of clinically relevant symptoms or of your individual performance or personality profile, but they are no substitute for specialist medical, psychological or psychiatric diagnostics. A confirmed diagnosis requires a structured clinical interview, a detailed history and, where appropriate, further psychometric testing.

              Anonymity and data protection

              All tests run entirely in your browser. Your answers are not transmitted, not stored and not logged. When you leave the page, all data is deleted. When printing or exporting to PDF, the result is generated exclusively on your device.

              No warranty

              All results are provided without warranty. If your result is concerning or your symptoms persist, please contact a specialist medical or psychotherapeutic practice. In an acute mental health crisis: call your local emergency number (112 / 911 / 999), or find a free 24/7 helpline for your country at findahelpline.com.

              Credits & thanks

              brainScreener is the free, global English edition of adhsiq.ch — a beautiful, carefully built Swiss screening project. Thank you for letting us build on your work. brainScreener is part of brainonbnb.com ($BOBAI) and, like everything we ship, completely free: no registration, no ads, no data collection.

              ============================================================================== === FILE: dashboard/brainscreener/iq-result.html ============================================================================== Your results — IQ test · brainScreener
              Results

              IQ test · Result

              Date:
              Anonymous results · generated client-side

              Estimated IQ

              Interpretation

              Profile across the cognitive domains

              Share of correct answers per CHC domain.

              Position in the distribution

              What does this mean?

              Important note · no warranty. This result is an estimate based on a short online test. A full IQ test (e.g. WAIS-IV, IST-2000-R, RIAS) is administered in a controlled setting by qualified psychologists and offers substantially higher precision. For important questions (e.g. giftedness, learning disorders, formal assessment), professional psychological testing is essential. Discuss the result with the professional treating you.

              Structure based on CHC theory (Cattell-Horn-Carroll). Norming on the standard score scale (M = 100, SD = 15) based on internal calibration. The 95% confidence interval accounts for the standard error of measurement.
              ============================================================================== === FILE: dashboard/brainscreener/iq.html ============================================================================== IQ test online — 40 tasks based on the CHC model · brainScreener
              IQ test · CHC model

              40 tasks from four cognitive domains.

              The test covers matrix reasoning (fluid intelligence), number series (quantitative reasoning), verbal analogies (crystallised intelligence) and logical reasoning. Difficulty increases as you progress. At the end you receive an IQ estimate on the standard score scale (M = 100, SD = 15) with a 95% confidence interval.

              • Duration (guideline)approx. 25–30 minutes
              • Items40
              • FormatMultiple choice (single answer)
              • Resultsinstant, printable as PDF
              Please note: You can move back and forth between tasks. Avoid interruptions and work briskly but carefully. It is normal not to solve every task.

              Allows the result to be anonymously matched to your file. It is written only onto the printed document and is not stored.

              Back to home page
              ============================================================================== === FILE: dashboard/brainscreener/mdq-result.html ============================================================================== Your results — MDQ · brainScreener
              Results

              MDQ

              Date:
              Anonymous report · generated client-side

              Results

              Detailed profile

              What does this mean?

              Recommended next steps

                In an acute crisis

                If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

                • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
                • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
                • findahelpline.com – free, verified crisis helplines in 130+ countries
                • befrienders.org – worldwide emotional support network (Samaritans)
                Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

                Instrument used:
                ============================================================================== === FILE: dashboard/brainscreener/mdq.html ============================================================================== MDQ — Bipolar Screening · brainScreener

                • Duration
                • Items
                • Source

                Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

                Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

                Back to home page
                ============================================================================== === FILE: dashboard/brainscreener/ocir-result.html ============================================================================== Your results — OCI-R · brainScreener
                Results

                OCI-R

                Date:
                Anonymous report · generated client-side

                Results

                Detailed profile

                What does this mean?

                Recommended next steps

                  In an acute crisis

                  If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

                  • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
                  • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
                  • findahelpline.com – free, verified crisis helplines in 130+ countries
                  • befrienders.org – worldwide emotional support network (Samaritans)
                  Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

                  Instrument used:
                  ============================================================================== === FILE: dashboard/brainscreener/ocir.html ============================================================================== OCI-R — OCD Screening · brainScreener

                  • Duration
                  • Items
                  • Source

                  Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

                  Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

                  Back to home page
                  ============================================================================== === FILE: dashboard/brainscreener/pcl5-result.html ============================================================================== Your results — PCL-5 · brainScreener
                  Results

                  PCL-5

                  Date:
                  Anonymous report · generated client-side

                  Results

                  Detailed profile

                  What does this mean?

                  Recommended next steps

                    In an acute crisis

                    If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

                    • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
                    • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
                    • findahelpline.com – free, verified crisis helplines in 130+ countries
                    • befrienders.org – worldwide emotional support network (Samaritans)
                    Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

                    Instrument used:
                    ============================================================================== === FILE: dashboard/brainscreener/pcl5.html ============================================================================== PCL-5 — Trauma/PTSD screening · brainScreener

                    • Duration
                    • Items
                    • Source

                    Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

                    Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

                    Back to home page
                    ============================================================================== === FILE: dashboard/brainscreener/phq9-result.html ============================================================================== Your results — PHQ-9 · brainScreener
                    Results

                    PHQ-9

                    Date:
                    Anonymous report · generated client-side

                    Results

                    Detailed profile

                    What does this mean?

                    Recommended next steps

                      In an acute crisis

                      If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

                      • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
                      • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
                      • findahelpline.com – free, verified crisis helplines in 130+ countries
                      • befrienders.org – worldwide emotional support network (Samaritans)
                      Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

                      Instrument used:
                      ============================================================================== === FILE: dashboard/brainscreener/phq9.html ============================================================================== PHQ-9 — Depression Screening · brainScreener

                      • Duration
                      • Items
                      • Source

                      Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

                      Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

                      Back to home page
                      ============================================================================== === FILE: dashboard/brainscreener/whodas36-result.html ============================================================================== Your results — WHODAS 2.0 · brainScreener
                      Results

                      WHODAS 2.0

                      Date:
                      Anonymous report · generated client-side

                      Results

                      Detailed profile

                      What does this mean?

                      Recommended next steps

                        In an acute crisis

                        If you are currently under severe strain or in a mental health crisis, help is available around the clock — free of charge and confidential:

                        • Your local emergency number – e.g. 112 (EU), 911 (US), 999 (UK) in acute danger
                        • 988 – Suicide & Crisis Lifeline (US & Canada, 24/7, call or text)
                        • findahelpline.com – free, verified crisis helplines in 130+ countries
                        • befrienders.org – worldwide emotional support network (Samaritans)
                        Important notice · no warranty. This report is a screening based on your self-assessment. It does not replace a medical, psychological or psychiatric diagnosis. A confirmed diagnosis requires a structured clinical interview, a thorough history and, where indicated, further psychometric testing.

                        Instrument used:
                        ============================================================================== === FILE: dashboard/brainscreener/whodas36.html ============================================================================== WHODAS 2.0 (36) — Functioning & Participation · brainScreener

                        • Duration
                        • Items
                        • Source

                        Please answer all questions honestly and spontaneously. There are no right or wrong answers. Your data never leaves your browser.

                        Allows the anonymous matching of the result to your file. It is only printed on the document and never stored.

                        Back to home page