{"id":56,"date":"2026-09-03T19:44:01","date_gmt":"2026-09-03T19:44:01","guid":{"rendered":"https:\/\/itdd.au.dk\/the-house\/the-enterance\/"},"modified":"2026-10-22T18:34:40","modified_gmt":"2026-10-22T18:34:40","slug":"frontdoor","status":"publish","type":"page","link":"https:\/\/itdd.au.dk\/the-house\/frontdoor\/","title":{"rendered":"Front Door"},"content":{"rendered":"\n<p class=\"has-text-align-center wp-block-paragraph\"><mark style=\"background-color:#050505\" class=\"has-inline-color has-base-color\">On the doorstep lies an old key<\/mark><\/p>\n\n\n\n<pre class=\"wp-block-verse has-text-align-center\"><mark style=\"background-color:#050505\" class=\"has-inline-color has-base-color\">The key is here just for you<\/mark><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-base-color\"><br><\/mark>                                                   <br>                                                  <\/pre>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-35f06ea7 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/itdd.au.dk\/the-house\/foyer\/\">Use the key to enter the house<\/a><\/div>\n<\/div>\n\n\n<style>\nbody {<br \/>\n  background-image: url('https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Front-Door-scaled.jpg');<br \/>\n}<br \/>\n<\/style>\n\n\n<!-- Horror Google Fonts -->\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Special+Elite&#038;display=swap\" rel=\"stylesheet\">\n\n<style>\n\/* =======================================================\n   1. GENNEMSIGTIGT OMR\u00c5DE (Blender 100% ind i baggrunden)\n   ======================================================= *\/\n.horror-puzzle-stage {\n    position: relative;\n    width: 100%;\n    max-width: 820px;\n    height: 440px;\n    margin: 15px auto;\n    background: transparent;\n    border: none;\n    box-shadow: none;\n    user-select: none;\n    touch-action: none;\n    font-family: 'Special Elite', monospace;\n    box-sizing: border-box;\n}\n\n.puzzle-whisper {\n    position: absolute;\n    top: 10px;\n    left: 0;\n    width: 100%;\n    text-align: center;\n    color: #cc3333;\n    font-size: 13px;\n    letter-spacing: 3px;\n    text-transform: uppercase;\n    text-shadow: 0 0 10px #000, 0 0 20px #000, 0 0 8px rgba(255, 0, 0, 0.7);\n    pointer-events: none;\n    z-index: 5;\n    animation: textFlicker 3.2s infinite;\n}\n\n@keyframes textFlicker {\n    0%, 100% { opacity: 0.9; }\n    50% { opacity: 0.35; }\n    52% { opacity: 1; }\n    54% { opacity: 0.25; }\n}\n\n\/* =======================================================\n   2. N\u00d8GLEHULLET & DET SKJULTE KODEORD\n   ======================================================= *\/\n.keyhole-zone {\n    position: absolute;\n    top: 50%;\n    right: 22%;\n    transform: translateY(-50%);\n    width: 90px;\n    height: 120px;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    z-index: 2;\n}\n\n\/* KODEORDET DER KUN VISES N\u00c5R N\u00d8GLEN ER LIGE OVER *\/\n.revealed-passcode {\n    position: absolute;\n    top: -28px;\n    left: 50%;\n    transform: translateX(-50%) translateY(5px) scale(0.9);\n    font-family: 'Special Elite', 'Courier New', monospace;\n    font-size: 24px;\n    font-weight: bold;\n    color: #ff2222;\n    text-transform: lowercase;\n    letter-spacing: 4px;\n    text-shadow: 0 0 10px #ff0000, 0 0 20px #990000, 0 0 4px #000;\n    white-space: nowrap;\n    opacity: 0;\n    pointer-events: none;\n    transition: opacity 0.2s ease, transform 0.2s ease;\n    z-index: 20;\n}\n\n\/* N\u00c5R N\u00d8GLEN ER OVER HULLET *\/\n.keyhole-zone.revealing .revealed-passcode {\n    opacity: 1;\n    transform: translateX(-50%) translateY(0) scale(1);\n    animation: ghostlyFlicker 1.5s infinite;\n}\n\n@keyframes ghostlyFlicker {\n    0%, 100% { opacity: 1; filter: drop-shadow(0 0 8px #ff0000); }\n    45% { opacity: 0.7; }\n    50% { opacity: 1; filter: drop-shadow(0 0 14px #ff0000); }\n    75% { opacity: 0.85; }\n}\n\n.escutcheon-plate {\n    width: 70px;\n    height: 95px;\n    background: rgba(12, 2, 2, 0.75);\n    backdrop-filter: blur(4px);\n    border: 2px solid #5a0808;\n    border-radius: 8px;\n    box-shadow: 0 10px 30px rgba(0,0,0,0.9), 0 0 15px rgba(0,0,0,0.8);\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    position: relative;\n    transition: all 0.25s ease;\n}\n\n.keyhole-zone.revealing .escutcheon-plate {\n    border-color: #ff1a1a;\n    box-shadow: 0 0 30px rgba(255, 26, 26, 0.9), inset 0 0 18px rgba(255, 0, 0, 0.6);\n    animation: shudder 0.12s infinite;\n}\n\n@keyframes shudder {\n    0% { transform: translate(1px, 1px); }\n    50% { transform: translate(-1px, -1px); }\n    100% { transform: translate(1px, -1px); }\n}\n\n.keyhole-cutout {\n    position: relative;\n    width: 18px;\n    height: 18px;\n    background: #000;\n    border-radius: 50%;\n    box-shadow: inset 0 0 6px #ff0000, 0 0 8px rgba(255, 0, 0, 0.5);\n}\n.keyhole-cutout::after {\n    content: '';\n    position: absolute;\n    top: 11px;\n    left: 3px;\n    width: 12px;\n    height: 20px;\n    background: #000;\n    clip-path: polygon(15% 0%, 85% 0%, 100% 100%, 0% 100%);\n    box-shadow: inset 0 -3px 5px #ff0000;\n}\n\n.keyhole-label {\n    margin-top: 12px;\n    color: #aa3333;\n    font-size: 10px;\n    letter-spacing: 3px;\n    text-shadow: 0 2px 6px #000;\n    transition: color 0.3s;\n}\n.keyhole-zone.revealing .keyhole-label {\n    color: #ff3333;\n    text-shadow: 0 0 10px #ff0000;\n}\n\n\/* =======================================================\n   3. DEN SV\u00c6VENDE, BEV\u00c6GELIGE N\u00d8GLE\n   ======================================================= *\/\n.draggable-key {\n    position: absolute;\n    top: 42%;\n    left: 18%;\n    width: 85px;\n    height: 115px;\n    cursor: grab;\n    z-index: 10;\n    filter: drop-shadow(0 15px 25px rgba(0, 0, 0, 0.95)) drop-shadow(0 0 12px rgba(180, 0, 0, 0.5));\n}\n\n.draggable-key:active {\n    cursor: grabbing;\n}\n\n.draggable-key svg {\n    width: 100%;\n    height: 100%;\n    pointer-events: none;\n}\n<\/style>\n\n<div class=\"horror-puzzle-stage\" id=\"puzzle-stage\">\n    \n    <div class=\"puzzle-whisper\">\n        &#8220;Align the teeth with the dark void&#8230;&#8221;\n    <\/div>\n\n    <!-- N\u00d8GLEHULLET MED DET SV\u00c6VENDE KODEORD -->\n    <div class=\"keyhole-zone\" id=\"keyhole-target\">\n        <!-- DETTE ER KODEORDET DER KUN SES VED HOVER\/HOLD -->\n        <div class=\"revealed-passcode\">old key<\/div>\n\n        <div class=\"escutcheon-plate\">\n            <div class=\"keyhole-cutout\"><\/div>\n        <\/div>\n        <span class=\"keyhole-label\">LOCKED<\/span>\n    <\/div>\n\n    <!-- DEN FRIT BEV\u00c6GELIGE N\u00d8GLE -->\n    <div class=\"draggable-key\" id=\"player-key\">\n        <svg viewBox=\"0 0 100 130\">\n            <defs>\n                <linearGradient id=\"rusted-iron\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                    <stop offset=\"0%\" stop-color=\"#4a2a26\" \/>\n                    <stop offset=\"40%\" stop-color=\"#181313\" \/>\n                    <stop offset=\"75%\" stop-color=\"#5a0a0a\" \/>\n                    <stop offset=\"100%\" stop-color=\"#0a0505\" \/>\n                <\/linearGradient>\n            <\/defs>\n            <path fill=\"url(#rusted-iron)\" stroke=\"#ff2a2a\" stroke-width=\"1.2\" d=\"\n                M 50 12 \n                C 30 12, 16 28, 16 46 \n                C 16 62, 30 74, 44 78 \n                L 44 116 \n                L 62 116 \n                L 62 108 \n                L 54 108 \n                L 54 98 \n                L 64 98 \n                L 64 88 \n                L 54 88 \n                L 54 78 \n                C 68 74, 82 62, 82 46 \n                C 82 28, 68 12, 50 12 Z\n                M 36 40 \n                A 7 7 0 1 1 36 54 \n                A 7 7 0 1 1 36 40 Z\n                M 64 40 \n                A 7 7 0 1 1 64 54 \n                A 7 7 0 1 1 64 40 Z\n                M 50 56 \n                L 45 68 \n                L 55 68 Z\" \/>\n        <\/svg>\n    <\/div>\n\n<\/div>\n\n<script>\n(function() {\n    const stage = document.getElementById('puzzle-stage');\n    const key = document.getElementById('player-key');\n    const target = document.getElementById('keyhole-target');\n\n    let isDragging = false;\n    let isRevealing = false;\n    let offsetX = 0;\n    let offsetY = 0;\n\n    \/\/ Subtil gyser-lyd n\u00e5r koden dukker frem\n    let audioCtx = null;\n    function playWhisperTone() {\n        if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();\n        if (audioCtx.state === 'suspended') audioCtx.resume();\n        const t = audioCtx.currentTime;\n\n        const osc = audioCtx.createOscillator();\n        const gain = audioCtx.createGain();\n        osc.type = 'sine';\n        osc.frequency.setValueAtTime(120, t);\n        osc.frequency.exponentialRampToValueAtTime(75, t + 0.4);\n\n        gain.gain.setValueAtTime(0.001, t);\n        gain.gain.linearRampToValueAtTime(0.18, t + 0.08);\n        gain.gain.exponentialRampToValueAtTime(0.001, t + 0.4);\n\n        osc.connect(gain);\n        gain.connect(audioCtx.destination);\n        osc.start(t);\n        osc.stop(t + 0.4);\n    }\n\n    key.addEventListener('pointerdown', (e) => {\n        isDragging = true;\n        key.setPointerCapture(e.pointerId);\n\n        const keyRect = key.getBoundingClientRect();\n        offsetX = e.clientX - keyRect.left;\n        offsetY = e.clientY - keyRect.top;\n    });\n\n    window.addEventListener('pointermove', (e) => {\n        if (!isDragging) return;\n\n        const stageRect = stage.getBoundingClientRect();\n        let newX = e.clientX - stageRect.left - offsetX;\n        let newY = e.clientY - stageRect.top - offsetY;\n\n        newX = Math.max(0, Math.min(newX, stageRect.width - key.offsetWidth));\n        newY = Math.max(0, Math.min(newY, stageRect.height - key.offsetHeight));\n\n        key.style.left = newX + 'px';\n        key.style.top = newY + 'px';\n\n        checkProximity();\n    });\n\n    window.addEventListener('pointerup', () => {\n        isDragging = false;\n    });\n\n    function checkProximity() {\n        const keyRect = key.getBoundingClientRect();\n        const targetRect = target.getBoundingClientRect();\n\n        \/\/ N\u00f8glens spids (den nederste del af n\u00f8glen)\n        const keyTipX = keyRect.left + (keyRect.width \/ 2);\n        const keyTipY = keyRect.top + (keyRect.height * 0.82);\n\n        \/\/ N\u00f8glehullets centrum\n        const targetCenterX = targetRect.left + (targetRect.width \/ 2);\n        const targetCenterY = targetRect.top + (targetRect.height \/ 2);\n\n        const distance = Math.hypot(keyTipX - targetCenterX, keyTipY - targetCenterY);\n\n        \/\/ Radius: Hvis n\u00f8glens spids er inden for 55px fra hullet, vises teksten\n        if (distance < 55) {\n            if (!isRevealing) {\n                isRevealing = true;\n                target.classList.add('revealing');\n                playWhisperTone();\n            }\n        } else {\n            if (isRevealing) {\n                isRevealing = false;\n                target.classList.remove('revealing');\n            }\n        }\n    }\n})();\n<\/script>\n\n\n<style>\nbody {<br \/>\n  background-image: url('https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Front-Door-scaled.jpg');<br \/>\n}<br \/>\n<\/style>\n<style>\nbody {<br \/>\n  background-image: url('https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Front-Door-scaled.jpg');<br \/>\n}<br \/>\n<\/style>\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-35f06ea7 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/itdd.au.dk\/the-house\/sample-page\/\">Explore the garden.<\/a><\/div>\n<\/div>\n\n\n\n<style>\nbody {\n  background-image: url('https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Front-Door-scaled.jpg');\n}\n<\/style>\n\n\n<style>\n.house-side-menu {\n  position: fixed;\n  left: 18px;\n  top: 50%;\n  transform: translateY(-50%);\n  display: flex;\n  flex-direction: column;\n  gap: 11px;\n  padding-left: 10px;\n  z-index: 999990;\n}\n\n.house-side-menu::before {\n  content: \"\";\n  position: absolute;\n  left: 0;\n  top: 0;\n  bottom: 0;\n  width: 2px;\n  background: rgba(255,255,255,0.35);\n}\n\n.house-menu-button {\n  position: relative;\n  width: 70.5px;\n  height: 70.5px;\n  padding: 0;\n  margin: 0;\n  border: 0;\n  background: transparent;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  z-index: 2;\n}\n\n.house-menu-button img {\n  width: 64.5px;\n  height: 64.5px;\n  object-fit: contain;\n  display: block;\n  transition: transform 0.18s ease, filter 0.18s ease;\n}\n\n.house-menu-button.house-ear img {\n  width: 60px;\n  height: 69px;\n}\n\n.house-menu-button.house-eye img {\n  width: 120px;\n  height: 136.5px;\n}\n\n.house-menu-button:hover img {\n  transform: translateX(5px) scale(1.08);\n  filter: brightness(1.08);\n}\n\n.house-menu-label {\n  position: absolute;\n  left: 53px;\n  top: 50%;\n  transform: translateY(-50%);\n  white-space: nowrap;\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: 14px;\n  line-height: 1;\n  color: #fff;\n  opacity: 0;\n  pointer-events: none;\n  transition: opacity 0.18s ease;\n}\n\n.house-menu-button:hover .house-menu-label {\n  opacity: 1;\n}\n\n\n\/* =========================================================\n   HELP POP-OUT\n   ========================================================= *\/\n\n.house-help-box {\n  position: fixed;\n  left: 82px;\n  top: 50%;\n  transform: translateY(-50%);\n\n  width: 240px;\n  max-width: calc(100vw - 110px);\n\n  padding: 18px 20px 20px;\n\n  background: rgba(245, 238, 216, 0.97);\n  color: #222;\n\n  border: 1px solid rgba(70, 55, 35, 0.45);\n  box-shadow: 0 5px 18px rgba(0,0,0,0.28);\n\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: 15px;\n  line-height: 1.45;\n\n  z-index: 999995;\n\n  display: none;\n}\n\n.house-help-box.is-open {\n  display: block;\n}\n\n.house-help-close {\n  position: absolute;\n  top: 5px;\n  right: 8px;\n\n  border: 0;\n  background: transparent;\n\n  color: #333;\n  font-family: Arial, sans-serif;\n  font-size: 20px;\n  line-height: 1;\n\n  padding: 0;\n  cursor: pointer;\n}\n\n.house-help-close:hover {\n  opacity: 0.55;\n}\n\n.house-help-text {\n  padding-right: 12px;\n}\n\n\n\/* =========================================================\n   PAPER NOTE BOXES\n   ========================================================= *\/\n\n.house-note-box,\n.house-notes-box {\n  position: fixed;\n\n  left: 82px;\n  top: 50%;\n  transform: translateY(-50%);\n\n  width: 285px;\n  max-width: calc(100vw - 115px);\n\n  background: rgba(245, 238, 216, 0.98);\n  color: #222;\n\n  border: 1px solid rgba(70, 55, 35, 0.45);\n  box-shadow: 0 5px 20px rgba(0,0,0,0.30);\n\n  font-family: Georgia, \"Times New Roman\", serif;\n\n  z-index: 999996;\n\n  display: none;\n}\n\n.house-note-box.is-open,\n.house-notes-box.is-open {\n  display: block;\n}\n\n.house-note-header,\n.house-notes-header {\n  position: relative;\n\n  padding: 13px 38px 10px 17px;\n\n  border-bottom: 1px solid rgba(70,55,35,0.25);\n\n  font-size: 16px;\n  line-height: 1.2;\n}\n\n.house-note-close,\n.house-notes-close {\n  position: absolute;\n\n  top: 5px;\n  right: 8px;\n\n  border: 0;\n  background: transparent;\n\n  color: #333;\n\n  font-family: Arial, sans-serif;\n  font-size: 20px;\n  line-height: 1;\n\n  padding: 0;\n  cursor: pointer;\n}\n\n.house-note-close:hover,\n.house-notes-close:hover {\n  opacity: 0.55;\n}\n\n\n\/* =========================================================\n   NOTE FORM\n   ========================================================= *\/\n\n.house-note-content {\n  padding: 15px 17px 17px;\n}\n\n.house-note-content label {\n  display: block;\n  margin-bottom: 5px;\n  font-size: 14px;\n}\n\n.house-note-content input,\n.house-note-content textarea {\n  box-sizing: border-box;\n\n  width: 100%;\n\n  border: 1px solid rgba(70,55,35,0.35);\n\n  background: rgba(255,255,255,0.72);\n\n  color: #222;\n\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: 14px;\n\n  padding: 8px;\n\n  outline: none;\n}\n\n.house-note-content input:focus,\n.house-note-content textarea:focus {\n  border-color: rgba(70,55,35,0.7);\n}\n\n.house-note-content textarea {\n  min-height: 105px;\n  resize: vertical;\n}\n\n.house-note-field {\n  margin-bottom: 12px;\n}\n\n.house-note-submit {\n  border: 1px solid rgba(70,55,35,0.45);\n\n  background: rgba(70,55,35,0.12);\n\n  color: #222;\n\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: 14px;\n\n  padding: 7px 13px;\n\n  cursor: pointer;\n}\n\n.house-note-submit:hover {\n  background: rgba(70,55,35,0.20);\n}\n\n.house-note-submit:disabled {\n  opacity: 0.55;\n  cursor: wait;\n}\n\n.house-note-status {\n  margin-top: 10px;\n\n  font-size: 13px;\n  line-height: 1.4;\n}\n\n.house-note-status.success {\n  color: #315b35;\n}\n\n.house-note-status.error {\n  color: #8a3028;\n}\n\n\n\/* =========================================================\n   PAPER NOTES LIST\n   ========================================================= *\/\n\n.house-notes-content {\n  padding: 14px 17px 17px;\n  max-height: 55vh;\n  overflow-y: auto;\n}\n\n.house-notes-intro {\n  margin-bottom: 12px;\n\n  font-size: 13px;\n  line-height: 1.4;\n\n  opacity: 0.75;\n}\n\n.house-single-note {\n  padding: 10px 0;\n\n  border-bottom: 1px solid rgba(70,55,35,0.22);\n}\n\n.house-single-note:last-child {\n  border-bottom: 0;\n}\n\n.house-single-note-author {\n  margin-bottom: 4px;\n\n  font-size: 13px;\n  font-weight: bold;\n}\n\n.house-single-note-date {\n  margin-bottom: 6px;\n\n  font-size: 11px;\n\n  opacity: 0.6;\n}\n\n.house-single-note-text {\n  font-size: 14px;\n  line-height: 1.45;\n\n  white-space: pre-wrap;\n}\n\n.house-no-notes {\n  font-size: 14px;\n  line-height: 1.45;\n  opacity: 0.75;\n}\n\n\n\/* =========================================================\n   ARTWORK\n   ========================================================= *\/\n\n#house-art-overlay {\n  position: fixed;\n  inset: 0;\n  z-index: 999999;\n\n  display: none;\n\n  align-items: center;\n  justify-content: center;\n\n  background: rgba(0,0,0,0.96);\n}\n\n#house-art-overlay img {\n  max-width: 96vw;\n  max-height: 94vh;\n\n  width: auto;\n  height: auto;\n\n  object-fit: contain;\n\n  display: block;\n}\n\n#house-art-close {\n  position: absolute;\n\n  top: 16px;\n  right: 22px;\n\n  border: 0;\n  background: transparent;\n\n  color: #fff;\n\n  font-family: Arial, sans-serif;\n  font-size: 32px;\n  line-height: 1;\n\n  cursor: pointer;\n\n  z-index: 2;\n}\n\n#house-art-close:hover {\n  opacity: 0.7;\n}\n\n\n\/* =========================================================\n   MOBILE\n   ========================================================= *\/\n\n@media (max-width: 700px) {\n\n  .house-side-menu {\n    left: 6px;\n    gap: 7px;\n    padding-left: 7px;\n  }\n\n  .house-menu-button {\n    width: 54px;\n    height: 54px;\n  }\n\n  .house-menu-button img {\n    width: 48px;\n    height: 48px;\n  }\n\n  .house-menu-button.house-ear img {\n    width: 45px;\n    height: 51px;\n  }\n\n  .house-menu-button.house-eye img {\n    width: 91.5px;\n    height: 105px;\n  }\n\n  .house-menu-label {\n    display: none;\n  }\n\n  .house-help-box,\n  .house-note-box,\n  .house-notes-box {\n    left: 51px;\n    top: 50%;\n\n    width: 220px;\n    max-width: calc(100vw - 65px);\n  }\n\n  .house-help-box {\n    padding: 16px 17px 18px;\n    font-size: 14px;\n  }\n\n  .house-note-header,\n  .house-notes-header {\n    font-size: 15px;\n  }\n\n  .house-note-content {\n    padding: 14px;\n  }\n\n  .house-notes-content {\n    max-height: 52vh;\n  }\n\n  #house-art-overlay img {\n    max-width: 94vw;\n    max-height: 90vh;\n  }\n\n  #house-art-close {\n    top: 10px;\n    right: 14px;\n    font-size: 28px;\n  }\n}\n<\/style>\n\n\n<!-- =========================================================\n     THE HOUSE SIDE MENU\n     ========================================================= -->\n\n<div id=\"house-side-menu\" class=\"house-side-menu\">\n\n  <button type=\"button\" class=\"house-menu-button house-story\" aria-label=\"Listen to the Story\">\n\n    <img decoding=\"async\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Antik-blomsterknap-100px.png\" alt=\"\">\n\n    <span class=\"house-menu-label\">\n      Listen to the Story\n    <\/span>\n\n  <\/button>\n\n\n  <button type=\"button\" class=\"house-menu-button house-eye\" aria-label=\"See the Art\">\n\n    <img decoding=\"async\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/eye_pendant-removebg-preview.png\" alt=\"\">\n\n    <span class=\"house-menu-label\">\n      See the Art\n    <\/span>\n\n  <\/button>\n\n\n  <button type=\"button\" class=\"house-menu-button house-ear\" aria-label=\"Listen to the House\">\n\n    <img decoding=\"async\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/ear-removebg-preview.png\" alt=\"\">\n\n    <span class=\"house-menu-label\">\n      Listen to the House\n    <\/span>\n\n  <\/button>\n\n\n  <button type=\"button\" class=\"house-menu-button house-help\" aria-label=\"Get Help\">\n\n    <img decoding=\"async\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/questionmark-removebg-preview-1.png\" alt=\"\">\n\n    <span class=\"house-menu-label\">\n      Get Help\n    <\/span>\n\n  <\/button>\n\n\n  <button type=\"button\" class=\"house-menu-button house-note\" aria-label=\"Leave a note behind\">\n\n    <img decoding=\"async\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Inkpot-removebg-preview.png\" alt=\"\">\n\n    <span class=\"house-menu-label\">\n      leave a note behind\n    <\/span>\n\n  <\/button>\n\n\n  <button type=\"button\" class=\"house-menu-button house-notes\" aria-label=\"Search for paper notes\">\n\n    <img decoding=\"async\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Louope-removebg-preview.png\" alt=\"\">\n\n    <span class=\"house-menu-label\">\n      search for paper notes\n    <\/span>\n\n  <\/button>\n\n<\/div>\n\n\n<!-- =========================================================\n     HELP\n     ========================================================= -->\n\n<div id=\"house-help-box\" class=\"house-help-box\" role=\"dialog\" aria-hidden=\"true\">\n\n  <button type=\"button\" id=\"house-help-close\" class=\"house-help-close\" aria-label=\"Close help\">\n    \u00d7\n  <\/button>\n\n  <div id=\"house-help-text\" class=\"house-help-text\">\n  <\/div>\n\n<\/div>\n\n\n<!-- =========================================================\n     LEAVE A NOTE\n     ========================================================= -->\n\n<div id=\"house-note-box\" class=\"house-note-box\" role=\"dialog\" aria-hidden=\"true\">\n\n  <div class=\"house-note-header\">\n\n    Leave a note behind\n\n    <button type=\"button\" id=\"house-note-close\" class=\"house-note-close\" aria-label=\"Close note box\">\n      \u00d7\n    <\/button>\n\n  <\/div>\n\n\n  <div class=\"house-note-content\">\n\n    <form id=\"house-note-form\">\n\n      <div class=\"house-note-field\">\n\n        <label for=\"house-note-author\">\n          Name\n        <\/label>\n\n        <input type=\"text\" id=\"house-note-author\" name=\"author\" maxlength=\"245\" autocomplete=\"name\" required=\"\">\n\n      <\/div>\n\n\n      <div class=\"house-note-field\">\n\n        <label for=\"house-note-email\">\n          Email\n        <\/label>\n\n        <input type=\"email\" id=\"house-note-email\" name=\"email\" autocomplete=\"email\" required=\"\">\n\n      <\/div>\n\n\n      <div class=\"house-note-field\">\n\n        <label for=\"house-note-comment\">\n          Note\n        <\/label>\n\n        <textarea id=\"house-note-comment\" name=\"comment\" required=\"\"><\/textarea>\n\n      <\/div>\n\n\n      <button type=\"submit\" id=\"house-note-submit\" class=\"house-note-submit\">\n        Leave note\n      <\/button>\n\n\n      <div id=\"house-note-status\" class=\"house-note-status\"><\/div>\n\n    <\/form>\n\n  <\/div>\n\n<\/div>\n\n\n<!-- =========================================================\n     SHOW PAPER NOTES\n     ========================================================= -->\n\n<div id=\"house-notes-box\" class=\"house-notes-box\" role=\"dialog\" aria-hidden=\"true\">\n\n  <div class=\"house-notes-header\">\n\n    Paper notes\n\n    <button type=\"button\" id=\"house-notes-close\" class=\"house-notes-close\" aria-label=\"Close paper notes\">\n      \u00d7\n    <\/button>\n\n  <\/div>\n\n\n  <div id=\"house-notes-content\" class=\"house-notes-content\">\n\n    <div class=\"house-notes-intro\">\n      Notes left behind on this page:\n    <\/div>\n\n    <div id=\"house-notes-list\">\n      Loading\u2026\n    <\/div>\n\n  <\/div>\n\n<\/div>\n\n\n<!-- =========================================================\n     ARTWORK\n     ========================================================= -->\n\n<div id=\"house-art-overlay\">\n\n  <button id=\"house-art-close\" type=\"button\" aria-label=\"Close artwork\">\n    \u00d7\n  <\/button>\n\n  <img decoding=\"async\" id=\"house-art-image\" src=\"\" alt=\"\">\n\n<\/div>\n\n\n<script>\n(function () {\n\n  function initHouseMenu() {\n\n    const menu =\n      document.getElementById(\"house-side-menu\");\n\n    if (!menu) {\n      return;\n    }\n\n    if (menu.dataset.houseMenuReady === \"true\") {\n      return;\n    }\n\n    menu.dataset.houseMenuReady = \"true\";\n\n\n    \/* =======================================================\n       PAGE SETTINGS\n       ======================================================= *\/\n\n    function getFiles() {\n\n      return window.houseMenuFiles || {\n\n        story: \"\",\n        art: \"\",\n        house: \"\",\n        help: \"\"\n\n      };\n\n    }\n\n\n    \/* =======================================================\n       CURRENT WORDPRESS PAGE \/ POST ID\n       ======================================================= *\/\n\n    let currentPostId = null;\n\n\n    \/*\n     * WordPress normally places one of these classes\n     * on the <body> element:\n     *\n     * page-id-123\n     * postid-123\n     *\n     * We support both.\n     *\/\n\n    function findPostIdFromBody() {\n\n      const bodyClasses =\n        document.body.className || \"\";\n\n\n      \/*\n       * Regular WordPress Page\n       *\/\n\n      const pageMatch =\n        bodyClasses.match(\n          \/(?:^|\\s)page-id-(\\d+)(?:\\s|$)\/\n        );\n\n\n      if (pageMatch && pageMatch[1]) {\n\n        return parseInt(\n          pageMatch[1],\n          10\n        );\n\n      }\n\n\n      \/*\n       * Regular WordPress Post\n       *\/\n\n      const postMatch =\n        bodyClasses.match(\n          \/(?:^|\\s)postid-(\\d+)(?:\\s|$)\/\n        );\n\n\n      if (postMatch && postMatch[1]) {\n\n        return parseInt(\n          postMatch[1],\n          10\n        );\n\n      }\n\n\n      return null;\n\n    }\n\n\n    \/*\n     * Find the current WordPress Page\/Post ID.\n     *\n     * The body class is the preferred method.\n     *\n     * REST API URL matching is retained as a fallback\n     * for unusual WordPress templates.\n     *\/\n\n    async function findCurrentPostId() {\n\n      if (currentPostId) {\n\n        return currentPostId;\n\n      }\n\n\n      \/* -----------------------------------------------------\n         FIRST: BODY CLASS\n         ----------------------------------------------------- *\/\n\n      const bodyId =\n        findPostIdFromBody();\n\n\n      if (bodyId) {\n\n        currentPostId =\n          bodyId;\n\n        return currentPostId;\n\n      }\n\n\n      \/* -----------------------------------------------------\n         SECOND: CURRENT URL \u2192 WORDPRESS PAGES\n         ----------------------------------------------------- *\/\n\n      const currentUrl =\n        window.location.href.split(\"#\")[0];\n\n      const cleanCurrentUrl =\n        currentUrl.replace(\/\\\/$\/, \"\");\n\n\n      try {\n\n        const pageResponse =\n          await fetch(\n            \"\/the-house\/wp-json\/wp\/v2\/pages\" +\n            \"?per_page=100\" +\n            \"&status=publish\",\n            {\n              credentials: \"same-origin\"\n            }\n          );\n\n\n        if (pageResponse.ok) {\n\n          const pages =\n            await pageResponse.json();\n\n\n          if (Array.isArray(pages)) {\n\n            const matchingPage =\n              pages.find(function (page) {\n\n                if (!page.link) {\n                  return false;\n                }\n\n                return (\n                  page.link.replace(\/\\\/$\/, \"\") ===\n                  cleanCurrentUrl\n                );\n\n              });\n\n\n            if (matchingPage) {\n\n              currentPostId =\n                parseInt(\n                  matchingPage.id,\n                  10\n                );\n\n              return currentPostId;\n\n            }\n\n          }\n\n        }\n\n      } catch (error) {\n\n        console.warn(\n          \"Could not identify the current WordPress page.\",\n          error\n        );\n\n      }\n\n\n      \/* -----------------------------------------------------\n         THIRD: CURRENT URL \u2192 WORDPRESS POSTS\n         ----------------------------------------------------- *\/\n\n      try {\n\n        const postResponse =\n          await fetch(\n            \"\/the-house\/wp-json\/wp\/v2\/posts\" +\n            \"?per_page=100\" +\n            \"&status=publish\",\n            {\n              credentials: \"same-origin\"\n            }\n          );\n\n\n        if (postResponse.ok) {\n\n          const posts =\n            await postResponse.json();\n\n\n          if (Array.isArray(posts)) {\n\n            const matchingPost =\n              posts.find(function (post) {\n\n                if (!post.link) {\n                  return false;\n                }\n\n                return (\n                  post.link.replace(\/\\\/$\/, \"\") ===\n                  cleanCurrentUrl\n                );\n\n              });\n\n\n            if (matchingPost) {\n\n              currentPostId =\n                parseInt(\n                  matchingPost.id,\n                  10\n                );\n\n              return currentPostId;\n\n            }\n\n          }\n\n        }\n\n      } catch (error) {\n\n        console.warn(\n          \"Could not identify the current WordPress post.\",\n          error\n        );\n\n      }\n\n\n      return null;\n\n    }\n\n\n    \/* =======================================================\n       AUDIO\n       ======================================================= *\/\n\n    let storyAudio = null;\n    let houseAudio = null;\n\n\n    function toggleAudio(type) {\n\n      const files =\n        getFiles();\n\n\n      const source =\n        type === \"story\"\n          ? files.story\n          : files.house;\n\n\n      if (!source) {\n        return;\n      }\n\n\n      let audio;\n\n\n      if (type === \"story\") {\n\n        if (!storyAudio) {\n\n          storyAudio =\n            new Audio(source);\n\n          storyAudio.loop =\n            false;\n\n        }\n\n        audio =\n          storyAudio;\n\n      } else {\n\n        if (!houseAudio) {\n\n          houseAudio =\n            new Audio(source);\n\n          houseAudio.loop =\n            false;\n\n        }\n\n        audio =\n          houseAudio;\n\n      }\n\n\n      \/*\n       * Only one house\/story audio track\n       * should play at a time.\n       *\/\n\n      if (\n        type === \"story\" &&\n        houseAudio\n      ) {\n\n        houseAudio.pause();\n\n        houseAudio.currentTime =\n          0;\n\n      }\n\n\n      if (\n        type === \"house\" &&\n        storyAudio\n      ) {\n\n        storyAudio.pause();\n\n        storyAudio.currentTime =\n          0;\n\n      }\n\n\n      if (audio.paused) {\n\n        audio.play()\n          .catch(function (error) {\n\n            console.warn(\n              \"Audio could not be played.\",\n              error\n            );\n\n          });\n\n      } else {\n\n        audio.pause();\n\n        audio.currentTime =\n          0;\n\n      }\n\n    }\n\n\n    \/* =======================================================\n       HELP\n       ======================================================= *\/\n\n    const helpBox =\n      document.getElementById(\n        \"house-help-box\"\n      );\n\n    const helpText =\n      document.getElementById(\n        \"house-help-text\"\n      );\n\n    const helpClose =\n      document.getElementById(\n        \"house-help-close\"\n      );\n\n\n    function openHelp() {\n\n      const files =\n        getFiles();\n\n\n      if (\n        !helpBox ||\n        !helpText\n      ) {\n        return;\n      }\n\n\n      helpText.textContent =\n        files.help ||\n        \"There is nothing for you to find here right now.\";\n\n\n      helpBox.classList.add(\n        \"is-open\"\n      );\n\n\n      helpBox.setAttribute(\n        \"aria-hidden\",\n        \"false\"\n      );\n\n    }\n\n\n    function closeHelp() {\n\n      if (!helpBox) {\n        return;\n      }\n\n\n      helpBox.classList.remove(\n        \"is-open\"\n      );\n\n\n      helpBox.setAttribute(\n        \"aria-hidden\",\n        \"true\"\n      );\n\n    }\n\n\n    if (helpClose) {\n\n      helpClose.addEventListener(\n        \"click\",\n        function (event) {\n\n          event.stopPropagation();\n\n          closeHelp();\n\n        }\n      );\n\n    }\n\n\n    \/* =======================================================\n       NOTE FORM\n       ======================================================= *\/\n\n    const noteBox =\n      document.getElementById(\n        \"house-note-box\"\n      );\n\n    const noteClose =\n      document.getElementById(\n        \"house-note-close\"\n      );\n\n    const noteForm =\n      document.getElementById(\n        \"house-note-form\"\n      );\n\n    const noteAuthor =\n      document.getElementById(\n        \"house-note-author\"\n      );\n\n    const noteComment =\n      document.getElementById(\n        \"house-note-comment\"\n      );\n\n    const noteSubmit =\n      document.getElementById(\n        \"house-note-submit\"\n      );\n\n    const noteStatus =\n      document.getElementById(\n        \"house-note-status\"\n      );\n\n\n    function openNoteBox() {\n\n      if (!noteBox) {\n        return;\n      }\n\n\n      if (noteStatus) {\n\n        noteStatus.textContent =\n          \"\";\n\n        noteStatus.className =\n          \"house-note-status\";\n\n      }\n\n\n      noteBox.classList.add(\n        \"is-open\"\n      );\n\n\n      noteBox.setAttribute(\n        \"aria-hidden\",\n        \"false\"\n      );\n\n\n      setTimeout(function () {\n\n        if (noteAuthor) {\n\n          noteAuthor.focus();\n\n        }\n\n      }, 50);\n\n    }\n\n\n    function closeNoteBox() {\n\n      if (!noteBox) {\n        return;\n      }\n\n\n      noteBox.classList.remove(\n        \"is-open\"\n      );\n\n\n      noteBox.setAttribute(\n        \"aria-hidden\",\n        \"true\"\n      );\n\n    }\n\n\n    if (noteClose) {\n\n      noteClose.addEventListener(\n        \"click\",\n        function (event) {\n\n          event.stopPropagation();\n\n          closeNoteBox();\n\n        }\n      );\n\n    }\n\n\n    \/* =======================================================\n       SAVE NOTE TO WORDPRESS COMMENTS\n       ======================================================= *\/\n\n    if (noteForm) {\n\n      noteForm.addEventListener(\n        \"submit\",\n        async function (event) {\n\n          event.preventDefault();\n\n          if (noteSubmit) {\n            noteSubmit.disabled = true;\n            noteSubmit.textContent = \"Finding page\u2026\";\n          }\n\n          if (noteStatus) {\n            noteStatus.textContent = \"Finding this page\u2026\";\n            noteStatus.className = \"house-note-status\";\n          }\n\n          try {\n\n            const postId = await findCurrentPostId();\n\n            if (!postId) {\n              throw new Error(\n                \"I couldn't identify this WordPress page. Please try refreshing the page.\"\n              );\n            }\n\n            const author = noteAuthor ? noteAuthor.value.trim() : \"\";\n            const comment = noteComment ? noteComment.value.trim() : \"\";\n            const emailField = document.getElementById(\"house-note-email\");\n            const email = emailField ? emailField.value.trim() : \"\";\n\n            if (!author) {\n              throw new Error(\"Please add your name.\");\n            }\n\n            if (!email) {\n              throw new Error(\"Please add your email address.\");\n            }\n\n            if (!emailField || !emailField.checkValidity()) {\n              throw new Error(\"Please enter a valid email address.\");\n            }\n\n            if (!comment) {\n              throw new Error(\"Please add your note.\");\n            }\n\n            if (noteStatus) {\n              noteStatus.textContent = \"Leaving your note\u2026\";\n              noteStatus.className = \"house-note-status\";\n            }\n\n            if (noteSubmit) {\n              noteSubmit.textContent = \"Leaving note\u2026\";\n            }\n\n            \/*\n             * Use WordPress's normal comment form endpoint rather than the\n             * REST API. This allows the site's existing anonymous-comment\n             * settings and moderation rules to handle the note.\n             *\n             * The form is submitted into a hidden same-origin iframe so the\n             * visitor stays on the current page.\n             *\/\n\n            let commentFrame = document.getElementById(\"house-comment-frame\");\n\n            if (!commentFrame) {\n              commentFrame = document.createElement(\"iframe\");\n              commentFrame.id = \"house-comment-frame\";\n              commentFrame.name = \"house-comment-frame\";\n              commentFrame.title = \"\";\n              commentFrame.setAttribute(\"aria-hidden\", \"true\");\n              commentFrame.style.position = \"fixed\";\n              commentFrame.style.width = \"1px\";\n              commentFrame.style.height = \"1px\";\n              commentFrame.style.border = \"0\";\n              commentFrame.style.opacity = \"0\";\n              commentFrame.style.pointerEvents = \"none\";\n              document.body.appendChild(commentFrame);\n            }\n\n            let postIdField = noteForm.querySelector('input[name=\"comment_post_ID\"]');\n            if (!postIdField) {\n              postIdField = document.createElement(\"input\");\n              postIdField.type = \"hidden\";\n              postIdField.name = \"comment_post_ID\";\n              noteForm.appendChild(postIdField);\n            }\n            postIdField.value = String(postId);\n\n            let parentField = noteForm.querySelector('input[name=\"comment_parent\"]');\n            if (!parentField) {\n              parentField = document.createElement(\"input\");\n              parentField.type = \"hidden\";\n              parentField.name = \"comment_parent\";\n              noteForm.appendChild(parentField);\n            }\n            parentField.value = \"0\";\n\n            let urlField = noteForm.querySelector('input[name=\"url\"]');\n            if (!urlField) {\n              urlField = document.createElement(\"input\");\n              urlField.type = \"hidden\";\n              urlField.name = \"url\";\n              noteForm.appendChild(urlField);\n            }\n            urlField.value = \"\";\n\n            noteForm.action = \"\/the-house\/wp-comments-post.php\";\n            noteForm.method = \"post\";\n            noteForm.target = \"house-comment-frame\";\n\n            \/*\n             * Submit the form into the hidden iframe. We wait for the\n             * WordPress response and inspect its URL\/body before telling\n             * the visitor that the note was saved.\n             *\/\n            const handleCommentResponse = function () {\n              try {\n                const frameWindow = commentFrame.contentWindow;\n                const currentUrl = frameWindow.location.href || \"\";\n\n                if (\n                  !currentUrl ||\n                  currentUrl === \"about:blank\" ||\n                  currentUrl.indexOf(\"about:blank\") === 0\n                ) {\n                  return;\n                }\n\n                const frameText = frameWindow.document.body\n                  ? frameWindow.document.body.innerText || \"\"\n                  : \"\";\n\n                const lowerUrl = currentUrl.toLowerCase();\n                const lowerText = frameText.toLowerCase();\n\n                \/*\n                 * WordPress sends the visitor to an error page when the\n                 * comment cannot be accepted. Catch that before success.\n                 *\/\n                if (\n                  lowerUrl.indexOf(\"wp-comments-post.php\") !== -1 &&\n                  (\n                    lowerUrl.indexOf(\"error\") !== -1 ||\n                    lowerText.indexOf(\"error:\") !== -1 ||\n                    lowerText.indexOf(\"sorry\") !== -1\n                  )\n                ) {\n                  const lines = frameText\n                    .split(\/\\r?\\n\/)\n                    .map(function (line) { return line.trim(); })\n                    .filter(Boolean);\n\n                  throw new Error(\n                    lines.length\n                      ? lines[0]\n                      : \"WordPress could not save the note.\"\n                  );\n                }\n\n                if (noteStatus) {\n                  noteStatus.textContent =\n                    \"Your note has been submitted. It may need approval before it appears in Paper notes.\";\n                  noteStatus.className = \"house-note-status success\";\n                }\n\n                if (noteComment) {\n                  noteComment.value = \"\";\n                }\n\n                if (notesBox && notesBox.classList.contains(\"is-open\")) {\n                  loadPageNotes();\n                }\n\n                setTimeout(function () {\n                  closeNoteBox();\n                }, 2200);\n\n              } catch (responseError) {\n                console.error(\"House note response error:\", responseError);\n\n                if (noteStatus) {\n                  noteStatus.textContent =\n                    responseError.message || \"WordPress could not save the note.\";\n                  noteStatus.className = \"house-note-status error\";\n                }\n              } finally {\n                commentFrame.removeEventListener(\"load\", handleCommentResponse);\n              }\n            };\n\n            commentFrame.addEventListener(\"load\", handleCommentResponse);\n\n            \/*\n             * HTMLFormElement.submit() sends the exact fields assembled\n             * above without triggering this submit listener again.\n             *\/\n            HTMLFormElement.prototype.submit.call(noteForm);\n\n          } catch (error) {\n\n            console.error(\"House note error:\", error);\n\n            if (noteStatus) {\n              noteStatus.textContent =\n                error.message || \"The note could not be saved.\";\n              noteStatus.className = \"house-note-status error\";\n            }\n\n          } finally {\n\n            if (noteSubmit) {\n              noteSubmit.disabled = false;\n              noteSubmit.textContent = \"Leave note\";\n            }\n\n          }\n\n        }\n      );\n\n    }\n\n\n    \/* =======================================================\n       SHOW PAPER NOTES\n       ======================================================= *\/\n\n    const notesBox =\n      document.getElementById(\n        \"house-notes-box\"\n      );\n\n    const notesClose =\n      document.getElementById(\n        \"house-notes-close\"\n      );\n\n    const notesList =\n      document.getElementById(\n        \"house-notes-list\"\n      );\n\n\n    function openNotesBox() {\n\n      if (!notesBox) {\n        return;\n      }\n\n\n      notesBox.classList.add(\n        \"is-open\"\n      );\n\n\n      notesBox.setAttribute(\n        \"aria-hidden\",\n        \"false\"\n      );\n\n\n      loadPageNotes();\n\n    }\n\n\n    function closeNotesBox() {\n\n      if (!notesBox) {\n        return;\n      }\n\n\n      notesBox.classList.remove(\n        \"is-open\"\n      );\n\n\n      notesBox.setAttribute(\n        \"aria-hidden\",\n        \"true\"\n      );\n\n    }\n\n\n    if (notesClose) {\n\n      notesClose.addEventListener(\n        \"click\",\n        function (event) {\n\n          event.stopPropagation();\n\n          closeNotesBox();\n\n        }\n      );\n\n    }\n\n\n    \/* =======================================================\n       LOAD WORDPRESS COMMENTS FOR CURRENT PAGE\n       ======================================================= *\/\n\n    async function loadPageNotes() {\n\n      if (!notesList) {\n        return;\n      }\n\n\n      notesList.innerHTML =\n        '<div class=\"house-no-notes\">' +\n        'Finding the notes\u2026' +\n        '<\/div>';\n\n\n      try {\n\n        \/*\n         * Find the same WordPress page ID\n         * used when saving the note.\n         *\/\n\n        const postId =\n          await findCurrentPostId();\n\n\n        if (!postId) {\n\n          throw new Error(\n            \"I couldn't identify this page.\"\n          );\n\n        }\n\n\n        \/*\n         * Ask WordPress for comments belonging\n         * specifically to this page.\n         *\n         * status=approve means we only show\n         * comments that WordPress has made public.\n         *\/\n\n        let comments = [];\n\n        \/*\n         * First try the WordPress REST API.\n         * This is the cleanest way to get only comments\n         * attached to the current page.\n         *\/\n        try {\n\n          const response =\n            await fetch(\n              \"\/the-house\/wp-json\/wp\/v2\/comments\" +\n              \"?post=\" +\n              encodeURIComponent(\n                postId\n              ) +\n              \"&status=approve\" +\n              \"&per_page=100\" +\n              \"&orderby=date\" +\n              \"&order=desc\",\n              {\n                method: \"GET\",\n                credentials: \"same-origin\"\n              }\n            );\n\n\n          if (response.ok) {\n\n            const data =\n              await response.json();\n\n            if (Array.isArray(data)) {\n              comments = data;\n            }\n\n          }\n\n        } catch (error) {\n\n          console.warn(\n            \"The WordPress comments API could not be read.\",\n            error\n          );\n\n        }\n\n\n        \/*\n         * Fallback: WordPress also prints approved comments\n         * directly into the page. If the REST API is blocked\n         * by the site's configuration, read those visible\n         * comments instead. This still keeps the notes limited\n         * to the current page.\n         *\/\n        if (comments.length === 0) {\n\n          const nativeComments =\n            Array.from(\n              document.querySelectorAll(\n                \"#comments li.comment, .comment-list li.comment, li.comment\"\n              )\n            );\n\n\n          comments = nativeComments.map(function (item) {\n\n            const authorElement =\n              item.querySelector(\n                \".comment-author, .fn, .commentmetadata .fn\"\n              );\n\n            const dateElement =\n              item.querySelector(\n                \"time, .comment-metadata, .comment-meta\"\n              );\n\n            const contentElement =\n              item.querySelector(\n                \".comment-content\"\n              );\n\n            return {\n              author_name: authorElement\n                ? authorElement.textContent.trim()\n                : \"Anonymous\",\n              date: dateElement\n                ? (dateElement.getAttribute(\"datetime\") || dateElement.textContent.trim())\n                : \"\",\n              content: {\n                rendered: contentElement\n                  ? contentElement.innerHTML\n                  : item.textContent\n              }\n            };\n\n          });\n\n        }\n\n\n        \/*\n         * No approved comments.\n         *\/\n\n        if (\n          !Array.isArray(\n            comments\n          ) ||\n          comments.length === 0\n        ) {\n\n          notesList.innerHTML =\n            '<div class=\"house-no-notes\">' +\n            'No paper notes have been left on this page yet.' +\n            '<\/div>';\n\n          return;\n\n        }\n\n\n        \/*\n         * Empty the loading message.\n         *\/\n\n        notesList.innerHTML =\n          \"\";\n\n\n        \/*\n         * Build each paper note safely\n         * using textContent rather than injecting\n         * comment HTML directly.\n         *\/\n\n        comments.forEach(\n          function (comment) {\n\n            const note =\n              document.createElement(\n                \"div\"\n              );\n\n            note.className =\n              \"house-single-note\";\n\n\n            const author =\n              document.createElement(\n                \"div\"\n              );\n\n            author.className =\n              \"house-single-note-author\";\n\n\n            author.textContent =\n              comment.author_name ||\n              \"Anonymous\";\n\n\n            const date =\n              document.createElement(\n                \"div\"\n              );\n\n            date.className =\n              \"house-single-note-date\";\n\n\n            if (comment.date) {\n\n              const parsedDate =\n                new Date(\n                  comment.date\n                );\n\n\n              if (\n                !isNaN(\n                  parsedDate.getTime()\n                )\n              ) {\n\n                date.textContent =\n                  parsedDate.toLocaleDateString(\n                    undefined,\n                    {\n                      year:\n                        \"numeric\",\n\n                      month:\n                        \"long\",\n\n                      day:\n                        \"numeric\"\n                    }\n                  );\n\n              }\n\n            }\n\n\n            const text =\n              document.createElement(\n                \"div\"\n              );\n\n            text.className =\n              \"house-single-note-text\";\n\n\n            \/*\n             * WordPress gives us rendered HTML\n             * for comment.content.\n             *\n             * We convert it to plain text so that\n             * visitors' comments cannot inject\n             * arbitrary HTML into the menu.\n             *\/\n\n            if (\n              comment.content &&\n              comment.content.rendered\n            ) {\n\n              text.textContent =\n                stripHtml(\n                  comment.content.rendered\n                );\n\n            } else {\n\n              text.textContent =\n                \"\";\n\n            }\n\n\n            note.appendChild(\n              author\n            );\n\n\n            if (\n              date.textContent\n            ) {\n\n              note.appendChild(\n                date\n              );\n\n            }\n\n\n            note.appendChild(\n              text\n            );\n\n\n            notesList.appendChild(\n              note\n            );\n\n          }\n        );\n\n\n      } catch (error) {\n\n        console.error(\n          \"House notes error:\",\n          error\n        );\n\n\n        notesList.innerHTML =\n          '<div class=\"house-no-notes\">' +\n          'The paper notes could not be loaded right now.' +\n          '<\/div>';\n\n      }\n\n    }\n\n\n    \/* =======================================================\n       REMOVE HTML FROM WORDPRESS COMMENT CONTENT\n       ======================================================= *\/\n\n    function stripHtml(html) {\n\n      const temporary =\n        document.createElement(\n          \"div\"\n        );\n\n\n      temporary.innerHTML =\n        html;\n\n\n      return (\n        temporary.textContent ||\n        temporary.innerText ||\n        \"\"\n      );\n\n    }\n\n\n    \/* =======================================================\n       ARTWORK\n       ======================================================= *\/\n\n    const artOverlay =\n      document.getElementById(\n        \"house-art-overlay\"\n      );\n\n    const artImage =\n      document.getElementById(\n        \"house-art-image\"\n      );\n\n    const artClose =\n      document.getElementById(\n        \"house-art-close\"\n      );\n\n\n    function openArtwork() {\n\n      const files =\n        getFiles();\n\n\n      if (\n        !files.art ||\n        !artOverlay ||\n        !artImage\n      ) {\n\n        return;\n\n      }\n\n\n      artImage.src =\n        files.art;\n\n\n      artOverlay.style.display =\n        \"flex\";\n\n\n      if (\n        artOverlay.requestFullscreen\n      ) {\n\n        artOverlay\n          .requestFullscreen()\n          .catch(function () {});\n\n      } else if (\n        artOverlay.webkitRequestFullscreen\n      ) {\n\n        artOverlay.webkitRequestFullscreen();\n\n      }\n\n    }\n\n\n    function closeArtwork() {\n\n      if (!artOverlay) {\n        return;\n      }\n\n\n      artOverlay.style.display =\n        \"none\";\n\n\n      if (artImage) {\n\n        artImage.src =\n          \"\";\n\n      }\n\n\n      if (\n        document.fullscreenElement\n      ) {\n\n        document\n          .exitFullscreen()\n          .catch(function () {});\n\n      } else if (\n        document.webkitFullscreenElement\n      ) {\n\n        document.webkitExitFullscreen();\n\n      }\n\n    }\n\n\n    if (artClose) {\n\n      artClose.addEventListener(\n        \"click\",\n        function (event) {\n\n          event.stopPropagation();\n\n          closeArtwork();\n\n        }\n      );\n\n    }\n\n\n    if (artOverlay) {\n\n      artOverlay.addEventListener(\n        \"click\",\n        function (event) {\n\n          if (\n            event.target ===\n            artOverlay\n          ) {\n\n            closeArtwork();\n\n          }\n\n        }\n      );\n\n    }\n\n\n    \/* =======================================================\n       ESCAPE KEY\n       ======================================================= *\/\n\n    document.addEventListener(\n      \"keydown\",\n      function (event) {\n\n        if (\n          event.key !==\n          \"Escape\"\n        ) {\n\n          return;\n\n        }\n\n\n        closeHelp();\n\n        closeNoteBox();\n\n        closeNotesBox();\n\n\n        if (\n          artOverlay &&\n          artOverlay.style.display ===\n          \"flex\"\n        ) {\n\n          closeArtwork();\n\n        }\n\n      }\n    );\n\n\n    \/* =======================================================\n       MENU BUTTONS\n       ======================================================= *\/\n\n    menu.addEventListener(\n      \"click\",\n      function (event) {\n\n        const button =\n          event.target.closest(\n            \".house-menu-button\"\n          );\n\n\n        if (\n          !button ||\n          !menu.contains(\n            button\n          )\n        ) {\n\n          return;\n\n        }\n\n\n        \/* ---------------------------------------------------\n           STORY\n           --------------------------------------------------- *\/\n\n        if (\n          button.classList.contains(\n            \"house-story\"\n          )\n        ) {\n\n          toggleAudio(\n            \"story\"\n          );\n\n          return;\n\n        }\n\n\n        \/* ---------------------------------------------------\n           ART\n           --------------------------------------------------- *\/\n\n        if (\n          button.classList.contains(\n            \"house-eye\"\n          )\n        ) {\n\n          openArtwork();\n\n          return;\n\n        }\n\n\n        \/* ---------------------------------------------------\n           HOUSE AUDIO\n           --------------------------------------------------- *\/\n\n        if (\n          button.classList.contains(\n            \"house-ear\"\n          )\n        ) {\n\n          toggleAudio(\n            \"house\"\n          );\n\n          return;\n\n        }\n\n\n        \/* ---------------------------------------------------\n           HELP\n           --------------------------------------------------- *\/\n\n        if (\n          button.classList.contains(\n            \"house-help\"\n          )\n        ) {\n\n          openHelp();\n\n          return;\n\n        }\n\n\n        \/* ---------------------------------------------------\n           LEAVE A NOTE\n           --------------------------------------------------- *\/\n\n        if (\n          button.classList.contains(\n            \"house-note\"\n          )\n        ) {\n\n          openNoteBox();\n\n          return;\n\n        }\n\n\n        \/* ---------------------------------------------------\n           SEARCH PAPER NOTES\n           --------------------------------------------------- *\/\n\n        if (\n          button.classList.contains(\n            \"house-notes\"\n          )\n        ) {\n\n          openNotesBox();\n\n          return;\n\n        }\n\n      }\n    );\n\n  }\n\n\n  \/* =========================================================\n     INITIALISE\n     ========================================================= *\/\n\n  if (\n    document.readyState ===\n    \"loading\"\n  ) {\n\n    document.addEventListener(\n      \"DOMContentLoaded\",\n      initHouseMenu\n    );\n\n  } else {\n\n    initHouseMenu();\n\n  }\n\n})();\n<\/script>\n\n\n<script>\nwindow.houseMenuFiles = {\n\n  story: \"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/front-door.mp3\",\n\n  art: \"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/09\/Front-Door-scaled.jpg\",\n\n  house: \"\",\n\n  help: \"If you drag the key over the keyhole it will reveal the password.\"\n\n};\n<\/script>\n\n\n\n<!-- HAUNTED LION DOOR KNOCKER -->\n\n<div class=\"haunted-door-knocker\">\n\n  <button class=\"lion-knocker\" type=\"button\" aria-label=\"Knock three times on the door\">\n\n    <!-- Stationary lion head -->\n    <img decoding=\"async\" class=\"lion-background\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/10\/lion-door-background.png\" alt=\"Ancient lion-head door knocker\">\n\n    <!-- Animated metal ring -->\n    <img decoding=\"async\" class=\"lion-ring\" src=\"https:\/\/itdd.au.dk\/the-house\/wp-content\/uploads\/sites\/112\/2026\/10\/lion-ring.png\" alt=\"\" aria-hidden=\"true\">\n\n  <\/button>\n\n<\/div>\n\n<style>\n\n\/* ==============================\n   KNOCKER POSITION AND SIZE\n   ============================== *\/\n\n.haunted-door-knocker {\n  position: absolute;\n\n  \/* Moved up 5 percentage points *\/\n  top: 37%;\n\n  \/* Keep horizontal position *\/\n  left: 74%;\n\n  \/* 15% bigger than 280px *\/\n  width: 322px;\n\n  transform: translate(-50%, -50%);\n  margin: 0;\n  z-index: 10;\n  text-align: center;\n}\n\n\/* ==============================\n   BUTTON STYLING\n   ============================== *\/\n\n.haunted-door-knocker .lion-knocker {\n  position: relative;\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin: 0;\n\n  border: none !important;\n  border-radius: 0;\n  outline: none !important;\n  box-shadow: none !important;\n\n  background: transparent !important;\n  cursor: pointer;\n  overflow: visible;\n\n  appearance: none;\n  -webkit-appearance: none;\n  -webkit-tap-highlight-color: transparent;\n}\n\n\/* Remove button outline *\/\n.haunted-door-knocker .lion-knocker:focus,\n.haunted-door-knocker .lion-knocker:active,\n.haunted-door-knocker .lion-knocker:focus-visible {\n  outline: none !important;\n  border: none !important;\n  box-shadow: none !important;\n  background: transparent !important;\n}\n\n\/* ==============================\n   STATIONARY LION HEAD\n   ============================== *\/\n\n.haunted-door-knocker .lion-background {\n  display: block;\n  width: 100%;\n  height: auto;\n\n  pointer-events: none;\n  transition: filter 0.4s ease;\n}\n\n\/* ==============================\n   ANIMATED METAL RING\n   ============================== *\/\n\n.haunted-door-knocker .lion-ring {\n  position: absolute;\n\n  left: 0;\n  top: 0;\n\n  width: 100%;\n  height: 100%;\n\n  object-fit: fill;\n  transform-origin: 50% 70%;\n\n  pointer-events: none;\n  will-change: transform;\n\n  transition: filter 0.4s ease;\n}\n\n\/* ==============================\n   GOLDEN HOVER GLOW\n   ============================== *\/\n\n@media (hover: hover) {\n\n  .haunted-door-knocker\n  .lion-knocker:hover\n  .lion-background {\n    filter:\n      brightness(1.07)\n      drop-shadow(\n        0 0 8px rgba(186, 137, 63, 0.35)\n      );\n  }\n\n  .haunted-door-knocker\n  .lion-knocker:hover\n  .lion-ring {\n    filter:\n      brightness(1.16)\n      drop-shadow(\n        0 0 7px rgba(255, 180, 68, 0.65)\n      );\n  }\n\n}\n\n\/* ==============================\n   KNOCKING ANIMATION\n   ============================== *\/\n\n\/* Only animate the ring *\/\n.haunted-door-knocker\n.lion-knocker.knocking\n.lion-ring {\n  animation: lionRingKnock 0.34s ease-in-out 3;\n}\n\n@keyframes lionRingKnock {\n\n  0%, 100% {\n    transform: scaleY(1);\n  }\n\n  35% {\n    transform: scaleY(0.77);\n  }\n\n  70% {\n    transform: scaleY(1.03);\n  }\n\n}\n\n\/* No flashing animation on the lion head *\/\n\n\/* Keyboard focus: subtle ring glow *\/\n.haunted-door-knocker\n.lion-knocker:focus-visible\n.lion-ring {\n  filter:\n    brightness(1.16)\n    drop-shadow(\n      0 0 7px rgba(255, 180, 68, 0.65)\n    );\n}\n\n\/* ==============================\n   MOBILE RESPONSIVENESS\n   ============================== *\/\n\n@media (max-width: 600px) {\n\n  .haunted-door-knocker {\n    width: 219px;\n  }\n\n}\n\n\/* Reduced motion accessibility *\/\n@media (prefers-reduced-motion: reduce) {\n\n  .haunted-door-knocker\n  .lion-knocker.knocking\n  .lion-ring {\n    animation: none;\n  }\n\n}\n\n<\/style>\n\n<script>\n\n(function () {\n\n  const button = document.querySelector(\n    \".haunted-door-knocker .lion-knocker\"\n  );\n\n  if (!button) return;\n\n  let audioContext;\n  let knocking = false;\n\n  \/* ==============================\n     CREATE DEEP KNOCKING SOUND\n     ============================== *\/\n\n  function playKnock(time) {\n\n    const oscillator =\n      audioContext.createOscillator();\n\n    const gain =\n      audioContext.createGain();\n\n    const filter =\n      audioContext.createBiquadFilter();\n\n    oscillator.type = \"triangle\";\n\n    oscillator.frequency.setValueAtTime(\n      145, time\n    );\n\n    oscillator.frequency.exponentialRampToValueAtTime(\n      58, time + 0.14\n    );\n\n    filter.type = \"lowpass\";\n    filter.frequency.value = 550;\n\n    gain.gain.setValueAtTime(\n      0.0001, time\n    );\n\n    gain.gain.exponentialRampToValueAtTime(\n      0.65, time + 0.006\n    );\n\n    gain.gain.exponentialRampToValueAtTime(\n      0.0001, time + 0.22\n    );\n\n    oscillator.connect(filter);\n    filter.connect(gain);\n    gain.connect(audioContext.destination);\n\n    oscillator.start(time);\n    oscillator.stop(time + 0.23);\n\n  }\n\n  \/* ==============================\n     CLICK TO KNOCK\n     ============================== *\/\n\n  button.addEventListener(\n    \"click\",\n    async function () {\n\n      if (knocking) return;\n\n      knocking = true;\n\n      \/* Start ring animation *\/\n      button.classList.remove(\"knocking\");\n\n      void button.offsetWidth;\n\n      button.classList.add(\"knocking\");\n\n      try {\n\n        const AudioClass =\n          window.AudioContext ||\n          window.webkitAudioContext;\n\n        if (AudioClass) {\n\n          audioContext ||= new AudioClass();\n\n          await audioContext.resume();\n\n          const now =\n            audioContext.currentTime;\n\n          \/* Three knocking sounds *\/\n\n          playKnock(now + 0.24);\n          playKnock(now + 0.58);\n          playKnock(now + 0.92);\n\n        }\n\n      } catch (error) {\n\n        console.warn(\n          \"Knocker audio unavailable:\",\n          error\n        );\n\n      }\n\n      \/* Reset animation *\/\n      setTimeout(function () {\n\n        button.classList.remove(\"knocking\");\n\n        knocking = false;\n\n      }, 1100);\n\n    }\n  );\n\n})();\n\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>On the doorstep lies an old key The key is here just for you &#8220;Align the teeth with the dark void&#8230;&#8221; old key LOCKED<\/p>\n","protected":false},"author":224,"featured_media":0,"parent":0,"menu_order":1,"comment_status":"open","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-56","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/pages\/56","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/users\/224"}],"replies":[{"embeddable":true,"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/comments?post=56"}],"version-history":[{"count":62,"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/pages\/56\/revisions"}],"predecessor-version":[{"id":1469,"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/pages\/56\/revisions\/1469"}],"wp:attachment":[{"href":"https:\/\/itdd.au.dk\/the-house\/wp-json\/wp\/v2\/media?parent=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}