{"id":3635,"date":"2024-10-15T17:29:06","date_gmt":"2024-10-15T15:29:06","guid":{"rendered":"https:\/\/fahrtauglich.ch\/?page_id=3635"},"modified":"2026-10-12T13:26:30","modified_gmt":"2026-10-12T11:26:30","slug":"tetris","status":"publish","type":"page","link":"https:\/\/fahrtauglich.ch\/fr\/praxisportal\/tetris\/","title":{"rendered":"Tetris"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"3635\" class=\"elementor elementor-3635\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-63d0d8a e-flex e-con-boxed e-con e-parent\" data-id=\"63d0d8a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cf16159 elementor-widget elementor-widget-html\" data-id=\"cf16159\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!--\r\n    Tetris \u2014 fahrtauglich.ch\/praxisportal\/tetris\/\r\n    Einbau: Inhalt dieser Datei vollstaendig in EIN Elementor-HTML-Widget einfuegen.\r\n    Das Snippet deckt die ganze Seite zwischen Header und Footer ab (Titel,\r\n    Einleitung mit Link auf trainmybrain.ch, Spiel, Spielanleitung, Texte, Quellen).\r\n    Alle uebrigen Elementor-Widgets der Seite werden geloescht. Kein\r\n    <html>\/<head>\/<body>: Header und Footer liefert das Theme.\r\n\r\n    Grundlage: trainmybrain-tetris.html. Der Spielmotor ist in beiden Versionen\r\n    identisch (Abschnitt \u00abTetris-Motor\u00bb im Skript), Aenderungen dort immer in\r\n    beiden Dateien nachziehen.\r\n\r\n    Optik: fahrtauglich.ch \u2014 Poppins, Gelb #FFBF00, Flaechen #F3F5F8, Pill-Buttons.\r\n    Alles CSS haengt an #fttet, damit nichts in die Elementor-Seite durchschlaegt.\r\n-->\r\n<style>\r\n    #fttet {\r\n        --fttet-gelb: #FFBF00;\r\n        --fttet-gelb-dunkel: #E6AB00;\r\n        --fttet-schwarz: #000000;\r\n        --fttet-text: #1F2937;\r\n        --fttet-text-2: #4B5563;\r\n        --fttet-flaeche: #F3F5F8;\r\n        --fttet-linie: #C8D5DC;\r\n\r\n        font-family: 'Poppins', sans-serif;\r\n        color: var(--fttet-text);\r\n        line-height: 1.5;\r\n        width: 100%;\r\n        max-width: 850px;\r\n        margin: 20px auto 60px;\r\n        box-sizing: border-box;\r\n    }\r\n    #fttet *, #fttet *::before, #fttet *::after { box-sizing: border-box; }\r\n    #fttet [hidden] { display: none !important; }\r\n\r\n    \/* ===== Seitenkopf \u2014 Masse wie die bisherigen Elementor-Widgets ===== *\/\r\n    #fttet .fttet-titel {\r\n        margin: 0;\r\n        font-family: inherit;\r\n        font-size: 48px;\r\n        font-weight: 600;\r\n        line-height: 1.2;\r\n        letter-spacing: 0;\r\n        text-align: center;\r\n        color: var(--fttet-schwarz);\r\n    }\r\n    #fttet .fttet-intro {\r\n        max-width: 760px;\r\n        margin: 50px auto 0;\r\n        font-size: 20px;\r\n        font-weight: 300;\r\n        line-height: 1.5;\r\n        text-align: center;\r\n        color: var(--fttet-schwarz);\r\n    }\r\n    \/* Links: schwarz mit gelber Unterstreichung \u2014 Gelb als Schrift auf Weiss\r\n       hielte nur 1.65:1. *\/\r\n    #fttet .fttet-intro a,\r\n    #fttet .fttet-box a {\r\n        color: var(--fttet-schwarz);\r\n        font-weight: 400;\r\n        text-decoration: underline;\r\n        text-decoration-color: var(--fttet-gelb);\r\n        text-decoration-thickness: 3px;\r\n        text-underline-offset: 3px;\r\n        overflow-wrap: anywhere;\r\n    }\r\n    #fttet .fttet-intro a:hover, #fttet .fttet-box a:hover,\r\n    #fttet .fttet-intro a:focus, #fttet .fttet-box a:focus { color: var(--fttet-schwarz); background: rgba(255, 191, 0, 0.18); }\r\n    #fttet a:focus-visible { outline: 3px solid var(--fttet-schwarz); outline-offset: 2px; }\r\n\r\n    \/* ===== Spielbereich ===== *\/\r\n    #fttet .fttet-spiel {\r\n        max-width: 680px;\r\n        margin: 34px auto 0;\r\n    }\r\n\r\n    \/* Spielkarte (Optik wie Wordle auf fahrtauglich.ch). overflow: clip statt\r\n       hidden \u2014 sonst verschiebt ein Fokus\/scrollIntoView den Karteninhalt. *\/\r\n    #fttet .fttet-karte {\r\n        position: relative;\r\n        overflow: clip;\r\n        background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\r\n        border: 2px solid #dee2e6;\r\n        border-radius: 20px;\r\n        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);\r\n        padding: 30px;\r\n    }\r\n    #fttet .fttet-karte::before {\r\n        content: '';\r\n        position: absolute;\r\n        top: -50%; left: -50%;\r\n        width: 200%; height: 200%;\r\n        background: radial-gradient(circle, rgba(52, 58, 64, 0.05) 1px, transparent 1px);\r\n        background-size: 30px 30px;\r\n        animation: fttet-hintergrund 25s linear infinite;\r\n        z-index: 0;\r\n        pointer-events: none;\r\n    }\r\n    @keyframes fttet-hintergrund {\r\n        0%   { transform: translate(0, 0) rotate(0deg); }\r\n        100% { transform: translate(-30px, -30px) rotate(360deg); }\r\n    }\r\n\r\n    \/* Raster: Feld links, Seitenspalte rechts; Touch-Tasten darunter *\/\r\n    #fttet .fttet-bereich {\r\n        position: relative;\r\n        z-index: 1;\r\n        display: grid;\r\n        grid-template-columns: auto 200px;\r\n        grid-template-rows: auto 1fr auto;\r\n        grid-template-areas:\r\n            \"brett seite\"\r\n            \"brett einst\"\r\n            \"touch touch\";\r\n        column-gap: 24px;\r\n        row-gap: 16px;\r\n        justify-content: center;\r\n        align-items: start;\r\n    }\r\n    #fttet .fttet-brett-huelle { grid-area: brett; }\r\n    #fttet .fttet-seite        { grid-area: seite; display: flex; flex-direction: column; gap: 12px; }\r\n    #fttet .fttet-einst        { grid-area: einst; display: flex; flex-direction: column; gap: 12px; }\r\n    #fttet .fttet-touch        { grid-area: touch; }\r\n\r\n    #fttet .fttet-brett {\r\n        display: block;\r\n        width: 300px;            \/* JS setzt die genaue Groesse *\/\r\n        height: 600px;\r\n        background: #ffffff;\r\n        border-radius: 6px;\r\n        box-shadow: 0 0 0 2px #343a40, 0 4px 15px rgba(0, 0, 0, 0.15);\r\n        touch-action: manipulation;\r\n    }\r\n\r\n    \/* Spielstand *\/\r\n    #fttet .fttet-werte {\r\n        display: grid;\r\n        grid-template-columns: 1fr 1fr;\r\n        gap: 8px;\r\n    }\r\n    #fttet .fttet-wert {\r\n        padding: 8px 10px;\r\n        background: rgba(255, 255, 255, 0.85);\r\n        border: 1px solid rgba(0, 0, 0, 0.06);\r\n        border-radius: 10px;\r\n    }\r\n    #fttet .fttet-wert-label,\r\n    #fttet .fttet-vorschau-label,\r\n    #fttet .fttet-einst-label {\r\n        display: block;\r\n        font-size: 0.7rem;\r\n        font-weight: 500;\r\n        text-transform: uppercase;\r\n        letter-spacing: 0.08em;\r\n        color: var(--fttet-text-2);\r\n    }\r\n    #fttet .fttet-wert-zahl {\r\n        display: block;\r\n        font-size: 1.35rem;\r\n        font-weight: 600;\r\n        line-height: 1.2;\r\n        color: var(--fttet-schwarz);\r\n        font-variant-numeric: tabular-nums;\r\n    }\r\n    #fttet .fttet-vorschau-box {\r\n        padding: 8px 10px 10px;\r\n        background: rgba(255, 255, 255, 0.85);\r\n        border: 1px solid rgba(0, 0, 0, 0.06);\r\n        border-radius: 10px;\r\n    }\r\n    #fttet .fttet-vorschau {\r\n        display: block;\r\n        width: 100%;\r\n        height: 64px;\r\n        margin-top: 4px;\r\n    }\r\n\r\n    \/* ===== Buttons (Pill-Stil der fahrtauglich.ch-Buttons) ===== *\/\r\n    #fttet .fttet-knopf {\r\n        -webkit-appearance: none;\r\n        appearance: none;\r\n        margin: 0;\r\n        display: inline-flex;\r\n        align-items: center;\r\n        justify-content: center;\r\n        width: 100%;\r\n        min-height: 48px;\r\n        padding: 10px 18px;\r\n        background: var(--fttet-gelb);\r\n        border: 2px solid var(--fttet-gelb);\r\n        border-radius: 100px;\r\n        box-shadow: none;\r\n        font-family: inherit;\r\n        font-size: 1rem;\r\n        font-weight: 500;\r\n        line-height: 1.2;\r\n        text-transform: none;\r\n        text-decoration: none;\r\n        color: var(--fttet-schwarz);\r\n        cursor: pointer;\r\n        transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;\r\n    }\r\n    #fttet .fttet-knopf:hover,\r\n    #fttet .fttet-knopf:focus {\r\n        background: var(--fttet-gelb-dunkel);\r\n        border-color: var(--fttet-gelb-dunkel);\r\n        color: var(--fttet-schwarz);\r\n    }\r\n    #fttet .fttet-knopf:hover { transform: translateY(-1px); }\r\n    #fttet .fttet-knopf-hell { background: #ffffff; border-color: var(--fttet-schwarz); }\r\n    #fttet .fttet-knopf-hell:hover,\r\n    #fttet .fttet-knopf-hell:focus { background: var(--fttet-flaeche); border-color: var(--fttet-schwarz); }\r\n\r\n    \/* Einstellungen *\/\r\n    #fttet .fttet-einst-gruppe { display: flex; flex-direction: column; gap: 4px; }\r\n    #fttet .fttet-einst-label strong { color: var(--fttet-schwarz); font-weight: 600; }\r\n    #fttet .fttet-regler {\r\n        width: 100%;\r\n        margin: 0;\r\n        accent-color: var(--fttet-gelb-dunkel);\r\n        cursor: pointer;\r\n    }\r\n    #fttet .fttet-musik-reihe { display: flex; gap: 8px; }\r\n    #fttet .fttet-musik-reihe .fttet-knopf { flex: 1 1 auto; width: auto; min-width: 0; min-height: 44px; padding: 8px 12px; font-size: 0.9rem; }\r\n    \/* Das Theme setzt select auf width: 100% \u2014 hier feste, schmale Breite *\/\r\n    #fttet .fttet-auswahl {\r\n        -webkit-appearance: auto;\r\n        appearance: auto;\r\n        flex: 0 0 92px;\r\n        width: 92px;\r\n        max-width: 92px;\r\n        min-height: 44px;\r\n        margin: 0;\r\n        padding: 6px 8px;\r\n        background: #ffffff;\r\n        border: 2px solid var(--fttet-schwarz);\r\n        border-radius: 10px;\r\n        font-family: inherit;\r\n        font-size: 0.9rem;\r\n        color: var(--fttet-schwarz);\r\n        cursor: pointer;\r\n    }\r\n\r\n    \/* Touch-Tasten: auf Touch-Geraeten und schmalen Fenstern *\/\r\n    #fttet .fttet-touch { display: none; }\r\n    @media (pointer: coarse), (max-width: 767px) {\r\n        #fttet .fttet-touch {\r\n            display: grid;\r\n            grid-template-columns: repeat(5, 1fr);\r\n            gap: 8px;\r\n            width: 100%;\r\n            max-width: 420px;\r\n            justify-self: center;\r\n        }\r\n    }\r\n    #fttet .fttet-taste {\r\n        -webkit-appearance: none;\r\n        appearance: none;\r\n        margin: 0;\r\n        min-height: 56px;\r\n        padding: 0;\r\n        display: flex;\r\n        align-items: center;\r\n        justify-content: center;\r\n        background: #ffffff;\r\n        border: 2px solid var(--fttet-schwarz);\r\n        border-radius: 14px;\r\n        font-family: inherit;\r\n        font-size: 1.5rem;\r\n        font-weight: 600;\r\n        line-height: 1;\r\n        color: var(--fttet-schwarz);\r\n        cursor: pointer;\r\n        touch-action: manipulation;\r\n        -webkit-user-select: none;\r\n        user-select: none;\r\n        -webkit-touch-callout: none;\r\n    }\r\n    #fttet .fttet-taste:active { background: var(--fttet-flaeche); }\r\n    #fttet .fttet-taste-fallen { background: var(--fttet-gelb); border-color: var(--fttet-gelb); }\r\n    #fttet .fttet-taste-fallen:active { background: var(--fttet-gelb-dunkel); }\r\n    #fttet .fttet-taste:hover, #fttet .fttet-taste:focus { color: var(--fttet-schwarz); }\r\n\r\n    #fttet .fttet-knopf:focus-visible,\r\n    #fttet .fttet-taste:focus-visible,\r\n    #fttet .fttet-auswahl:focus-visible,\r\n    #fttet .fttet-regler:focus-visible,\r\n    #fttet .fttet-modal-schliessen:focus-visible,\r\n    #fttet summary:focus-visible {\r\n        outline: 3px solid var(--fttet-schwarz);\r\n        outline-offset: 2px;\r\n    }\r\n\r\n    \/* ===== Spielanleitung ===== *\/\r\n    #fttet .fttet-anleitung {\r\n        margin-top: 24px;\r\n        text-align: left;\r\n        background: #ffffff;\r\n        border-radius: 8px;\r\n        box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);\r\n        padding: 15px 18px;\r\n    }\r\n    #fttet .fttet-anleitung summary {\r\n        cursor: pointer;\r\n        list-style: none;\r\n        display: flex;\r\n        align-items: center;\r\n        justify-content: space-between;\r\n        gap: 1rem;\r\n        padding: 4px 0;\r\n        font-size: 1.15rem;\r\n        font-weight: 600;\r\n        color: var(--fttet-schwarz);\r\n        user-select: none;\r\n    }\r\n    #fttet .fttet-anleitung summary::-webkit-details-marker { display: none; }\r\n    #fttet .fttet-chev { width: 20px; height: 20px; flex: 0 0 auto; transition: transform 0.2s ease; }\r\n    #fttet .fttet-anleitung[open] .fttet-chev { transform: rotate(180deg); }\r\n    #fttet .fttet-anleitung-liste {\r\n        list-style: none;\r\n        margin: 12px 0 4px;\r\n        padding: 0;\r\n        display: grid;\r\n        gap: 8px;\r\n    }\r\n    #fttet .fttet-anleitung-liste li {\r\n        margin: 0;\r\n        padding: 10px 14px;\r\n        background: var(--fttet-flaeche);\r\n        border-left: 3px solid var(--fttet-gelb);\r\n        border-radius: 6px;\r\n        font-size: 0.95rem;\r\n        font-weight: 300;\r\n        line-height: 1.55;\r\n        color: var(--fttet-schwarz);\r\n    }\r\n    #fttet .fttet-anleitung-liste li strong { font-weight: 600; }\r\n\r\n    \/* ===== Textabschnitte (Kartenstil der bisherigen Textboxen) ===== *\/\r\n    #fttet .fttet-abschnitt { margin-top: 70px; }\r\n    #fttet .fttet-abschnitt h2 {\r\n        margin: 0 0 20px;\r\n        font-family: inherit;\r\n        font-size: 36px;\r\n        font-weight: 600;\r\n        line-height: 1.2;\r\n        letter-spacing: 0;\r\n        text-transform: none;\r\n        text-align: center;\r\n        color: var(--fttet-schwarz);\r\n    }\r\n    #fttet .fttet-box {\r\n        background: #ffffff;\r\n        border-radius: 8px;\r\n        box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);\r\n        padding: 15px 20px;\r\n        font-size: 22px;\r\n        font-weight: 300;\r\n        line-height: 1.5;\r\n        color: var(--fttet-schwarz);\r\n        text-align: left;\r\n    }\r\n    #fttet .fttet-box p { margin: 0 0 14px; }\r\n    #fttet .fttet-box p:last-child { margin-bottom: 0; }\r\n    #fttet .fttet-box strong { font-weight: 500; }\r\n\r\n    #fttet .fttet-punkte-tabelle {\r\n        width: 100%;\r\n        max-width: 420px;\r\n        margin: 0 0 14px;\r\n        border-collapse: collapse;\r\n        font-size: 0.9em;\r\n    }\r\n    #fttet .fttet-punkte-tabelle th,\r\n    #fttet .fttet-punkte-tabelle td {\r\n        padding: 6px 10px;\r\n        border-bottom: 1px solid var(--fttet-linie);\r\n        text-align: left;\r\n        font-weight: 300;\r\n    }\r\n    #fttet .fttet-punkte-tabelle th { font-weight: 500; }\r\n    #fttet .fttet-punkte-tabelle td:last-child,\r\n    #fttet .fttet-punkte-tabelle th:last-child { text-align: right; font-variant-numeric: tabular-nums; }\r\n\r\n    #fttet .fttet-tipps { margin: 0; padding-left: 1.2em; }\r\n    #fttet .fttet-tipps li { margin: 0 0 14px; padding-left: 0.2em; }\r\n    #fttet .fttet-tipps li:last-child { margin-bottom: 0; }\r\n    #fttet .fttet-tipps li::marker { color: var(--fttet-gelb-dunkel); }\r\n    #fttet .fttet-tipps strong { display: block; }\r\n\r\n    #fttet .fttet-nutzen { list-style: none; margin: 6px 0 14px; padding: 0; }\r\n    #fttet .fttet-nutzen li {\r\n        display: grid;\r\n        grid-template-columns: 2.4em 1fr;\r\n        gap: 0 0.6em;\r\n        padding: 14px 0;\r\n        border-top: 1px solid var(--fttet-linie);\r\n    }\r\n    #fttet .fttet-nutzen li:last-child { border-bottom: 1px solid var(--fttet-linie); }\r\n    #fttet .fttet-nutzen-nr { font-weight: 600; line-height: 1.5; color: var(--fttet-gelb-dunkel); }\r\n    #fttet .fttet-nutzen strong { display: block; }\r\n    #fttet .fttet-vermerk {\r\n        padding: 10px 14px;\r\n        background: var(--fttet-flaeche);\r\n        border-left: 3px solid var(--fttet-gelb);\r\n        border-radius: 6px;\r\n        font-size: 0.85em;\r\n    }\r\n    #fttet .fttet-quellen-titel { margin-top: 20px !important; font-weight: 500; }\r\n    #fttet .fttet-quellen { list-style: none; margin: 0; padding: 0; font-size: 0.8em; }\r\n    #fttet .fttet-quellen li { margin: 0 0 10px; }\r\n    #fttet .fttet-quellen li:last-child { margin-bottom: 0; }\r\n\r\n    \/* ===== Dialog ===== *\/\r\n    #fttet .fttet-modal {\r\n        position: fixed;\r\n        inset: 0;\r\n        z-index: 100000;\r\n        display: none;\r\n        align-items: center;\r\n        justify-content: center;\r\n        padding: 20px;\r\n    }\r\n    #fttet .fttet-modal.active { display: flex; }\r\n    #fttet .fttet-modal-hintergrund {\r\n        position: absolute;\r\n        inset: 0;\r\n        background: rgba(0, 0, 0, 0.4);\r\n        backdrop-filter: blur(5px);\r\n    }\r\n    #fttet .fttet-modal-inhalt {\r\n        position: relative;\r\n        width: 100%;\r\n        max-width: 420px;\r\n        max-height: 85vh;\r\n        overflow-y: auto;\r\n        background: #ffffff;\r\n        border-radius: 15px;\r\n        box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);\r\n        padding: 32px 28px 28px;\r\n        text-align: center;\r\n        animation: fttet-modal-ein 0.25s ease;\r\n    }\r\n    @keyframes fttet-modal-ein {\r\n        from { opacity: 0; transform: scale(0.96) translateY(12px); }\r\n        to   { opacity: 1; transform: none; }\r\n    }\r\n    #fttet .fttet-modal-schliessen {\r\n        -webkit-appearance: none;\r\n        appearance: none;\r\n        position: absolute;\r\n        top: 8px;\r\n        right: 8px;\r\n        width: 44px;\r\n        height: 44px;\r\n        margin: 0;\r\n        padding: 0;\r\n        display: flex;\r\n        align-items: center;\r\n        justify-content: center;\r\n        background: none;\r\n        border: none;\r\n        border-radius: 50%;\r\n        font-family: inherit;\r\n        font-size: 28px;\r\n        line-height: 1;\r\n        color: #6B7280;\r\n        cursor: pointer;\r\n    }\r\n    #fttet .fttet-modal-schliessen:hover,\r\n    #fttet .fttet-modal-schliessen:focus { background: var(--fttet-flaeche); color: #374151; }\r\n    #fttet .fttet-modal h2 {\r\n        margin: 0 0 8px;\r\n        font-family: inherit;\r\n        font-size: 1.75rem;\r\n        font-weight: 600;\r\n        line-height: 1.2;\r\n        color: var(--fttet-text);\r\n    }\r\n    #fttet .fttet-modal p { margin: 0 0 6px; color: var(--fttet-text-2); }\r\n    #fttet .fttet-ergebnis {\r\n        display: flex;\r\n        justify-content: center;\r\n        gap: 28px;\r\n        margin: 18px 0 10px;\r\n        flex-wrap: wrap;\r\n    }\r\n    #fttet .fttet-ergebnis strong {\r\n        display: block;\r\n        font-size: 2rem;\r\n        font-weight: 700;\r\n        line-height: 1.1;\r\n        color: var(--fttet-schwarz);\r\n        font-variant-numeric: tabular-nums;\r\n    }\r\n    #fttet .fttet-ergebnis span { font-size: 0.85rem; color: var(--fttet-text-2); }\r\n    #fttet .fttet-modal-knoepfe {\r\n        display: flex;\r\n        gap: 10px;\r\n        justify-content: center;\r\n        flex-wrap: wrap;\r\n        margin-top: 18px;\r\n    }\r\n    #fttet .fttet-modal-knoepfe .fttet-knopf { width: auto; padding: 10px 28px; }\r\n\r\n    #fttet .fttet-sr { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }\r\n\r\n    \/* ===== Responsive (Elementor: Tablet <= 1024px, Handy <= 767px) ===== *\/\r\n    @media (max-width: 1024px) {\r\n        #fttet .fttet-titel { font-size: 45px; }\r\n        #fttet .fttet-intro { font-size: 16px; margin-top: 30px; }\r\n        #fttet .fttet-box   { font-size: 16px; }\r\n    }\r\n    @media (max-width: 768px) {\r\n        #fttet { max-width: 95%; }\r\n        #fttet .fttet-karte { padding: 20px; }\r\n    }\r\n    @media (max-width: 767px) {\r\n        #fttet .fttet-titel { font-size: 28px; }\r\n        #fttet .fttet-intro { margin-top: 20px; }\r\n        #fttet .fttet-spiel { margin-top: 24px; }\r\n        #fttet .fttet-abschnitt { margin-top: 50px; }\r\n        #fttet .fttet-abschnitt h2 { font-size: 28px; }\r\n        #fttet .fttet-box   { padding: 15px; }\r\n\r\n        \/* Schmale Seitenspalte neben dem Feld, Einstellungen unter die Tasten *\/\r\n        #fttet .fttet-karte { padding: 14px 10px; border-radius: 16px; }\r\n        #fttet .fttet-bereich {\r\n            grid-template-columns: auto 92px;\r\n            grid-template-rows: auto auto auto;\r\n            grid-template-areas:\r\n                \"brett seite\"\r\n                \"touch touch\"\r\n                \"einst einst\";\r\n            column-gap: 10px;\r\n            row-gap: 12px;\r\n        }\r\n        #fttet .fttet-seite { gap: 8px; }\r\n        #fttet .fttet-werte { grid-template-columns: 1fr; gap: 6px; }\r\n        #fttet .fttet-wert, #fttet .fttet-vorschau-box { padding: 5px 7px; border-radius: 8px; }\r\n        #fttet .fttet-wert-label, #fttet .fttet-vorschau-label { font-size: 0.6rem; letter-spacing: 0.04em; }\r\n        #fttet .fttet-wert-zahl { font-size: 1.05rem; }\r\n        #fttet .fttet-vorschau { height: 44px; }\r\n        #fttet .fttet-seite .fttet-knopf { min-height: 44px; padding: 6px 4px; font-size: 0.85rem; }\r\n        #fttet .fttet-einst {\r\n            flex-direction: row;\r\n            flex-wrap: wrap;\r\n            justify-content: center;\r\n            gap: 12px 20px;\r\n        }\r\n        #fttet .fttet-einst-gruppe { flex: 1 1 200px; max-width: 320px; }\r\n    }\r\n\r\n    @media (prefers-reduced-motion: reduce) {\r\n        #fttet *, #fttet *::before, #fttet *::after {\r\n            animation-duration: 0.01ms !important;\r\n            animation-iteration-count: 1 !important;\r\n            transition-duration: 0.01ms !important;\r\n        }\r\n    }\r\n<\/style>\r\n\r\n<div id=\"fttet\">\r\n\r\n    <div class=\"fttet-sr\" aria-live=\"polite\" aria-atomic=\"true\" id=\"fttet-sr\"><\/div>\r\n\r\n    <h1 class=\"fttet-titel\">Tetris<\/h1>\r\n\r\n    <p class=\"fttet-intro\">Drehen und verschieben Sie die fallenden Steine so, dass l\u00fcckenlose Reihen entstehen. Weitere Spiele f\u00fcr Ged\u00e4chtnis, Konzentration und Logik finden Sie auf <a href=\"https:\/\/trainmybrain.ch\/\">trainmybrain.ch<\/a>, unserer Plattform f\u00fcr kognitive Spiele.<\/p>\r\n\r\n    <div class=\"fttet-spiel\">\r\n\r\n        <section class=\"fttet-karte\" aria-label=\"Tetris Spielbereich\">\r\n            <div class=\"fttet-bereich\" id=\"fttet-bereich\">\r\n\r\n                <div class=\"fttet-brett-huelle\" id=\"fttet-brett-huelle\">\r\n                    <canvas class=\"fttet-brett\" id=\"fttet-brett\" width=\"300\" height=\"600\" role=\"img\" aria-label=\"Tetris-Spielfeld, 10 Spalten und 20 Zeilen\"><\/canvas>\r\n                <\/div>\r\n\r\n                <div class=\"fttet-seite\" id=\"fttet-seite\">\r\n                    <div class=\"fttet-vorschau-box\">\r\n                        <span class=\"fttet-vorschau-label\">N\u00e4chster Stein<\/span>\r\n                        <canvas class=\"fttet-vorschau\" id=\"fttet-vorschau\" role=\"img\" aria-label=\"Vorschau auf den n\u00e4chsten Stein\"><\/canvas>\r\n                    <\/div>\r\n                    <div class=\"fttet-werte\" aria-label=\"Spielstand\">\r\n                        <div class=\"fttet-wert\"><span class=\"fttet-wert-label\">Punkte<\/span><span class=\"fttet-wert-zahl\" id=\"fttet-punkte\">0<\/span><\/div>\r\n                        <div class=\"fttet-wert\"><span class=\"fttet-wert-label\">Linien<\/span><span class=\"fttet-wert-zahl\" id=\"fttet-linien\">0<\/span><\/div>\r\n                        <div class=\"fttet-wert\"><span class=\"fttet-wert-label\">Level<\/span><span class=\"fttet-wert-zahl\" id=\"fttet-level\">1<\/span><\/div>\r\n                        <div class=\"fttet-wert\"><span class=\"fttet-wert-label\">Bestwert<\/span><span class=\"fttet-wert-zahl\" id=\"fttet-best\">0<\/span><\/div>\r\n                    <\/div>\r\n                    <button type=\"button\" id=\"fttet-start\" class=\"fttet-knopf\">Start<\/button>\r\n                    <button type=\"button\" id=\"fttet-neu\" class=\"fttet-knopf fttet-knopf-hell\">Neues Spiel<\/button>\r\n                <\/div>\r\n\r\n                <div class=\"fttet-einst\">\r\n                    <div class=\"fttet-einst-gruppe\">\r\n                        <label class=\"fttet-einst-label\" for=\"fttet-startlevel\">Startlevel: <strong id=\"fttet-startlevel-wert\">1<\/strong><\/label>\r\n                        <input class=\"fttet-regler\" type=\"range\" id=\"fttet-startlevel\" min=\"1\" max=\"10\" value=\"1\">\r\n                    <\/div>\r\n                    <div class=\"fttet-einst-gruppe\">\r\n                        <span class=\"fttet-einst-label\" id=\"fttet-musik-label\">Musik<\/span>\r\n                        <div class=\"fttet-musik-reihe\">\r\n                            <button type=\"button\" id=\"fttet-musik\" class=\"fttet-knopf fttet-knopf-hell\" aria-pressed=\"false\" aria-describedby=\"fttet-musik-label\">Musik: aus<\/button>\r\n                            <select class=\"fttet-auswahl\" id=\"fttet-musikstil\" aria-label=\"Musikstil\">\r\n                                <option value=\"Classic\">Classic<\/option>\r\n                                <option value=\"Jazz\">Jazz<\/option>\r\n                                <option value=\"Rock\">Rock<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"fttet-touch\" id=\"fttet-touch\" aria-label=\"Touch-Steuerung\">\r\n                    <button type=\"button\" class=\"fttet-taste\" id=\"fttet-links\" aria-label=\"Nach links\">\u2190<\/button>\r\n                    <button type=\"button\" class=\"fttet-taste\" id=\"fttet-drehen\" aria-label=\"Drehen\">\u21bb<\/button>\r\n                    <button type=\"button\" class=\"fttet-taste\" id=\"fttet-rechts\" aria-label=\"Nach rechts\">\u2192<\/button>\r\n                    <button type=\"button\" class=\"fttet-taste\" id=\"fttet-runter\" aria-label=\"Schneller fallen\">\u2193<\/button>\r\n                    <button type=\"button\" class=\"fttet-taste fttet-taste-fallen\" id=\"fttet-fallen\" aria-label=\"Ganz fallen lassen\">\u2913<\/button>\r\n                <\/div>\r\n\r\n            <\/div>\r\n        <\/section>\r\n\r\n        <!-- Spielanleitung -->\r\n        <details class=\"fttet-anleitung\" id=\"fttet-anleitung\">\r\n            <summary>\r\n                Spielanleitung\r\n                <svg class=\"fttet-chev\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"\/><\/svg>\r\n            <\/summary>\r\n            <ul class=\"fttet-anleitung-liste\">\r\n                <li><strong>Ziel:<\/strong> Ordnen Sie die fallenden Steine so an, dass waagrechte Reihen ohne L\u00fccke entstehen. Volle Reihen verschwinden und bringen Punkte.<\/li>\r\n                <li><strong>Tastatur:<\/strong> Pfeil links und rechts verschieben den Stein, Pfeil oben dreht ihn im Uhrzeigersinn, Pfeil unten l\u00e4sst ihn schneller fallen. Die Leertaste l\u00e4sst ihn sofort ganz nach unten fallen. P oder Esc pausiert.<\/li>\r\n                <li><strong>Touch:<\/strong> Die Tasten unter dem Feld (\u2190 \u21bb \u2192 \u2193 \u2913) machen dasselbe. Gedr\u00fcckt halten wiederholt die Bewegung.<\/li>\r\n                <li><strong>Schatten:<\/strong> Der umrandete Umriss zeigt, wo der Stein landen wird.<\/li>\r\n                <li><strong>Nach dem Aufsetzen:<\/strong> Eine halbe Sekunde bleibt, um den Stein noch zu schieben oder zu drehen, danach wird er fest.<\/li>\r\n                <li><strong>Drehen am Rand:<\/strong> Passt der gedrehte Stein nicht an seinen Platz, weicht er automatisch zur Seite aus.<\/li>\r\n                <li><strong>Level:<\/strong> Alle 10 Reihen steigt das Level und die Steine fallen schneller. Mit dem Startlevel beginnen Sie direkt schneller.<\/li>\r\n                <li><strong>Spielende:<\/strong> Hat ein neuer Stein oben keinen Platz mehr, ist das Spiel vorbei. Ihr Bestwert bleibt auf diesem Ger\u00e4t gespeichert.<\/li>\r\n            <\/ul>\r\n        <\/details>\r\n\r\n    <\/div><!-- \/.fttet-spiel -->\r\n\r\n    <!-- ===== Wie funktioniert Tetris? ===== -->\r\n    <section class=\"fttet-abschnitt\" aria-labelledby=\"fttet-h-regeln\">\r\n        <h2 id=\"fttet-h-regeln\">Wie funktioniert Tetris?<\/h2>\r\n        <div class=\"fttet-box\">\r\n            <p>Von oben fallen nacheinander Steine in ein Feld mit 10 Spalten und 20 Zeilen. Jeder Stein besteht aus vier Quadraten. Es gibt sieben Formen, die nach ihrer Gestalt mit Buchstaben benannt sind: I, O, T, S, Z, J und L.<\/p>\r\n            <p>Sie drehen und verschieben jeden Stein, bis er passend liegt. Ist eine waagrechte Reihe l\u00fcckenlos gef\u00fcllt, verschwindet sie und alles dar\u00fcber rutscht nach. Je mehr Reihen Sie mit einem Stein gleichzeitig f\u00fcllen, desto mehr Punkte gibt es:<\/p>\r\n            <table class=\"fttet-punkte-tabelle\">\r\n                <thead><tr><th scope=\"col\">Reihen auf einmal<\/th><th scope=\"col\">Punkte \u00d7 Level<\/th><\/tr><\/thead>\r\n                <tbody>\r\n                    <tr><td>1 Reihe<\/td><td>40<\/td><\/tr>\r\n                    <tr><td>2 Reihen<\/td><td>100<\/td><\/tr>\r\n                    <tr><td>3 Reihen<\/td><td>300<\/td><\/tr>\r\n                    <tr><td>4 Reihen (\u00abTetris\u00bb)<\/td><td>1200<\/td><\/tr>\r\n                <\/tbody>\r\n            <\/table>\r\n            <p>Alle 10 Reihen steigt das Level, die Steine fallen schneller und jede Reihe z\u00e4hlt mehr. Das Spiel endet, wenn der Stapel so hoch ist, dass ein neuer Stein keinen Platz mehr hat. Die Steine kommen in Siebener-Paketen mit je einer Form jeder Art. So wartet man nie lange auf einen bestimmten Stein.<\/p>\r\n        <\/div>\r\n    <\/section>\r\n\r\n    <!-- ===== Nutzen ===== -->\r\n    <section class=\"fttet-abschnitt\" aria-labelledby=\"fttet-h-nutzen\">\r\n        <h2 id=\"fttet-h-nutzen\">Was ist der Nutzen von Tetris?<\/h2>\r\n        <div class=\"fttet-box\">\r\n            <p>Tetris geh\u00f6rt zu den am besten untersuchten Computerspielen. Diese F\u00e4higkeiten sind dabei gefordert:<\/p>\r\n            <ol class=\"fttet-nutzen\">\r\n                <li><span class=\"fttet-nutzen-nr\" aria-hidden=\"true\">01<\/span><div><strong>R\u00e4umliches Vorstellungsverm\u00f6gen<\/strong>Jeder Stein muss im Kopf gedreht und mit den L\u00fccken verglichen werden. In einer Studie verbesserten Studierende, die regelm\u00e4ssig Tetris spielten, ihr r\u00e4umliches Drehen auch bei anderen Aufgaben, und der Effekt hielt \u00fcber Monate an (Terlecki et al., 2008).<\/div><\/li>\r\n                <li><span class=\"fttet-nutzen-nr\" aria-hidden=\"true\">02<\/span><div><strong>Effizienter denken durch \u00dcbung<\/strong>Nach einigen Wochen Training brauchte das Gehirn beim Spielen weniger Energie, w\u00e4hrend die Leistung stieg. Die Forschenden deuten das als Zeichen, dass \u00dcbung das Gehirn effizienter arbeiten l\u00e4sst (Haier et al., 1992).<\/div><\/li>\r\n                <li><span class=\"fttet-nutzen-nr\" aria-hidden=\"true\">03<\/span><div><strong>Vorausplanen unter Zeitdruck<\/strong>W\u00e4hrend ein Stein f\u00e4llt, entscheiden Sie schon, wohin der n\u00e4chste geh\u00f6rt. Das trainiert schnelles Abw\u00e4gen und Planen.<\/div><\/li>\r\n                <li><span class=\"fttet-nutzen-nr\" aria-hidden=\"true\">04<\/span><div><strong>Dauerhafte Aufmerksamkeit<\/strong>Feld, aktueller Stein und Vorschau wollen gleichzeitig beachtet werden, und mit jedem Level wird es schneller.<\/div><\/li>\r\n                <li><span class=\"fttet-nutzen-nr\" aria-hidden=\"true\">05<\/span><div><strong>Abschalten<\/strong>Tetris fordert die volle Aufmerksamkeit. Eine kurze Runde kann deshalb eine willkommene Pause vom Alltag sein.<\/div><\/li>\r\n            <\/ol>\r\n            <p class=\"fttet-vermerk\">Belegt ist vor allem, dass Spielende in Tetris selbst und in \u00e4hnlichen r\u00e4umlichen Aufgaben besser werden. Dass sich das auf den Alltag oder die Fahreignung \u00fcbertr\u00e4gt, ist nicht nachgewiesen.<\/p>\r\n        <\/div>\r\n    <\/section>\r\n\r\n    <!-- ===== Tipps ===== -->\r\n    <section class=\"fttet-abschnitt\" aria-labelledby=\"fttet-h-tipps\">\r\n        <h2 id=\"fttet-h-tipps\">Tetris-Tipps f\u00fcr mehr Punkte<\/h2>\r\n        <div class=\"fttet-box\">\r\n            <ul class=\"fttet-tipps\">\r\n                <li><strong>Flach stapeln<\/strong>Halten Sie die Oberfl\u00e4che m\u00f6glichst eben. Hohe T\u00fcrme und tiefe Schluchten lassen L\u00fccken entstehen, die schwer zu f\u00fcllen sind.<\/li>\r\n                <li><strong>Einen Schacht f\u00fcr den I-Stein freihalten<\/strong>Nur der lange I-Stein f\u00fcllt vier Reihen auf einmal. Lassen Sie am Rand eine Spalte frei, dann bringt er Ihnen 1200 Punkte mal Level.<\/li>\r\n                <li><strong>Fr\u00fch drehen<\/strong>Drehen Sie den Stein gleich nach dem Erscheinen. So sehen Sie schneller, wo er passt. Ge\u00fcbte Spielende machen das ebenso: Das Drehen am Bildschirm ist schneller als das Drehen im Kopf (Kirsh &amp; Maglio, 1994).<\/li>\r\n                <li><strong>Vorschau und Schatten nutzen<\/strong>Planen Sie mit dem n\u00e4chsten Stein. Der Schatten zeigt, wo der aktuelle landet, bevor Sie ihn fallen lassen.<\/li>\r\n                <li><strong>Unter Kanten schieben<\/strong>Nach dem Aufsetzen bleibt eine halbe Sekunde: Ein Stein l\u00e4sst sich so noch seitlich unter einen \u00dcberhang schieben.<\/li>\r\n                <li><strong>Ruhig bleiben<\/strong>Wird es schneller, hilft ein gleichm\u00e4ssiger Rhythmus mehr als Hektik. Lieber einmal Pause dr\u00fccken als einen Stein falsch setzen.<\/li>\r\n            <\/ul>\r\n        <\/div>\r\n    <\/section>\r\n\r\n    <!-- ===== Geschichte ===== -->\r\n    <section class=\"fttet-abschnitt\" aria-labelledby=\"fttet-h-geschichte\">\r\n        <h2 id=\"fttet-h-geschichte\">Geschichte<\/h2>\r\n        <div class=\"fttet-box\">\r\n            <p>Tetris entwickelte der russische Programmierer Alexei Paschitnow 1984 am Dorodnizyn-Rechenzentrum der Akademie der Wissenschaften in Moskau. Vorbild war das Legespiel Pentomino. Der Name verbindet das griechische \u00abtetra\u00bb (vier), weil jeder Stein aus vier Quadraten besteht, mit Tennis, Paschitnows Lieblingssport.<\/p>\r\n            <p>Das Spiel verbreitete sich zuerst in der Sowjetunion und dann weltweit. Weltber\u00fchmt wurde es 1989 mit dem Nintendo Game Boy, dem es beilag. Heute gilt Tetris als eines der meistverkauften Videospiele aller Zeiten und ist auch in der Forschung beliebt, weil es einfach zu erkl\u00e4ren und doch schwer zu meistern ist.<\/p>\r\n            <p class=\"fttet-quellen-titel\">Quellen<\/p>\r\n            <ul class=\"fttet-quellen\">\r\n                <li>Haier, R. J., Siegel, B. V., MacLachlan, A., Soderling, E., Lottenberg, S. &amp; Buchsbaum, M. S. (1992). Regional glucose metabolic changes after learning a complex visuospatial\/motor task: a positron emission tomographic study. <em>Brain Research, 570<\/em>(1\u20132), 134\u2013143. <a href=\"https:\/\/doi.org\/10.1016\/0006-8993(92)90573-R\" target=\"_blank\" rel=\"noopener\">https:\/\/doi.org\/10.1016\/0006-8993(92)90573-R<\/a><\/li>\r\n                <li>Kirsh, D. &amp; Maglio, P. (1994). On distinguishing epistemic from pragmatic action. <em>Cognitive Science, 18<\/em>(4), 513\u2013549. <a href=\"https:\/\/doi.org\/10.1207\/s15516709cog1804_1\" target=\"_blank\" rel=\"noopener\">https:\/\/doi.org\/10.1207\/s15516709cog1804_1<\/a><\/li>\r\n                <li>Terlecki, M. S., Newcombe, N. S. &amp; Little, M. (2008). Durable and generalized effects of spatial experience on mental rotation: gender differences in growth patterns. <em>Applied Cognitive Psychology, 22<\/em>(7), 996\u20131013. <a href=\"https:\/\/doi.org\/10.1002\/acp.1420\" target=\"_blank\" rel=\"noopener\">https:\/\/doi.org\/10.1002\/acp.1420<\/a><\/li>\r\n                <li>Wikipedia: Tetris. <a href=\"https:\/\/de.wikipedia.org\/wiki\/Tetris\" target=\"_blank\" rel=\"noopener\">https:\/\/de.wikipedia.org\/wiki\/Tetris<\/a><\/li>\r\n            <\/ul>\r\n        <\/div>\r\n    <\/section>\r\n\r\n    <!-- Dialog: Spiel vorbei -->\r\n    <div class=\"fttet-modal\" id=\"fttet-modal-ende\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"fttet-modal-titel\">\r\n        <div class=\"fttet-modal-hintergrund\"><\/div>\r\n        <div class=\"fttet-modal-inhalt\">\r\n            <button type=\"button\" class=\"fttet-modal-schliessen\" aria-label=\"Schliessen\">\u00d7<\/button>\r\n            <h2 id=\"fttet-modal-titel\">Spiel vorbei<\/h2>\r\n            <p>Der Stapel hat den oberen Rand erreicht. Ihr Ergebnis:<\/p>\r\n            <div class=\"fttet-ergebnis\">\r\n                <div><strong id=\"fttet-ende-punkte\">0<\/strong><span>Punkte<\/span><\/div>\r\n                <div><strong id=\"fttet-ende-linien\">0<\/strong><span>Linien<\/span><\/div>\r\n                <div><strong id=\"fttet-ende-level\">1<\/strong><span>Level<\/span><\/div>\r\n            <\/div>\r\n            <p id=\"fttet-ende-best\"><\/p>\r\n            <div class=\"fttet-modal-knoepfe\">\r\n                <button type=\"button\" id=\"fttet-nochmals\" class=\"fttet-knopf\">Nochmals spielen<\/button>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n<\/div>\r\n\r\n<script>\r\n(function () {\r\n    'use strict';\r\n\r\n    \/\/ Elementor oder ein Optimierungs-Plugin kann das Skript nach\r\n    \/\/ DOMContentLoaded ausfuehren \u2014 dann wuerde ein reiner Listener nie feuern.\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', fttetStart);\r\n    } else {\r\n        fttetStart();\r\n    }\r\n\r\n    function fttetStart() {\r\n        const root = document.getElementById('fttet');\r\n        if (!root || root.dataset.fttetBereit) return;\r\n        root.dataset.fttetBereit = '1';\r\n\r\n        \/\/ \u2550\u2550 Tetris-Motor (identisch in fahrtauglich- und trainmybrain-Version) \u2550\u2550\r\n        \/\/ Stand 2026-10-12. Gegenueber der alten Fassung behoben:\r\n        \/\/   - Beutel mit sort(() => Math.random() - 0.5) war verzerrt (T kam zu\r\n        \/\/     26 % als erstes Stueck, J zu 4 %) -> Fisher-Yates\r\n        \/\/   - das I-Stueck erschien in einem vollen Stapel und ueberschrieb\r\n        \/\/     Bloecke, ohne dass das Spiel endete -> Game Over, wenn ein neues\r\n        \/\/     Stueck keinen Platz hat\r\n        \/\/   - die Vorschau lag ueber dem Spielfeld (Desktop 4.6 x 3.9 Zellen,\r\n        \/\/     Handy 57 % der Breite) -> Vorschau in der Seitenspalte\r\n        \/\/ Neu (Entscheid User): Schatten am Landeplatz, 0.5 s Sperrzeit nach dem\r\n        \/\/ Aufsetzen, Ausweichen beim Drehen an Wand\/Stapel, Wiederholung beim\r\n        \/\/ Gedrueckthalten der Touch-Tasten, Musik startet still, Bestwert.\r\n        function tetrisMotor(cfg) {\r\n            const el = s => document.getElementById(cfg.prefix + s);\r\n\r\n            const SPALTEN = 10, ZEILEN = 20;\r\n            const SPERRZEIT = 500;        \/\/ ms nach dem Aufsetzen, um noch zu schieben\r\n            const MAX_SPERR_RESETS = 15;  \/\/ gegen endloses Drehen am Boden\r\n            const WDH_VERZOEGERUNG = 170, WDH_TAKT = 50;   \/\/ Touch: Gedrueckthalten\r\n            const PUNKTE = [0, 40, 100, 300, 1200];\r\n\r\n            const FORMEN = {\r\n                I: [[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]],\r\n                J: [[1,0,0],[1,1,1],[0,0,0]],\r\n                L: [[0,0,1],[1,1,1],[0,0,0]],\r\n                O: [[1,1],[1,1]],\r\n                S: [[0,1,1],[1,1,0],[0,0,0]],\r\n                Z: [[1,1,0],[0,1,1],[0,0,0]],\r\n                T: [[0,1,0],[1,1,1],[0,0,0]]\r\n            };\r\n            const FARBEN = cfg.farben;\r\n\r\n            const BEWEGUNG_REDUZIERT = window.matchMedia &&\r\n                window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n\r\n            \/\/ \u2500\u2500 DOM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            const brett       = el('brett');\r\n            const ctx         = brett.getContext('2d');\r\n            const huelle      = el('brett-huelle');\r\n            const bereich     = el('bereich');\r\n            const vorschau    = el('vorschau');\r\n            const vCtx        = vorschau.getContext('2d');\r\n            const punkteEl    = el('punkte');\r\n            const linienEl    = el('linien');\r\n            const levelEl     = el('level');\r\n            const bestEl      = el('best');\r\n            const regler      = el('startlevel');\r\n            const reglerWert  = el('startlevel-wert');\r\n            const btnStart    = el('start');\r\n            const btnNeu      = el('neu');\r\n            const btnMusik    = el('musik');\r\n            const musikStil   = el('musikstil');\r\n            const srEl        = el('sr');\r\n\r\n            \/\/ \u2500\u2500 Zustand \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            let feld = [];\r\n            let stueck = null, naechstes = null;\r\n            let beutel = [];\r\n            let zustand = 'bereit';   \/\/ bereit | laeuft | pause | ende\r\n            let punkte = 0, linien = 0, level = 1, startLevel = 1;\r\n            let fallTakt = 1000, fallZaehler = 0;\r\n            let sperrUhr = 0, sperrResets = 0, tiefsteZeile = 0;\r\n            let letzteZeit = 0, schleife = null;\r\n            let zelle = 30, breite = 300, hoehe = 600;\r\n\r\n            function leeresFeld() {\r\n                feld = Array.from({ length: ZEILEN }, () => new Array(SPALTEN).fill(0));\r\n            }\r\n\r\n            \/\/ \u2500\u2500 Zufall: 7er-Beutel, Fisher-Yates (gleichverteilt) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            function beutelFuellen() {\r\n                beutel = Object.keys(FORMEN);\r\n                for (let i = beutel.length - 1; i > 0; i--) {\r\n                    const j = Math.floor(Math.random() * (i + 1));\r\n                    [beutel[i], beutel[j]] = [beutel[j], beutel[i]];\r\n                }\r\n            }\r\n            function ausBeutel() {\r\n                if (!beutel.length) beutelFuellen();\r\n                return beutel.pop();\r\n            }\r\n\r\n            \/\/ Neues Stueck: waagrecht mittig, oberste belegte Zeile auf Zeile 0\r\n            \/\/ (sofort sichtbar).\r\n            function erzeuge(name) {\r\n                const matrix = FORMEN[name].map(r => r.slice());\r\n                const oben = matrix.findIndex(r => r.some(Boolean));\r\n                return { name, matrix, zeile: -oben, spalte: Math.floor((SPALTEN - matrix[0].length) \/ 2) };\r\n            }\r\n\r\n            \/\/ \u2500\u2500 Regeln \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            \/\/ Oberhalb des Feldes (z < 0) ist Platz, z. B. zum Drehen ganz oben.\r\n            function passt(matrix, z, s) {\r\n                for (let r = 0; r < matrix.length; r++) {\r\n                    for (let c = 0; c < matrix[r].length; c++) {\r\n                        if (!matrix[r][c]) continue;\r\n                        const nz = z + r, ns = s + c;\r\n                        if (ns < 0 || ns >= SPALTEN || nz >= ZEILEN) return false;\r\n                        if (nz >= 0 && feld[nz][ns]) return false;\r\n                    }\r\n                }\r\n                return true;\r\n            }\r\n\r\n            function liegtAuf() { return !passt(stueck.matrix, stueck.zeile + 1, stueck.spalte); }\r\n\r\n            function drehen(matrix) {\r\n                return matrix[0].map((_, i) => matrix.map(r => r[i]).reverse());   \/\/ im Uhrzeigersinn\r\n            }\r\n\r\n            \/\/ Erfolgreiche Bewegung am Boden setzt die Sperrzeit zurueck,\r\n            \/\/ hoechstens MAX_SPERR_RESETS Mal pro Stueck und Zeile.\r\n            function nachBewegung() {\r\n                if (sperrResets < MAX_SPERR_RESETS) { sperrUhr = 0; sperrResets++; }\r\n            }\r\n\r\n            function schieben(ds) {\r\n                if (zustand !== 'laeuft') return false;\r\n                if (!passt(stueck.matrix, stueck.zeile, stueck.spalte + ds)) return false;\r\n                stueck.spalte += ds;\r\n                nachBewegung();\r\n                zeichnen();\r\n                return true;\r\n            }\r\n\r\n            \/\/ Drehen mit Ausweichen: erst an Ort, dann seitlich, zuletzt eine\r\n            \/\/ Zeile hoeher \u2014 so scheitert Drehen an Wand oder Stapel nicht mehr.\r\n            const AUSWEICHEN = [[0, 0], [0, -1], [0, 1], [0, -2], [0, 2], [-1, 0], [-1, -1], [-1, 1]];\r\n            function drehenVersuchen() {\r\n                if (zustand !== 'laeuft' || stueck.name === 'O') return false;\r\n                const m = drehen(stueck.matrix);\r\n                for (const [dz, ds] of AUSWEICHEN) {\r\n                    if (passt(m, stueck.zeile + dz, stueck.spalte + ds)) {\r\n                        stueck.matrix = m;\r\n                        stueck.zeile += dz;\r\n                        stueck.spalte += ds;\r\n                        nachBewegung();\r\n                        zeichnen();\r\n                        return true;\r\n                    }\r\n                }\r\n                return false;\r\n            }\r\n\r\n            function einsRunter() {\r\n                if (!passt(stueck.matrix, stueck.zeile + 1, stueck.spalte)) return false;\r\n                stueck.zeile++;\r\n                if (stueck.zeile > tiefsteZeile) { tiefsteZeile = stueck.zeile; sperrResets = 0; }\r\n                sperrUhr = 0;\r\n                return true;\r\n            }\r\n\r\n            \/\/ Pfeil runter: schneller fallen. Am Boden passiert nichts \u2014 die\r\n            \/\/ Sperrzeit laeuft weiter, Schieben bleibt moeglich.\r\n            function weicherFall() {\r\n                if (zustand !== 'laeuft') return;\r\n                if (einsRunter()) { fallZaehler = 0; zeichnen(); }\r\n            }\r\n\r\n            function harterFall() {\r\n                if (zustand !== 'laeuft') return;\r\n                while (einsRunter()) {}\r\n                festsetzen();\r\n            }\r\n\r\n            function landeZeile() {\r\n                let z = stueck.zeile;\r\n                while (passt(stueck.matrix, z + 1, stueck.spalte)) z++;\r\n                return z;\r\n            }\r\n\r\n            function festsetzen() {\r\n                let ueberRand = false;\r\n                stueck.matrix.forEach((r, ri) => r.forEach((v, ci) => {\r\n                    if (!v) return;\r\n                    const z = stueck.zeile + ri;\r\n                    if (z < 0) ueberRand = true;\r\n                    else feld[z][stueck.spalte + ci] = stueck.name;\r\n                }));\r\n                if (ueberRand) { spielEnde(); return; }   \/\/ ueber den oberen Rand gestapelt\r\n\r\n                linienLeeren();\r\n\r\n                stueck = naechstes;\r\n                naechstes = erzeuge(ausBeutel());\r\n                tiefsteZeile = stueck.zeile;\r\n                sperrUhr = 0; sperrResets = 0; fallZaehler = 0;\r\n                vorschauZeichnen();\r\n\r\n                \/\/ Kein Platz fuer das neue Stueck: Spielfeld voll\r\n                if (!passt(stueck.matrix, stueck.zeile, stueck.spalte)) { spielEnde(); return; }\r\n                zeichnen();\r\n            }\r\n\r\n            function linienLeeren() {\r\n                let geleert = 0;\r\n                for (let z = ZEILEN - 1; z >= 0; z--) {\r\n                    if (feld[z].every(Boolean)) {\r\n                        feld.splice(z, 1);\r\n                        feld.unshift(new Array(SPALTEN).fill(0));\r\n                        geleert++;\r\n                        z++;   \/\/ dieselbe Zeile neu pruefen\r\n                    }\r\n                }\r\n                if (!geleert) return;\r\n                punkte += PUNKTE[geleert] * level;\r\n                linien += geleert;\r\n                \/\/ Alle 10 Linien ein Level hoeher, gezaehlt ab dem Startlevel\r\n                const neuesLevel = startLevel + Math.floor(linien \/ 10);\r\n                if (neuesLevel > level) {\r\n                    level = neuesLevel;\r\n                    fallTakt = taktFuer(level);\r\n                    sr(`Level ${level}.`);\r\n                }\r\n                werteAnzeigen();\r\n            }\r\n\r\n            function taktFuer(l) { return Math.max(100, 1000 - (l - 1) * 100); }\r\n\r\n            \/\/ \u2500\u2500 Spielablauf \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            function neuesSpiel() {\r\n                cfg.modalSchliessen('modal-ende');\r\n                leeresFeld();\r\n                beutel = [];\r\n                startLevel = parseInt(regler.value, 10) || 1;\r\n                level = startLevel;\r\n                punkte = 0; linien = 0;\r\n                fallTakt = taktFuer(level);\r\n                stueck = erzeuge(ausBeutel());\r\n                naechstes = erzeuge(ausBeutel());\r\n                tiefsteZeile = stueck.zeile;\r\n                sperrUhr = 0; sperrResets = 0; fallZaehler = 0;\r\n                werteAnzeigen();\r\n                vorschauZeichnen();\r\n                zustand = 'laeuft';\r\n                knopfText();\r\n                sr(`Spiel gestartet, Level ${level}.`);\r\n                cfg.ereignis({ event: 'tetris_start', tetris_startlevel: startLevel });\r\n                musikAnpassen();\r\n                feldSichtbarMachen();\r\n                schleifeStarten();\r\n            }\r\n\r\n            function pause() {\r\n                if (zustand !== 'laeuft') return;\r\n                zustand = 'pause';\r\n                schleifeStopp();\r\n                knopfText();\r\n                musikAnpassen();\r\n                zeichnen();\r\n                sr('Pause.');\r\n            }\r\n\r\n            function weiter() {\r\n                if (zustand !== 'pause') return;\r\n                zustand = 'laeuft';\r\n                knopfText();\r\n                musikAnpassen();\r\n                schleifeStarten();\r\n            }\r\n\r\n            function startPause() {\r\n                if (zustand === 'laeuft') pause();\r\n                else if (zustand === 'pause') weiter();\r\n                else neuesSpiel();\r\n            }\r\n\r\n            function spielEnde() {\r\n                zustand = 'ende';\r\n                schleifeStopp();\r\n                knopfText();\r\n                musikAnpassen();\r\n                zeichnen();\r\n                const bisher = bestwert();\r\n                const neu = punkte > bisher;\r\n                if (neu) bestwertSpeichern(punkte);\r\n                werteAnzeigen();\r\n                el('ende-punkte').textContent = punkte;\r\n                el('ende-linien').textContent = linien;\r\n                el('ende-level').textContent  = level;\r\n                el('ende-best').textContent = neu\r\n                    ? (bisher ? 'Neuer Bestwert!' : 'Ihr erster Bestwert.')\r\n                    : `Ihr Bestwert: ${bisher}`;\r\n                sr(`Spiel vorbei. ${punkte} Punkte, ${linien} Linien.`);\r\n                cfg.ereignis({ event: 'tetris_game_over', tetris_punkte: punkte, tetris_linien: linien, tetris_level: level, tetris_startlevel: startLevel });\r\n                setTimeout(() => { if (zustand === 'ende') cfg.modalOeffnen('modal-ende', 'nochmals'); }, 400);\r\n            }\r\n\r\n            function schleifeStarten() {\r\n                schleifeStopp();\r\n                letzteZeit = performance.now();\r\n                const takt = (jetzt) => {\r\n                    if (zustand !== 'laeuft') { schleife = null; return; }\r\n                    \/\/ Nach einem Tab-Wechsel nicht mehrere Zeilen auf einmal fallen\r\n                    const dt = Math.min(100, Math.max(0, jetzt - letzteZeit));\r\n                    letzteZeit = jetzt;\r\n                    if (liegtAuf()) {\r\n                        sperrUhr += dt;\r\n                        if (sperrUhr >= SPERRZEIT) festsetzen();\r\n                    } else {\r\n                        fallZaehler += dt;\r\n                        if (fallZaehler >= fallTakt) { fallZaehler -= fallTakt; einsRunter(); }\r\n                    }\r\n                    if (zustand === 'laeuft') zeichnen();\r\n                    schleife = zustand === 'laeuft' ? requestAnimationFrame(takt) : null;\r\n                };\r\n                schleife = requestAnimationFrame(takt);\r\n            }\r\n\r\n            function schleifeStopp() {\r\n                if (schleife) cancelAnimationFrame(schleife);\r\n                schleife = null;\r\n            }\r\n\r\n            \/\/ Tab verlassen = Pause (vorher lief die Musik im Hintergrund weiter)\r\n            document.addEventListener('visibilitychange', () => { if (document.hidden) pause(); });\r\n\r\n            \/\/ \u2500\u2500 Zeichnen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            function block(c, x, y, g, farbe) {\r\n                c.fillStyle = farbe;\r\n                c.fillRect(x + 1, y + 1, g - 2, g - 2);\r\n                c.fillStyle = 'rgba(255,255,255,0.28)';\r\n                c.fillRect(x + 1, y + 1, g - 2, Math.max(2, Math.round(g \/ 7)));\r\n            }\r\n\r\n            function zeichnen() {\r\n                const g = zelle;\r\n                ctx.clearRect(0, 0, breite, hoehe);\r\n                ctx.fillStyle = '#ffffff';\r\n                ctx.fillRect(0, 0, breite, hoehe);\r\n\r\n                ctx.strokeStyle = cfg.rasterFarbe;\r\n                ctx.lineWidth = 1;\r\n                ctx.beginPath();\r\n                for (let s = 1; s < SPALTEN; s++) { ctx.moveTo(s * g + 0.5, 0); ctx.lineTo(s * g + 0.5, hoehe); }\r\n                for (let z = 1; z < ZEILEN; z++) { ctx.moveTo(0, z * g + 0.5); ctx.lineTo(breite, z * g + 0.5); }\r\n                ctx.stroke();\r\n\r\n                for (let z = 0; z < ZEILEN; z++) {\r\n                    for (let s = 0; s < SPALTEN; s++) {\r\n                        if (feld[z] && feld[z][s]) block(ctx, s * g, z * g, g, FARBEN[feld[z][s]]);\r\n                    }\r\n                }\r\n\r\n                if (stueck && (zustand === 'laeuft' || zustand === 'pause')) {\r\n                    \/\/ Schatten: wo das Stueck landen wird\r\n                    const lz = landeZeile();\r\n                    ctx.strokeStyle = FARBEN[stueck.name];\r\n                    ctx.lineWidth = 2;\r\n                    ctx.globalAlpha = 0.55;\r\n                    stueck.matrix.forEach((r, ri) => r.forEach((v, ci) => {\r\n                        const z = lz + ri;\r\n                        if (v && z >= 0) ctx.strokeRect((stueck.spalte + ci) * g + 2, z * g + 2, g - 4, g - 4);\r\n                    }));\r\n                    ctx.globalAlpha = 1;\r\n                    stueck.matrix.forEach((r, ri) => r.forEach((v, ci) => {\r\n                        const z = stueck.zeile + ri;\r\n                        if (v && z >= 0) block(ctx, (stueck.spalte + ci) * g, z * g, g, FARBEN[stueck.name]);\r\n                    }));\r\n                }\r\n\r\n                const hinweis = { bereit: 'Start dr\u00fccken', pause: 'Pause', ende: 'Spiel vorbei' }[zustand];\r\n                if (hinweis) {\r\n                    ctx.fillStyle = 'rgba(0,0,0,0.62)';\r\n                    ctx.fillRect(0, hoehe \/ 2 - g * 1.2, breite, g * 2.4);\r\n                    ctx.fillStyle = '#ffffff';\r\n                    ctx.font = `600 ${Math.max(15, Math.round(g * 0.75))}px ${cfg.schrift}`;\r\n                    ctx.textAlign = 'center';\r\n                    ctx.textBaseline = 'middle';\r\n                    ctx.fillText(hinweis, breite \/ 2, hoehe \/ 2 + 1);\r\n                }\r\n            }\r\n\r\n            function vorschauZeichnen() {\r\n                const w = vorschau.clientWidth || 96, h = vorschau.clientHeight || 64;\r\n                const dpr = Math.min(window.devicePixelRatio || 1, 3);\r\n                if (vorschau.width !== Math.round(w * dpr)) { vorschau.width = Math.round(w * dpr); vorschau.height = Math.round(h * dpr); }\r\n                vCtx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n                vCtx.clearRect(0, 0, w, h);\r\n                if (!naechstes || zustand === 'bereit') return;\r\n                \/\/ Auf die belegten Zellen zuschneiden, damit das Stueck mittig steht\r\n                const m = naechstes.matrix;\r\n                const zeilen = m.map((r, i) => r.some(Boolean) ? i : -1).filter(i => i >= 0);\r\n                const spalten = m[0].map((_, j) => m.some(r => r[j]) ? j : -1).filter(j => j >= 0);\r\n                const hz = zeilen.length, bs = spalten.length;\r\n                const g = Math.floor(Math.min((w - 8) \/ 4, (h - 8) \/ 2));\r\n                const ox = Math.round((w - bs * g) \/ 2), oy = Math.round((h - hz * g) \/ 2);\r\n                zeilen.forEach((ri, a) => spalten.forEach((ci, b) => {\r\n                    if (m[ri][ci]) block(vCtx, ox + b * g, oy + a * g, g, FARBEN[naechstes.name]);\r\n                }));\r\n            }\r\n\r\n            \/\/ \u2500\u2500 Groesse: Feld und Steuerung passen zusammen ins Fenster \u2500\u2500\u2500\u2500\u2500\u2500\r\n            \/\/ innerHeight wird nur bei Breitenaenderung gelesen \u2014 die mobile\r\n            \/\/ Adressleiste loest so keinen Neuaufbau aus.\r\n            let letzteBreite = 0;\r\n            function groesseAnpassen(erzwingen) {\r\n                const b = bereich.clientWidth;\r\n                if (!b || (!erzwingen && b === letzteBreite)) return;\r\n                letzteBreite = b;\r\n                const seite = el('seite');\r\n                const nebenan = seite.getBoundingClientRect().top < huelle.getBoundingClientRect().bottom;\r\n                const abstand = parseFloat(getComputedStyle(bereich).columnGap) || 0;\r\n                const freiW = b - (nebenan ? seite.getBoundingClientRect().width + abstand : 0);\r\n                const freiH = window.innerHeight - cfg.kopfHoehe() - unterhalb() - 24;\r\n                const g = Math.max(14, Math.min(32, Math.floor(Math.min(freiW \/ SPALTEN, freiH \/ ZEILEN))));\r\n                zelle = g;\r\n                breite = g * SPALTEN;\r\n                hoehe = g * ZEILEN;\r\n                const dpr = Math.min(window.devicePixelRatio || 1, 3);\r\n                brett.style.width = breite + 'px';\r\n                brett.style.height = hoehe + 'px';\r\n                brett.width = Math.round(breite * dpr);\r\n                brett.height = Math.round(hoehe * dpr);\r\n                ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n                zeichnen();\r\n                vorschauZeichnen();\r\n            }\r\n\r\n            \/\/ Hoehe der Bedienelemente unter dem Feld (Touch-Tasten), die beim\r\n            \/\/ Spielen zusammen mit dem Feld sichtbar sein muessen.\r\n            function unterhalb() {\r\n                const unten = huelle.getBoundingClientRect().bottom;\r\n                let max = unten;\r\n                cfg.unterDemFeld.forEach(s => {\r\n                    const e = el(s);\r\n                    if (!e || !e.offsetParent) return;\r\n                    const r = e.getBoundingClientRect();\r\n                    if (r.top >= unten - 1) max = Math.max(max, r.bottom);\r\n                });\r\n                return max - unten;\r\n            }\r\n\r\n            function feldSichtbarMachen() {\r\n                const kopf = cfg.kopfHoehe();\r\n                const r = huelle.getBoundingClientRect();\r\n                const unten = r.bottom + unterhalb();\r\n                if (r.top >= kopf + 4 && unten <= window.innerHeight) return;\r\n                window.scrollTo({ top: window.scrollY + r.top - kopf - 10, behavior: BEWEGUNG_REDUZIERT ? 'auto' : 'smooth' });\r\n            }\r\n\r\n            if (window.ResizeObserver) new ResizeObserver(() => groesseAnpassen()).observe(bereich);\r\n            else window.addEventListener('resize', () => groesseAnpassen());\r\n\r\n            \/\/ \u2500\u2500 Anzeigen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            function werteAnzeigen() {\r\n                punkteEl.textContent = punkte;\r\n                linienEl.textContent = linien;\r\n                levelEl.textContent = level;\r\n                bestEl.textContent = bestwert();\r\n            }\r\n\r\n            function knopfText() {\r\n                btnStart.textContent = { laeuft: 'Pause', pause: 'Weiter' }[zustand] || 'Start';\r\n            }\r\n\r\n            function sr(text) { if (srEl) srEl.textContent = text; }\r\n\r\n            \/\/ \u2500\u2500 Bestwert \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            function bestwert() {\r\n                try { return Number(localStorage.getItem(cfg.speicher.best)) || 0; } catch (e) { return 0; }\r\n            }\r\n            function bestwertSpeichern(p) {\r\n                try { localStorage.setItem(cfg.speicher.best, String(p)); } catch (e) {}\r\n            }\r\n\r\n            \/\/ \u2500\u2500 Musik: startet still, Wahl wird gespeichert \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            let audio = null;\r\n            let musikAn = false;\r\n            try {\r\n                const m = JSON.parse(localStorage.getItem(cfg.speicher.musik) || '{}');\r\n                musikAn = m.an === true;\r\n                if (m.stil && cfg.musik[m.stil]) musikStil.value = m.stil;\r\n            } catch (e) {}\r\n\r\n            function musikSpeichern() {\r\n                try { localStorage.setItem(cfg.speicher.musik, JSON.stringify({ an: musikAn, stil: musikStil.value })); } catch (e) {}\r\n            }\r\n\r\n            function musikKnopf() {\r\n                btnMusik.textContent = musikAn ? 'Musik: an' : 'Musik: aus';\r\n                btnMusik.setAttribute('aria-pressed', musikAn ? 'true' : 'false');\r\n            }\r\n\r\n            \/\/ Musik spielt nur, solange das Spiel laeuft. Die Datei wird erst\r\n            \/\/ geladen, wenn jemand die Musik einschaltet.\r\n            function musikAnpassen() {\r\n                const soll = musikAn && zustand === 'laeuft';\r\n                if (soll) {\r\n                    const quelle = cfg.musik[musikStil.value] || cfg.musik.Classic;\r\n                    if (!audio) { audio = new Audio(); audio.loop = true; audio.volume = 0.5; audio.preload = 'none'; }\r\n                    if (audio.src !== quelle) audio.src = quelle;\r\n                    const p = audio.play();\r\n                    if (p && p.catch) p.catch(() => {});\r\n                } else if (audio) {\r\n                    audio.pause();\r\n                }\r\n            }\r\n\r\n            btnMusik.addEventListener('click', e => {\r\n                if (e.detail > 0) btnMusik.blur();\r\n                musikAn = !musikAn;\r\n                musikKnopf();\r\n                musikSpeichern();\r\n                musikAnpassen();\r\n            });\r\n            musikStil.addEventListener('change', () => { musikSpeichern(); musikAnpassen(); });\r\n\r\n            \/\/ \u2500\u2500 Bedienung \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            regler.addEventListener('input', () => { reglerWert.textContent = regler.value; });\r\n\r\n            \/\/ Nach Mausklick Fokus abgeben: sonst loest die Leertaste (Fallen)\r\n            \/\/ in manchen Browsern zusaetzlich den Knopf aus.\r\n            function klick(btn, fn) {\r\n                btn.addEventListener('click', e => { if (e.detail > 0) btn.blur(); fn(); });\r\n            }\r\n            klick(btnStart, startPause);\r\n            klick(btnNeu, neuesSpiel);\r\n            klick(el('nochmals'), neuesSpiel);\r\n\r\n            const TASTEN = {\r\n                ArrowLeft:  () => schieben(-1),\r\n                ArrowRight: () => schieben(1),\r\n                ArrowUp:    drehenVersuchen,\r\n                ArrowDown:  weicherFall,\r\n                ' ':        harterFall\r\n            };\r\n            document.addEventListener('keydown', e => {\r\n                if (cfg.modalOffen()) return;\r\n                if (e.key === 'p' || e.key === 'P' || (e.key === 'Escape' && zustand === 'laeuft')) {\r\n                    if (zustand === 'laeuft' || zustand === 'pause') { e.preventDefault(); startPause(); }\r\n                    return;\r\n                }\r\n                if (zustand !== 'laeuft' || !TASTEN[e.key]) return;\r\n                e.preventDefault();\r\n                if (e.key === ' ' && e.repeat) return;   \/\/ Leertaste halten: nur ein Stueck\r\n                TASTEN[e.key]();\r\n            });\r\n            document.addEventListener('keyup', e => { if (e.key === ' ' && zustand === 'laeuft') e.preventDefault(); });\r\n\r\n            \/\/ Touch-Tasten: sofort beim Beruehren, Wiederholung beim Halten.\r\n            \/\/ Klicks per Tastatur (detail 0) loesen einmal aus.\r\n            function touchTaste(name, fn, wiederholen) {\r\n                const btn = el(name);\r\n                if (!btn) return;\r\n                let t1 = null, t2 = null;\r\n                const stopp = () => { clearTimeout(t1); clearInterval(t2); t1 = t2 = null; };\r\n                btn.addEventListener('pointerdown', e => {\r\n                    if (e.button !== 0) return;\r\n                    e.preventDefault();\r\n                    stopp();\r\n                    fn();\r\n                    if (wiederholen) t1 = setTimeout(() => { t2 = setInterval(() => { if (zustand === 'laeuft') fn(); else stopp(); }, WDH_TAKT); }, WDH_VERZOEGERUNG);\r\n                });\r\n                ['pointerup', 'pointercancel', 'pointerleave'].forEach(t => btn.addEventListener(t, stopp));\r\n                btn.addEventListener('click', e => { if (e.detail === 0) fn(); });\r\n                btn.addEventListener('contextmenu', e => e.preventDefault());\r\n            }\r\n            touchTaste('links',  () => schieben(-1), true);\r\n            touchTaste('rechts', () => schieben(1), true);\r\n            touchTaste('runter', weicherFall, true);\r\n            touchTaste('drehen', drehenVersuchen, false);\r\n            touchTaste('fallen', harterFall, false);\r\n\r\n            \/\/ \u2500\u2500 Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            leeresFeld();\r\n            musikKnopf();\r\n            werteAnzeigen();\r\n            knopfText();\r\n            groesseAnpassen(true);\r\n\r\n            \/\/ Schnittstelle fuer Tests\r\n            return {\r\n                get zustand() { return zustand; },\r\n                get stueck() { return stueck; },\r\n                get feld() { return feld; },\r\n                get punkte() { return punkte; },\r\n                get level() { return level; },\r\n                get linien() { return linien; },\r\n                get zelle() { return zelle; },\r\n                festsetzenTest: () => festsetzen(),\r\n                feldSetzen: f => { feld = f; zeichnen(); },\r\n                stueckSetzen: name => { stueck = erzeuge(name); tiefsteZeile = stueck.zeile; zeichnen(); }\r\n            };\r\n        }\r\n\r\n        \/\/ Hoehe eines fixierten\/klebenden Seitenkopfs (Theme), gemessen statt\r\n        \/\/ geraten: oberstes Element in der Fenstermitte und seine Vorfahren.\r\n        function kopfHoehe() {\r\n            let el = document.elementFromPoint(window.innerWidth \/ 2, 2);\r\n            while (el && el !== document.body && el !== document.documentElement) {\r\n                const pos = getComputedStyle(el).position;\r\n                if (pos === 'fixed' || pos === 'sticky') {\r\n                    const r = el.getBoundingClientRect();\r\n                    return r.top <= 2 ? Math.max(0, r.bottom) : 0;\r\n                }\r\n                el = el.parentElement;\r\n            }\r\n            return 0;\r\n        }\r\n\r\n        \/\/ \u2500\u2500 Dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n        function modalOeffnen(name, fokus) {\r\n            const m = document.getElementById('fttet-' + name);\r\n            if (!m) return;\r\n            m.classList.add('active');\r\n            document.body.style.overflow = 'hidden';\r\n            const ziel = fokus && document.getElementById('fttet-' + fokus);\r\n            if (ziel) ziel.focus();\r\n        }\r\n        function modalSchliessen(name) {\r\n            const m = document.getElementById('fttet-' + name);\r\n            if (!m || !m.classList.contains('active')) return;\r\n            m.classList.remove('active');\r\n            document.body.style.overflow = '';\r\n        }\r\n        function modalOffen() { return !!root.querySelector('.fttet-modal.active'); }\r\n\r\n        root.querySelectorAll('.fttet-modal').forEach(m => {\r\n            const zu = () => modalSchliessen(m.id.replace('fttet-', ''));\r\n            m.querySelector('.fttet-modal-schliessen').addEventListener('click', zu);\r\n            m.querySelector('.fttet-modal-hintergrund').addEventListener('click', zu);\r\n        });\r\n        document.addEventListener('keydown', e => {\r\n            if (e.key === 'Escape' && modalOffen()) { e.preventDefault(); modalSchliessen('modal-ende'); }\r\n        });\r\n\r\n        \/** Spielereignis an GTM (dataLayer). Nur Spieldaten, keine Personendaten. *\/\r\n        function ftEvent(daten) {\r\n            try {\r\n                window.dataLayer = window.dataLayer || [];\r\n                window.dataLayer.push(Object.assign({ spiel_seite: 'fahrtauglich' }, daten));\r\n            } catch (e) {}\r\n        }\r\n\r\n        root.__tetris = tetrisMotor({\r\n            prefix: 'fttet-',\r\n            farben: { I: '#06B6D4', O: '#FFBF00', T: '#A855F7', S: '#16A34A', Z: '#EF4444', J: '#2563EB', L: '#F97316' },\r\n            rasterFarbe: '#E9EDF1',\r\n            schrift: 'Poppins, sans-serif',\r\n            musik: {\r\n                Classic: 'https:\/\/fahrtauglich.ch\/wp-content\/uploads\/2024\/10\/Classic-Tetris.mp3',\r\n                Jazz:    'https:\/\/fahrtauglich.ch\/wp-content\/uploads\/2024\/10\/Jazz-Tetris.mp3',\r\n                Rock:    'https:\/\/fahrtauglich.ch\/wp-content\/uploads\/2024\/10\/Rock-Tetris.mp3'\r\n            },\r\n            speicher: { best: 'ft_tetris_best_v1', musik: 'ft_tetris_musik_v1' },\r\n            unterDemFeld: ['touch'],\r\n            kopfHoehe, modalOeffnen, modalSchliessen, modalOffen,\r\n            ereignis: ftEvent\r\n        });\r\n\r\n        try {\r\n            if (!localStorage.getItem('ft_tetris_seen')) {\r\n                document.getElementById('fttet-anleitung').open = true;\r\n                localStorage.setItem('ft_tetris_seen', '1');\r\n            }\r\n        } catch (e) {}\r\n    }\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Erleben Sie Tetris: Das beliebte Spiel zur F\u00f6rderung von Konzentration und r\u00e4umlichem Denken.<\/p>","protected":false},"author":1,"featured_media":0,"parent":1467,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"content-type":"","iawp_total_views":12149,"footnotes":""},"class_list":["post-3635","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Tetris: Spielen Sie den Spieleklassiker gratis<\/title>\n<meta name=\"description\" content=\"Tetris kostenlos online: Das Klassikerspiel trainiert Konzentration und r\u00e4umliches Denken - f\u00fcr Mobile und Desktop.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fahrtauglich.ch\/fr\/praxisportal\/tetris\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tetris: Spielen Sie den Spieleklassiker gratis\" \/>\n<meta property=\"og:description\" content=\"Tetris kostenlos online: Das Klassikerspiel trainiert Konzentration und r\u00e4umliches Denken - f\u00fcr Mobile und Desktop.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fahrtauglich.ch\/fr\/praxisportal\/tetris\/\" \/>\n<meta property=\"og:site_name\" content=\"Fahrtauglich\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-12T11:26:30+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data1\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/praxisportal\\\/tetris\\\/\",\"url\":\"https:\\\/\\\/fahrtauglich.ch\\\/praxisportal\\\/tetris\\\/\",\"name\":\"Tetris: Spielen Sie den Spieleklassiker gratis\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/#website\"},\"datePublished\":\"2024-10-15T15:29:06+00:00\",\"dateModified\":\"2026-10-12T11:26:30+00:00\",\"description\":\"Tetris kostenlos online: Das Klassikerspiel trainiert Konzentration und r\u00e4umliches Denken - f\u00fcr Mobile und Desktop.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/praxisportal\\\/tetris\\\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/fahrtauglich.ch\\\/praxisportal\\\/tetris\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/praxisportal\\\/tetris\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/fahrtauglich.ch\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Praxisportal\",\"item\":\"https:\\\/\\\/fahrtauglich.ch\\\/praxisportal\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Tetris\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/#website\",\"url\":\"https:\\\/\\\/fahrtauglich.ch\\\/\",\"name\":\"Fahrtauglich\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/fahrtauglich.ch\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/#organization\",\"name\":\"Fahrtauglich\",\"url\":\"https:\\\/\\\/fahrtauglich.ch\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/fahrtauglich.ch\\\/wp-content\\\/uploads\\\/2024\\\/08\\\/cropped-Logo-2.jpg\",\"contentUrl\":\"https:\\\/\\\/fahrtauglich.ch\\\/wp-content\\\/uploads\\\/2024\\\/08\\\/cropped-Logo-2.jpg\",\"width\":307,\"height\":188,\"caption\":\"Fahrtauglich\"},\"image\":{\"@id\":\"https:\\\/\\\/fahrtauglich.ch\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Tetris: Spielen Sie den Spieleklassiker gratis","description":"Tetris kostenlos online: Das Klassikerspiel trainiert Konzentration und r\u00e4umliches Denken - f\u00fcr Mobile und Desktop.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fahrtauglich.ch\/fr\/praxisportal\/tetris\/","og_locale":"fr_FR","og_type":"article","og_title":"Tetris: Spielen Sie den Spieleklassiker gratis","og_description":"Tetris kostenlos online: Das Klassikerspiel trainiert Konzentration und r\u00e4umliches Denken - f\u00fcr Mobile und Desktop.","og_url":"https:\/\/fahrtauglich.ch\/fr\/praxisportal\/tetris\/","og_site_name":"Fahrtauglich","article_modified_time":"2026-10-12T11:26:30+00:00","twitter_card":"summary_large_image","twitter_misc":{"Dur\u00e9e de lecture estim\u00e9e":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/fahrtauglich.ch\/praxisportal\/tetris\/","url":"https:\/\/fahrtauglich.ch\/praxisportal\/tetris\/","name":"Tetris: Spielen Sie den Spieleklassiker gratis","isPartOf":{"@id":"https:\/\/fahrtauglich.ch\/#website"},"datePublished":"2024-10-15T15:29:06+00:00","dateModified":"2026-10-12T11:26:30+00:00","description":"Tetris kostenlos online: Das Klassikerspiel trainiert Konzentration und r\u00e4umliches Denken - f\u00fcr Mobile und Desktop.","breadcrumb":{"@id":"https:\/\/fahrtauglich.ch\/praxisportal\/tetris\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fahrtauglich.ch\/praxisportal\/tetris\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fahrtauglich.ch\/praxisportal\/tetris\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/fahrtauglich.ch\/"},{"@type":"ListItem","position":2,"name":"Praxisportal","item":"https:\/\/fahrtauglich.ch\/praxisportal\/"},{"@type":"ListItem","position":3,"name":"Tetris"}]},{"@type":"WebSite","@id":"https:\/\/fahrtauglich.ch\/#website","url":"https:\/\/fahrtauglich.ch\/","name":"Fahrtauglich","description":"","publisher":{"@id":"https:\/\/fahrtauglich.ch\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fahrtauglich.ch\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"fr-FR"},{"@type":"Organization","@id":"https:\/\/fahrtauglich.ch\/#organization","name":"Fahrtauglich","url":"https:\/\/fahrtauglich.ch\/","logo":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/fahrtauglich.ch\/#\/schema\/logo\/image\/","url":"https:\/\/fahrtauglich.ch\/wp-content\/uploads\/2024\/08\/cropped-Logo-2.jpg","contentUrl":"https:\/\/fahrtauglich.ch\/wp-content\/uploads\/2024\/08\/cropped-Logo-2.jpg","width":307,"height":188,"caption":"Fahrtauglich"},"image":{"@id":"https:\/\/fahrtauglich.ch\/#\/schema\/logo\/image\/"}}]}},"rttpg_featured_image_url":null,"rttpg_author":{"display_name":"fahrtauglich.ch","author_link":"https:\/\/fahrtauglich.ch\/fr\/blog\/author\/mintcream-quetzal-259960-hostingersite-com\/"},"rttpg_comment":0,"rttpg_category":null,"rttpg_excerpt":"Erleben Sie Tetris: Das beliebte Spiel zur F\u00f6rderung von Konzentration und r\u00e4umlichem Denken.","_links":{"self":[{"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/pages\/3635","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/comments?post=3635"}],"version-history":[{"count":92,"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/pages\/3635\/revisions"}],"predecessor-version":[{"id":8584,"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/pages\/3635\/revisions\/8584"}],"up":[{"embeddable":true,"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/pages\/1467"}],"wp:attachment":[{"href":"https:\/\/fahrtauglich.ch\/fr\/wp-json\/wp\/v2\/media?parent=3635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}