{"id":42628,"date":"2026-02-05T22:09:01","date_gmt":"2026-02-05T21:09:01","guid":{"rendered":"https:\/\/gruble.net\/?p=42628"},"modified":"2026-02-18T11:36:26","modified_gmt":"2026-02-18T10:36:26","slug":"kviz-2","status":"publish","type":"post","link":"https:\/\/gruble.net\/kviz-2\/","title":{"rendered":"Live KvIz"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"42628\" class=\"elementor elementor-42628\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-96369c1 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"96369c1\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-799b421\" data-id=\"799b421\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-0938b72 elementor-widget elementor-widget-html\" data-id=\"0938b72\" 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<!doctype html>\n<meta charset=\"utf-8\" \/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" \/>\n\n<style>\n  :root{\n    \/* Lys, poppende \u201cKvIz\u201d-tema *\/\n    --bg:#f6f7ff;\n    --card:#ffffff;\n    --text:#0f172a;\n    --muted:#475569;\n    --border:#e2e8f0;\n\n    --primary:#7c3aed;   \/* lilla *\/\n    --primary2:#ec4899;  \/* rosa *\/\n    --accent:#22c55e;    \/* gr\u00f8nn *\/\n    --warn:#f59e0b;      \/* gul *\/\n    --good:#16a34a;\n    --bad:#ef4444;\n  }\n\n  \/* --- Scoped \u201cCSS shield\u201d (for \u00e5 t\u00e5le ekstern theme-css) --- *\/\n  #quizbox, #quizbox * { box-sizing: border-box; }\n  #quizbox { color: var(--text) !important; }\n  #quizbox p, #quizbox div, #quizbox span, #quizbox strong { color: inherit; }\n  #quizbox a { color: var(--text) !important; }\n  #quizbox button { color: var(--text) !important; background: transparent; }\n  #quizbox img { max-width: 100% !important; }\n\n  body{margin:0;background:transparent;font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;color:var(--text);}\n\n  #quizbox{\n    max-width: 980px;\n    margin: 0 auto;\n    background:\n      radial-gradient(900px 420px at 15% -10%, rgba(124,58,237,.25), transparent 60%),\n      radial-gradient(900px 420px at 95% 0%, rgba(236,72,153,.18), transparent 60%),\n      radial-gradient(900px 420px at 55% 110%, rgba(34,197,94,.14), transparent 60%),\n      linear-gradient(180deg, #f8fbff 0%, #f6f7ff 100%);\n    border: 1px solid var(--border);\n    border-radius: 12px;\n    padding: 14px;\n  }\n\n  #quizbox h3{\n    margin: 0 0 10px 0;\n    text-align:center;\n    font-weight: 1000;\n    letter-spacing: .3px;\n    font-size: 26px;\n    padding: 8px 12px;\n    border: none !important;              \/* ingen \u201cramme\u201d *\/\n    border-radius: 0;\n    \/* VIKTIG: ingen bakgrunnsb\u00e5nd (tema-css kan ellers gi \u201cbl\u00e5tt p\u00e5 bl\u00e5tt\u201d) *\/\n    background: transparent !important;\n    color: var(--text) !important;\n    -webkit-text-fill-color: currentColor; \/* iOS\/Safari-sikkerhet *\/\n    text-shadow: 0 12px 28px rgba(124,58,237,.12);\n    position: relative;\n  }\n  #quizbox h3::after{\n    content:\"\";\n    display:block;\n    width: min(220px, 60%);\n    height: 6px;\n    margin: 8px auto 0 auto;\n    border-radius: 999px;\n    background: linear-gradient(90deg, rgba(124,58,237,.55), rgba(236,72,153,.45));\n    box-shadow: 0 10px 22px rgba(124,58,237,.18);\n  }\n\n  .topMetaRow{\n    margin: 6px auto 12px auto;\n    display:flex;\n    gap: 10px;\n    flex-wrap: wrap;\n    align-items: center;\n    justify-content: center;\n    color: var(--muted);\n    font-size: 12px;\n  }\n  .topMetaPill{\n    display:inline-flex;\n    gap: 8px;\n    align-items: center;\n    padding: 6px 10px;\n    border-radius: 999px;\n    background: #fff !important;\n    border: 1px solid var(--border) !important;\n    color: var(--muted) !important;\n    box-shadow: 0 10px 26px rgba(0,0,0,.08);\n  }\n  .topMetaPill strong{ color: var(--text); }\n  .topMetaPill{\n    cursor: pointer;\n    user-select: none;\n  }\n  .topMetaPill:focus-visible{\n    outline: 3px solid rgba(124,58,237,.35);\n    outline-offset: 2px;\n  }\n\n  \/* Badge modal *\/\n  .modalBackdrop{\n    position: fixed;\n    inset: 0;\n    background: rgba(15,23,42,.55);\n    backdrop-filter: blur(6px);\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    padding: 14px;\n    z-index: 99999;\n  }\n  .modalBackdrop.hidden{ display:none !important; }\n  .modalCard{\n    width: min(520px, 100%);\n    background: #fff;\n    color: var(--text);\n    border: 1px solid var(--border);\n    border-radius: 16px;\n    box-shadow: 0 22px 70px rgba(0,0,0,.35);\n    padding: 14px 14px;\n  }\n  .modalHeader{\n    display:flex;\n    gap: 10px;\n    align-items:flex-start;\n    justify-content: space-between;\n    margin-bottom: 8px;\n  }\n  .modalTitle{\n    font-weight: 1000;\n    font-size: 16px;\n    margin: 0;\n  }\n  .modalClose{\n    appearance:none;\n    \/* Shield mot theme-css *\/\n    border: 1px solid var(--border) !important;\n    background: #fff !important;\n    color: var(--text) !important;\n    border-radius: 12px !important;\n    padding: 8px 10px !important;\n    font-weight: 950 !important;\n    font-size: 13px !important;\n    cursor: pointer !important;\n    display: inline-flex !important;\n    align-items: center !important;\n    justify-content: center !important;\n    line-height: 1 !important;\n    text-decoration: none !important;\n    box-shadow: 0 10px 22px rgba(15,23,42,.10) !important;\n  }\n  .modalClose:hover{\n    border-color: rgba(124,58,237,.35) !important;\n    background: rgba(124,58,237,.06) !important;\n  }\n  .modalBody{\n    font-size: 13px;\n    line-height: 1.45;\n    color: var(--muted);\n  }\n  .modalBody strong{ color: var(--text); }\n  .badgeBig{\n    display:flex;\n    gap: 10px;\n    align-items:center;\n    justify-content:center;\n    margin: 10px 0 6px 0;\n    padding: 10px 10px;\n    border-radius: 14px;\n    border: 1px solid var(--border);\n    background: linear-gradient(180deg, rgba(124,58,237,.08), rgba(236,72,153,.06));\n  }\n  .badgeIcon{\n    font-size: 26px;\n    line-height: 1;\n  }\n  .badgeName{\n    font-weight: 1000;\n    color: var(--text);\n  }\n\n  .panel{\n    background: var(--card) !important;\n    border: 1px solid var(--border) !important;\n    border-radius: 12px;\n    padding: 16px !important; \/* hindre at theme-css fjerner \u201cluft\u201d *\/\n    box-shadow: 0 14px 40px rgba(15,23,42,.10);\n  }\n\n  .row{display:flex;gap:12px;align-items:stretch;flex-wrap:wrap;}\n  .col{flex:1 1 320px;min-width:280px;}\n\n  .articleCard{\n    display:flex;\n    gap:12px;\n    align-items:stretch;\n    min-width: 0;\n  }\n  .thumbWrap{\n    width: 260px;\n    max-width: 100%;\n    flex: 0 0 auto;\n    border-radius: 12px;\n    overflow: hidden;\n    border: 1px solid var(--border);\n    background: #fff;\n    min-width: 0;\n    aspect-ratio: 16 \/ 9;\n  }\n  \/* N\u00e5r vi viser nk-dekor i thumbnail: bruk kvadratisk ramme *\/\n  .thumbWrap.isSquareThumb{\n    aspect-ratio: 1 \/ 1;\n  }\n  .thumbWrap.thumbWrapSmall{\n    width: 220px;\n  }\n  .thumbWrap.isHidden{ display:none !important; }\n\n  \/* Desktop vs mobile placement of thumbnail *\/\n  .thumbDesktop{ display:block; }\n  .thumbMobile{ display:none; width:100%; }\n  .thumbWrap a{\n    display:block;\n    height:100%;\n    width:100%;\n    text-decoration:none;\n    color:inherit;\n  }\n  .thumb{\n    width:100% !important;\n    height:100% !important;\n    min-width: 100% !important;\n    min-height: 100% !important;\n    object-fit: cover !important;\n    display:block !important;\n    padding: 0 !important;\n    margin: 0 !important;\n    border: 0 !important;\n    border-radius: 0 !important;\n    transform-origin: center center;\n    background: linear-gradient(135deg, rgba(124,58,237,.25), rgba(236,72,153,.18));\n  }\n  \/* N\u00e5r vi bruker nk-dekor i artikkel-thumbnail: zoom litt inn for \u00e5 fjerne \u201cinnebygd\u201d luft *\/\n  .thumb[data-news-decor=\"1\"]{ transform: scale(1.12); }\n  .articleMeta{flex: 1 1 auto; min-width: 240px; min-width: 0;}\n  .sourcePill{\n    display:inline-block;\n    font-size: 12px;\n    padding: 4px 10px;\n    border-radius: 999px;\n    border:1px solid var(--border);\n    color: var(--muted);\n    background: #fff;\n  }\n  #quizbox .sourcePill a{\n    color: var(--muted) !important;\n    text-decoration: none !important;\n    border-bottom: 1px solid rgba(124,58,237,.18);\n    font-weight: 900;\n  }\n  #quizbox .sourcePill a:hover{\n    color: var(--primary) !important;\n    border-bottom-color: rgba(124,58,237,.45);\n  }\n  .articleTitle{\n    margin: 8px 0 6px 0;\n    font-size: 18px;\n    line-height: 1.25;\n    overflow-wrap: anywhere;\n  }\n  .articleTitle a{\n    color: var(--text);\n    text-decoration: none;\n    border-bottom: 1px solid rgba(124,58,237,.25);\n  }\n  .articleTitle a:hover{color:var(--primary);border-bottom-color: rgba(124,58,237,.45);}\n  .articleSummary{\n    margin: 0;\n    color: var(--muted);\n    font-size: 14px;\n    line-height: 1.55;\n  }\n  #quizbox .summaryTitle{\n    margin: 10px 0 8px 0;\n    font-size: 12px;\n    font-weight: 1000;\n    letter-spacing: .5px;\n    text-transform: uppercase;\n    color: var(--text) !important;\n    opacity: .92;\n    display: inline-flex;\n    align-items: center;\n    gap: 8px;\n  }\n  #quizbox .summaryTitle::before{\n    content:\"KI\";\n    font-size: 11px;\n    font-weight: 1000;\n    letter-spacing: .6px;\n    padding: 2px 8px;\n    border-radius: 999px;\n    background: rgba(124,58,237,.12);\n    border: 1px solid rgba(124,58,237,.22);\n    color: var(--text) !important;\n  }\n  .summaryP{\n    margin: 0 0 8px 0;\n  }\n  .summaryP:last-child{ margin-bottom: 0; }\n  .summaryMeta{\n    margin-top: 8px;\n    font-size: 12px;\n    color: var(--muted);\n  }\n\n  .readMoreRow{\n    margin-top: 10px;\n    text-align: left;\n  }\n  #quizbox .readMoreRow a{\n    display: inline-block;\n    color: var(--text) !important;\n    text-decoration: none;\n    border-bottom: 1px solid rgba(34,197,94,.45);\n    font-weight: 900;\n    letter-spacing: .4px;\n    padding: 4px 10px;\n    border-radius: 999px;\n    background: rgba(34,197,94,.12);\n  }\n  #quizbox .readMoreRow a:hover{\n    border-bottom-color: rgba(34,197,94,.75);\n    background: rgba(34,197,94,.18);\n  }\n  .readMoreNote{\n    margin-top: 6px;\n    font-size: 12px;\n    color: var(--muted);\n  }\n\n  .imgCreditRow{\n    margin-top: 10px;\n    font-size: 12px;\n    color: var(--muted);\n  }\n  #quizbox .imgCreditRow a{\n    color: var(--muted) !important;\n    text-decoration: underline;\n    text-underline-offset: 2px;\n  }\n  #quizbox .imgCreditRow.isHidden{ display:none !important; }\n\n  .btnRow{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px;}\n  .btnRow.center{justify-content:center;}\n  .btn{\n    appearance:none;\n    border:1px solid var(--border) !important;\n    background: #fff !important;\n    color: var(--text) !important;\n    padding: 10px 12px;\n    border-radius: 10px;\n    font-weight: 900;\n    cursor:pointer;\n    transition: transform .08s ease, background .2s ease, border-color .2s ease;\n    display: inline-flex;         \/* <-- vertikal sentering av tekst *\/\n    align-items: center;\n    justify-content: center;\n    line-height: 1;\n  }\n  .btn:hover{transform: translateY(-1px); border-color:rgba(255,255,255,.24);}\n  .btn:disabled{opacity:.6;cursor:not-allowed;transform:none;}\n  .btn.primary{\n    background: linear-gradient(90deg, #8b5cf6, #fb7185) !important; \/* lysere *\/\n    border-color: rgba(124,58,237,.30) !important;\n    color:#fff !important;\n    box-shadow: 0 10px 26px rgba(124,58,237,.18);\n  }\n  .btn.primary:hover{filter: brightness(1.05);}\n\n  .btn.danger{\n    background: rgba(239,68,68,.10) !important;\n    border-color: rgba(239,68,68,.35) !important;\n    color: var(--text) !important;\n  }\n  .btn.danger:hover{\n    background: rgba(220,38,38,.18) !important;\n    border-color: rgba(220,38,38,.75) !important;\n  }\n  .btn.danger.small{\n    padding: 8px 10px;\n    border-radius: 12px;\n    font-size: 13px;\n    font-weight: 900;\n    background: rgba(239,68,68,.12) !important;\n    border-color: rgba(239,68,68,.45) !important;\n  }\n  .btn.danger.small:hover{\n    background: rgba(244,63,94,.20) !important;\n    border-color: rgba(244,63,94,.80) !important;\n  }\n\n  .statusLine{\n    margin-top: 10px;\n    color: var(--muted);\n    font-size: 13px;\n    display:flex;\n    gap:10px;\n    flex-wrap:wrap;\n  }\n  .statusLine strong{color:var(--text);}\n\n  .qHeader{\n    display:flex;\n    justify-content: space-between;\n    align-items:center;\n    gap: 10px;\n    flex-wrap: wrap;\n    margin-bottom: 10px;\n  }\n  .qHeader .kicker{color:var(--muted);font-size:13px;}\n  .qText{\n    font-size: 20px;\n    margin: 0 0 10px 0;\n    font-weight: 800;\n    line-height: 1.25;\n    color: var(--text) !important;\n    text-align: center;\n  }\n\n  .qaArea{\n    margin-top: 10px;\n    padding: 14px 12px;\n    border-radius: 16px;\n    border: 1px solid var(--border);\n    background: linear-gradient(180deg, rgba(124,58,237,.06), rgba(236,72,153,.04));\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.60);\n  }\n  .aiNote{\n    margin: 10px auto 0 auto;\n    max-width: 760px;\n    text-align: center;\n    font-size: 12px;\n    color: var(--muted);\n  }\n  .aiNote strong{ color: var(--text); }\n\n\n  .choices{\n    display:flex;\n    flex-direction: column;\n    align-items: center;\n    gap: 10px;\n    max-width: 760px;\n    margin: 0 auto;\n  }\n\n  .choiceBtn{\n    text-align:center;\n    padding: 12px 14px;\n    border-radius: 12px;\n    border:1px solid var(--border) !important;\n    background: #fff !important;\n    cursor:pointer;\n    font-weight: 700;\n    line-height: 1.2;\n    color: var(--text) !important;\n    box-shadow: 0 10px 26px rgba(0,0,0,.18);\n    display:flex;\n    align-items:center;         \/* <-- fikser \u201ctekst i bunnen\u201d *\/\n    min-height: 54px;\n    justify-content: center;\n    width: fit-content;\n    max-width: min(760px, 100%);\n    white-space: normal;\n    overflow-wrap: anywhere;\n    font-size: 16px;\n  }\n  .choiceBtn:hover{border-color:rgba(255,255,255,.26);background: rgba(255,255,255,.10) !important;}\n  .choiceBtn:disabled{opacity:.55;cursor:not-allowed;}\n  \/* Tydelig feedback n\u00e5r valgt alternativ blir deaktivert *\/\n  .choiceBtn.correct{\n    border-color: rgba(34,197,94,.75) !important;\n    background: rgba(34,197,94,.16) !important;\n  }\n  .choiceBtn.wrong{\n    border-color: rgba(239,68,68,.85) !important;\n    background: rgba(239,68,68,.14) !important;\n  }\n  .choiceBtn.correct:disabled,\n  .choiceBtn.wrong:disabled{\n    opacity: 1; \/* behold fargen selv om knappen er disabled *\/\n  }\n\n  .explain{\n    margin-top: 10px;\n    padding: 10px 12px;\n    border-radius: 12px;\n    border:1px solid var(--border) !important;\n    background: #fff !important;\n    color: var(--text) !important;\n    font-size: 14px;\n    line-height: 1.45;\n    text-align: center;\n  }\n\n  .hidden{display:none !important;}\n  .center{text-align:center;}\n  .bigScore{font-size: 34px; font-weight: 950; margin: 8px 0; color:var(--text);}\n  .small{color:var(--muted);font-size: 13px;}\n  .toggleRow{\n    margin-top: 12px;\n    padding: 12px 12px;\n    border-radius: 14px;\n    border: 1px dashed rgba(124,58,237,.35);\n    background: rgba(124,58,237,.06);\n  }\n  .toggleRow label{\n    display:flex;\n    gap:10px;\n    align-items:flex-start;\n    cursor:pointer;\n    user-select:none;\n  }\n  .toggleRow input[type=\"checkbox\"]{\n    margin-top: 2px;\n    transform: scale(1.15);\n  }\n  .toggleTitle{\n    font-weight: 950;\n    margin: 0;\n  }\n  .toggleText{\n    margin: 4px 0 0 0;\n    color: var(--muted);\n    font-size: 13px;\n    line-height: 1.4;\n  }\n\n  \/* --- Confetti (end screen) --- *\/\n  .celebrateWrap{\n    margin-top: 6px;\n  }\n  .trophy{\n    font-size: 42px;\n    line-height: 1;\n    margin: 6px 0 2px 0;\n    filter: drop-shadow(0 12px 22px rgba(15,23,42,.18));\n  }\n  .confetti{\n    position: relative;\n    width: 100%;\n    height: 90px;\n    margin: 6px auto 0 auto;\n    overflow: hidden;\n    pointer-events: none;\n  }\n  .confettiPiece{\n    position:absolute;\n    top: -14px;\n    width: 10px;\n    height: 16px;\n    border-radius: 2px;\n    opacity: .95;\n    transform: rotate(0deg);\n    animation: confettiFall 1200ms ease-in forwards;\n  }\n  @keyframes confettiFall{\n    0% { transform: translateY(-10px) rotate(0deg); opacity: .95; }\n    100% { transform: translateY(120px) rotate(520deg); opacity: 1; }\n  }\n\n  .endThumbWrap{\n    margin: 12px auto 6px auto;\n    max-width: 520px;\n    width: 100%;\n    aspect-ratio: 16 \/ 9;\n    border-radius: 16px;\n    overflow: hidden;\n    border: 1px solid var(--border);\n    background: #fff;\n  }\n  .endThumbWrap img{\n    width: 100% !important;\n    height: 100% !important;\n    object-fit: cover !important;\n    display: block !important;\n  }\n  .infoBox{\n    margin: 12px auto 0 auto;\n    max-width: 720px;\n    text-align: center;\n    padding: 12px 12px;\n    border-radius: 14px;\n    border: 1px solid var(--border);\n    background: #fff;\n    color: var(--text);\n    font-size: 13px;\n    line-height: 1.45;\n  }\n  .infoBox strong{ color: var(--text); }\n  .infoTitle{\n    font-weight: 950;\n    font-size: 15px;\n    margin-top: 8px;\n    margin-bottom: 4px;\n  }\n  .infoText{\n    margin: 0 auto;\n    max-width: 640px;\n  }\n\n  \/* --- Loading \u201ctema-bilder\u201d --- *\/\n  #quizbox .loadingThumbs{\n    margin: 10px 0 6px 0;\n    display: inline-flex;\n    gap: 10px;\n    align-items: center;\n    justify-content: center;\n    flex-wrap: wrap;\n    user-select: none;\n    line-height: 1;\n  }\n  #quizbox .loadingThumbs img{\n    width: 46px !important;\n    height: 46px !important;\n    border-radius: 14px;\n    object-fit: cover !important;\n    display: block !important;\n    padding: 0 !important;\n    margin: 0 !important;\n    border: 1px solid rgba(124,58,237,.18);\n    box-shadow: 0 10px 18px rgba(15,23,42,.12);\n    --thumbScale: 1;\n    transform: translateY(0) scale(var(--thumbScale));\n    animation: emojiBounce 900ms ease-in-out infinite;\n  }\n  \/* nk-bildene kan ha \u201cinnebygd\u201d luft \u2192 zoom litt inn (uten \u00e5 \u00f8delegge bounce-animasjonen) *\/\n  #quizbox .loadingThumbs img[data-news-decor=\"1\"]{ --thumbScale: 1.12; }\n  #quizbox .loadingThumbs img:nth-child(2){ animation-delay: 120ms; }\n  #quizbox .loadingThumbs img:nth-child(3){ animation-delay: 240ms; }\n  \/* Mini variant for \u201clager sp\u00f8rsm\u00e5l\u2026\u201d *\/\n  #quizbox .loadingThumbs.mini{\n    margin: 8px 0 0 0;\n    gap: 8px;\n  }\n  #quizbox .loadingThumbs.mini img{\n    width: 28px !important;\n    height: 28px !important;\n    border-radius: 10px;\n  }\n  @keyframes emojiBounce{\n    0%, 100% { transform: translateY(0) scale(var(--thumbScale)); opacity: .9; }\n    45% { transform: translateY(-7px) scale(calc(var(--thumbScale) * 1.08)); opacity: 1; }\n    70% { transform: translateY(-2px) scale(calc(var(--thumbScale) * 1.02)); }\n  }\n\n  \/* --- Mobile friendliness --- *\/\n  @media (max-width: 520px){\n    #quizbox{ padding: 10px; border-radius: 14px; }\n\n    #quizbox h3{\n      font-size: 20px;\n      padding: 8px 10px;\n    }\n    \/* Hold badge\/poeng p\u00e5 \u00e9n linje (scroll om n\u00f8dvendig) *\/\n    .topMetaRow{\n      margin: 6px auto 10px auto;\n      flex-wrap: nowrap;\n      justify-content: center;\n      overflow-x: auto;\n      -webkit-overflow-scrolling: touch;\n      gap: 8px;\n      padding-bottom: 4px; \/* litt luft for evt scrollbar *\/\n    }\n    .topMetaRow::-webkit-scrollbar{ height: 6px; }\n    .topMetaRow::-webkit-scrollbar-thumb{\n      background: rgba(124,58,237,.22);\n      border-radius: 999px;\n    }\n    .topMetaPill{\n      width: auto;\n      flex: 0 0 auto;\n      justify-content: center;\n      font-size: 11px;\n      padding: 6px 9px;\n      white-space: nowrap;\n    }\n\n    .panel{ padding: 14px !important; border-radius: 14px; }\n\n    .row{ gap: 10px; }\n    .col{ min-width: 0; }\n\n    .articleCard{\n      flex-direction: column !important;\n      align-items: stretch;\n    }\n\n    .thumbWrap{\n      width: 100% !important;\n      border-radius: 14px;\n    }\n    .thumbWrap.isSquareThumb{\n      width: min(360px, 100%) !important;\n      margin-left: auto;\n      margin-right: auto;\n    }\n    .thumbWrap.thumbWrapSmall{\n      width: 100% !important;\n    }\n    \/* h\u00f8yden styres av aspect-ratio p\u00e5 wrapperen *\/\n    .articleMeta{ min-width: 0 !important; }\n\n    \/* On narrow screens: thumbnail should be between title and summary *\/\n    .thumbDesktop{ display:none !important; }\n    .thumbMobile{ display:block !important; }\n\n    .articleTitle{ font-size: 16px; }\n    .articleSummary{ font-size: 14px; -webkit-line-clamp: 4; line-clamp: 4; }\n\n    .btnRow{\n      flex-direction: column;\n      gap: 10px;\n    }\n    .btn{\n      width: 100%;\n      padding: 12px 14px;\n      border-radius: 14px;\n    }\n\n    .qHeader{ margin-bottom: 12px; }\n    .qText{ font-size: 17px; }\n\n    .choices{\n      max-width: 100%;\n      gap: 10px;\n    }\n    .choiceBtn{\n      min-height: 58px;\n      padding: 12px 12px;\n      border-radius: 14px;\n      font-size: 16px;\n    }\n  }\n<\/style>\n\n<div id=\"quizbox\">\n  <h3 id=\"quizTitle\">Ta en KvIz<\/h3>\n  <div class=\"topMetaRow\" id=\"dailyBadgeRow\" aria-live=\"polite\">\n    <span class=\"topMetaPill\" id=\"dailyPointsPill\" tabindex=\"0\" role=\"button\" aria-label=\"Dine poeng (trykk for forklaring)\">\u2b50 <strong id=\"dailyPoints\">0<\/strong><\/span>\n    <span class=\"topMetaPill\" id=\"dailyBadgePill\" tabindex=\"0\" role=\"button\" aria-label=\"Din badge (trykk for forklaring)\"><strong id=\"dailyBadge\">\u2014<\/strong><\/span>\n    <span class=\"topMetaPill\" id=\"dailyNextPill\" tabindex=\"0\" role=\"button\" aria-label=\"Neste badge (trykk for forklaring)\">\u27a1\ufe0f <strong id=\"dailyNext\">10<\/strong><\/span>\n  <\/div>\n\n  <div id=\"loadingPanel\" class=\"panel\">\n    <div class=\"center\">\n      <div style=\"font-weight:800;\">Henter sak og lager KvIz ...<\/div>\n      <div class=\"loadingThumbs\" aria-hidden=\"true\">\n        <img decoding=\"async\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/kunnskaper.jpg\" alt=\"\" \/>\n        <img data-news-decor=\"1\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/nk01.jpg\" loading=\"eager\" decoding=\"async\" alt=\"\" \/>\n        <img decoding=\"async\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/statistikk.jpg\" alt=\"\" \/>\n        <img decoding=\"async\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/forskning.jpg\" alt=\"\" \/>\n      <\/div>\n      <div class=\"small\" id=\"loadingSub\">Dette tar vanligvis noen sekunder.<\/div>\n      <div class=\"infoBox\" role=\"note\" aria-label=\"Om denne KvIzen\">\n        <div class=\"infoTitle\">Hva er dette?<\/div>\n        <div class=\"infoText\">Du f\u00e5r en liten KvIz med 3 sp\u00f8rsm\u00e5l om en sak.<\/div>\n\n        <div class=\"infoTitle\">Hvordan lages den?<\/div>\n        <div class=\"infoText\">\n          En KI lager et kort <strong>KI-sammendrag<\/strong> av saken og lager sp\u00f8rsm\u00e5l med svaralternativer.\n          Noen ganger kan det bli feil \u2013 derfor kan du trykke <strong>\"Les hele saken\"<\/strong> og sjekke kilden selv.\n        <\/div>\n\n        <div class=\"infoTitle\">Hvor kommer innholdet fra?<\/div>\n        <div class=\"infoText\">\n          Saker hentes fra \u00e5pne kilder som for eksempel <strong>Nettavisen<\/strong>, <strong>Teknisk Ukeblad<\/strong>, <strong>SSB<\/strong>, <strong>BBC News<\/strong>, <strong>UN News<\/strong>, <strong>NASA<\/strong> og <strong>Wikipedia<\/strong>.\n          Lenken \u00e5pnes i en ny fane, s\u00e5 KvIzen blir ikke borte.\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <div id=\"startPanel\" class=\"panel hidden\">\n    <div class=\"articleCard\">\n      <!-- Desktop placement -->\n      <div class=\"thumbWrap thumbDesktop\" id=\"articleThumbWrap\">\n        <a id=\"articleLinkThumb\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <img id=\"articleThumb\" class=\"thumb\" alt=\"\" \/>\n        <\/a>\n      <\/div>\n      <div class=\"articleMeta\">\n        <span class=\"sourcePill\"><a id=\"articleSourceLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">Kilde<\/a><\/span>\n        <div class=\"articleTitle\">\n          <a id=\"articleLinkTitle\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><\/a>\n        <\/div>\n        <!-- Mobile placement (between title and summary) -->\n        <div class=\"thumbWrap thumbMobile\" id=\"articleThumbWrapMobile\">\n          <a id=\"articleLinkThumbMobile\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <img id=\"articleThumbMobile\" class=\"thumb\" alt=\"\" \/>\n          <\/a>\n        <\/div>\n        <div class=\"summaryTitle\" aria-hidden=\"true\">KI-sammendrag<\/div>\n        <div class=\"articleSummary\" id=\"articleSummary\"><\/div>\n        <div class=\"summaryMeta\" id=\"articleSummaryMeta\"><\/div>\n        <div class=\"readMoreRow\">\n          <a id=\"readMoreLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><strong>Les hele saken<\/strong><\/a>\n          <div class=\"readMoreNote\">(\u00c5pnes i egen fane)<\/div>\n        <\/div>\n        <div class=\"imgCreditRow isHidden\" id=\"articleImgCreditRow\">\n          Foto: <a id=\"articleImgCreditLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><span id=\"articleImgCredit\"><\/span><\/a>\n        <\/div>\n\n        <div class=\"btnRow\">\n          <button class=\"btn primary\" id=\"startBtn\">Start KvIz<\/button>\n          <button class=\"btn\" id=\"anotherBtn\">Velg en annen sak<\/button>\n        <\/div>\n        <div id=\"qGenRow\" class=\"hidden center\" style=\"margin-top:10px;\">\n          <div class=\"small\" id=\"qGenText\">Lager sp\u00f8rsm\u00e5l\u2026<\/div>\n          <div class=\"loadingThumbs mini\" aria-hidden=\"true\">\n            <img data-news-decor=\"1\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/nk01.jpg\" loading=\"eager\" decoding=\"async\" alt=\"\" \/>\n            <img decoding=\"async\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/kunnskaper.jpg\" alt=\"\" \/>\n            <img decoding=\"async\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/statistikk.jpg\" alt=\"\" \/>\n            <img decoding=\"async\" src=\"https:\/\/gruble.net\/wp-content\/uploads\/forskning.jpg\" alt=\"\" \/>\n          <\/div>\n        <\/div>\n        <div class=\"toggleRow\" role=\"note\" aria-label=\"Bonusmodus\">\n          <label>\n            <input type=\"checkbox\" id=\"hardModeToggle\" \/>\n            <div>\n              <div class=\"toggleTitle\">Bonusmodus: Ta KvIzen uten hjelp<\/div>\n              <div class=\"toggleText\">\n                Skjuler sammendraget og alle \u201cLES MER\u201d\/artikkel-lenker f\u00f8r du starter.\n                Du f\u00e5r <strong>+1 bonuspoeng per sp\u00f8rsm\u00e5l<\/strong> du svarer riktig p\u00e5.\n                F\u00e5r du <strong>alt riktig p\u00e5 f\u00f8rste fors\u00f8k<\/strong>, f\u00e5r du <strong>+1 ekstra<\/strong> p\u00e5 slutten (maks <strong>10<\/strong> poeng).\n              <\/div>\n            <\/div>\n          <\/label>\n        <\/div>\n        <div class=\"statusLine\">\n          <span><strong>3<\/strong> oppgaver<\/span>\n          <span><strong>3<\/strong> fors\u00f8k per oppgave<\/span>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <div id=\"questionPanel\" class=\"panel hidden\">\n    <div class=\"qHeader\">\n      <div class=\"kicker\" id=\"progressText\">Oppgave 1\/3<\/div>\n      <div class=\"kicker\">Poeng: <strong id=\"scoreText\">0<\/strong><\/div>\n    <\/div>\n\n    <div class=\"row\" style=\"margin-bottom:12px;\">\n      <div class=\"col\">\n        <div class=\"articleCard\" style=\"align-items:flex-start;\">\n          <!-- Desktop placement -->\n          <div class=\"thumbWrap thumbWrapSmall thumbDesktop\" id=\"qArticleThumbWrap\">\n            <a id=\"qArticleLinkThumb\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">\n              <img id=\"qArticleThumb\" class=\"thumb\" alt=\"\" \/>\n            <\/a>\n          <\/div>\n          <div class=\"articleMeta\">\n            <span class=\"sourcePill\"><a id=\"qArticleSourceLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">Kilde<\/a><\/span>\n            <div class=\"articleTitle\" style=\"font-size:16px;\">\n              <a id=\"qArticleLinkTitle\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><\/a>\n            <\/div>\n            <!-- Mobile placement (between title and summary) -->\n            <div class=\"thumbWrap thumbMobile\" id=\"qArticleThumbWrapMobile\">\n              <a id=\"qArticleLinkThumbMobile\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">\n                <img id=\"qArticleThumbMobile\" class=\"thumb\" alt=\"\" \/>\n              <\/a>\n            <\/div>\n            <div class=\"summaryTitle\" aria-hidden=\"true\">KI-sammendrag<\/div>\n            <div class=\"articleSummary\" id=\"qArticleSummary\"><\/div>\n            <div class=\"summaryMeta\" id=\"qArticleSummaryMeta\"><\/div>\n            <div class=\"readMoreRow\">\n              <a id=\"qReadMoreLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><strong>LES HELE SAKEN<\/strong><\/a>\n              <div class=\"readMoreNote\">(\u00c5pnes i egen fane)<\/div>\n            <\/div>\n            <div class=\"imgCreditRow isHidden\" id=\"qImgCreditRow\">\n              Foto: <a id=\"qImgCreditLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><span id=\"qImgCredit\"><\/span><\/a>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"qaArea\">\n      <p class=\"qText\" id=\"qText\"><\/p>\n      <div class=\"choices\" id=\"choices\"><\/div>\n      <div class=\"btnRow center\" style=\"margin-top:12px;\">\n        <button class=\"btn primary hidden\" id=\"nextBtn\">Neste<\/button>\n      <\/div>\n      <div class=\"explain hidden\" id=\"explain\"><\/div>\n    <\/div>\n\n    <div class=\"btnRow center\" style=\"margin-top:12px;\">\n      <button class=\"btn danger small hidden\" id=\"quitBtn\">Avslutt<\/button>\n    <\/div>\n    <div class=\"aiNote\" style=\"margin-top:12px;\"><strong>Merk:<\/strong> KI kan gj\u00f8re feil n\u00e5r den lager alternativer.<\/div>\n  <\/div>\n\n  <div id=\"endPanel\" class=\"panel hidden\">\n    <div class=\"center\">\n      <div style=\"font-weight:900;font-size:20px;\">Ferdig!<\/div>\n      <div class=\"celebrateWrap hidden\" id=\"celebrateWrap\" aria-live=\"polite\">\n        <div class=\"trophy\" aria-hidden=\"true\">\ud83c\udfc6<\/div>\n        <div id=\"celebrateText\" style=\"font-weight:900;\">Helt perfekt!<\/div>\n        <div class=\"confetti\" id=\"confetti\" aria-hidden=\"true\"><\/div>\n      <\/div>\n      <div class=\"endThumbWrap\" aria-hidden=\"true\">\n        <img id=\"endThumb\" alt=\"\" \/>\n      <\/div>\n      <div class=\"readMoreRow center\" style=\"margin-top:10px;\">\n        <a id=\"endReadMoreLink\" href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\"><strong>LES SAKEN<\/strong><\/a>\n        <div class=\"readMoreNote\">(\u00c5pnes i egen fane)<\/div>\n      <\/div>\n      <div class=\"bigScore\"><span id=\"finalScore\">0<\/span> poeng<\/div>\n      <div class=\"small\" id=\"finalMeta\"><\/div>\n      <div class=\"infoBox\" style=\"margin-top:12px;\">\n        <div class=\"infoTitle\">Din badge<\/div>\n        <div class=\"infoText\">\n          Du har n\u00e5 <strong id=\"endDailyPoints\">0<\/strong> poeng totalt og badge: <strong id=\"endDailyBadge\">Ingen enn\u00e5<\/strong>.\n          <span id=\"endDailyNextWrap\">Neste badge ved <strong id=\"endDailyNext\">10<\/strong> poeng.<\/span>\n        <\/div>\n      <\/div>\n      <div class=\"btnRow\" style=\"justify-content:center;margin-top:14px;\">\n        <button class=\"btn primary\" id=\"newQuizBtn\">Ny KvIz<\/button>\n        <button class=\"btn\" id=\"retryBtn\">Pr\u00f8v samme KvIz igjen<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<div class=\"modalBackdrop hidden\" id=\"badgeModal\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Badge og poeng\">\n  <div class=\"modalCard\">\n    <div class=\"modalHeader\">\n      <div>\n        <div class=\"modalTitle\" id=\"badgeModalTitle\">Din badge<\/div>\n      <\/div>\n      <button class=\"modalClose\" id=\"badgeModalClose\" type=\"button\">Lukk<\/button>\n    <\/div>\n    <div class=\"badgeBig\">\n      <div class=\"badgeIcon\" id=\"badgeModalIcon\" aria-hidden=\"true\">\ud83c\udfc1<\/div>\n      <div>\n        <div class=\"badgeName\" id=\"badgeModalName\">Ingen enn\u00e5<\/div>\n        <div class=\"modalBody\" id=\"badgeModalSub\"><\/div>\n      <\/div>\n    <\/div>\n    <div class=\"modalBody\" id=\"badgeModalBody\"><\/div>\n  <\/div>\n<\/div>\n\n<script>\n  \/\/ Endepunktet der PHP-en faktisk ligger hos deg.\n  \/\/ Hvis denne HTML-en lastes fra samme mappe som newsquiz.php, vil fallbacken (new URL('newsquiz.php', ...))\n  \/\/ ogs\u00e5 fungere uten at du m\u00e5 endre noe.\n  const QUIZ_ENDPOINT = '\/games\/nyhetsquiz\/newsquiz.php';\n  const NEWS_DECOR_THUMBS = Array.from({ length: 9 }, (_, i) => {\n    const n = String(i + 1).padStart(2, '0');\n    return `https:\/\/gruble.net\/wp-content\/uploads\/nk${n}.jpg`;\n  });\n  const DEFAULT_THUMBS = {\n    knowledge: 'https:\/\/gruble.net\/wp-content\/uploads\/kunnskaper.jpg',\n    news: 'https:\/\/gruble.net\/wp-content\/uploads\/nyheter-1.jpg',\n    stats: 'https:\/\/gruble.net\/wp-content\/uploads\/statistikk.jpg',\n    research: 'https:\/\/gruble.net\/wp-content\/uploads\/forskning.jpg',\n  };\n\n  function pickNewsDecorThumb(seed) {\n    const arr = NEWS_DECOR_THUMBS;\n    if (!arr || !arr.length) return DEFAULT_THUMBS.news;\n    if (!seed) return arr[Math.floor(Math.random() * arr.length)];\n    let h = 0;\n    for (let i = 0; i < seed.length; i++) h = ((h << 5) - h) + seed.charCodeAt(i);\n    const idx = Math.abs(h) % arr.length;\n    return arr[idx];\n  }\n\n  function applyNewsDecorThumb(seed) {\n    const src = pickNewsDecorThumb(seed);\n    document.querySelectorAll('img[data-news-decor=\"1\"]').forEach(img => {\n      if (!img) return;\n      img.src = src;\n    });\n  }\n\n  async function fetchWithTimeout(url, options = {}, timeoutMs = 45000) {\n    const ctrl = new AbortController();\n    const t = setTimeout(() => ctrl.abort(), Math.max(1, timeoutMs | 0));\n    try {\n      const res = await fetch(url, { ...options, signal: ctrl.signal });\n      const text = await res.text();\n      return { res, text };\n    } finally {\n      clearTimeout(t);\n    }\n  }\n\n  const els = {\n    quizTitle: document.getElementById('quizTitle'),\n    dailyBadgeRow: document.getElementById('dailyBadgeRow'),\n    dailyPointsPill: document.getElementById('dailyPointsPill'),\n    dailyBadgePill: document.getElementById('dailyBadgePill'),\n    dailyNextPill: document.getElementById('dailyNextPill'),\n    dailyPoints: document.getElementById('dailyPoints'),\n    dailyBadge: document.getElementById('dailyBadge'),\n    dailyNext: document.getElementById('dailyNext'),\n    articleThumbWrap: document.getElementById('articleThumbWrap'),\n    loadingPanel: document.getElementById('loadingPanel'),\n    loadingSub: document.getElementById('loadingSub'),\n    startPanel: document.getElementById('startPanel'),\n    questionPanel: document.getElementById('questionPanel'),\n    endPanel: document.getElementById('endPanel'),\n\n    articleThumb: document.getElementById('articleThumb'),\n    articleLinkThumb: document.getElementById('articleLinkThumb'),\n    articleThumbWrapMobile: document.getElementById('articleThumbWrapMobile'),\n    articleThumbMobile: document.getElementById('articleThumbMobile'),\n    articleLinkThumbMobile: document.getElementById('articleLinkThumbMobile'),\n    articleLinkTitle: document.getElementById('articleLinkTitle'),\n    articleSourceLink: document.getElementById('articleSourceLink'),\n    articleSummary: document.getElementById('articleSummary'),\n    articleSummaryMeta: document.getElementById('articleSummaryMeta'),\n    readMoreLink: document.getElementById('readMoreLink'),\n    qReadMoreLink: document.getElementById('qReadMoreLink'),\n    articleImgCreditRow: document.getElementById('articleImgCreditRow'),\n    articleImgCredit: document.getElementById('articleImgCredit'),\n    articleImgCreditLink: document.getElementById('articleImgCreditLink'),\n    qImgCreditRow: document.getElementById('qImgCreditRow'),\n    qImgCredit: document.getElementById('qImgCredit'),\n    qImgCreditLink: document.getElementById('qImgCreditLink'),\n\n    startBtn: document.getElementById('startBtn'),\n    anotherBtn: document.getElementById('anotherBtn'),\n    hardModeToggle: document.getElementById('hardModeToggle'),\n    qGenRow: document.getElementById('qGenRow'),\n    qGenText: document.getElementById('qGenText'),\n\n    qArticleThumb: document.getElementById('qArticleThumb'),\n    qArticleThumbWrap: document.getElementById('qArticleThumbWrap'),\n    qArticleThumbWrapMobile: document.getElementById('qArticleThumbWrapMobile'),\n    qArticleThumbMobile: document.getElementById('qArticleThumbMobile'),\n    qArticleLinkThumbMobile: document.getElementById('qArticleLinkThumbMobile'),\n    qArticleLinkThumb: document.getElementById('qArticleLinkThumb'),\n    qArticleLinkTitle: document.getElementById('qArticleLinkTitle'),\n    qArticleSourceLink: document.getElementById('qArticleSourceLink'),\n    qArticleSummary: document.getElementById('qArticleSummary'),\n    qArticleSummaryMeta: document.getElementById('qArticleSummaryMeta'),\n\n    progressText: document.getElementById('progressText'),\n    scoreText: document.getElementById('scoreText'),\n\n    qText: document.getElementById('qText'),\n    choices: document.getElementById('choices'),\n    explain: document.getElementById('explain'),\n\n    nextBtn: document.getElementById('nextBtn'),\n    quitBtn: document.getElementById('quitBtn'),\n\n    finalScore: document.getElementById('finalScore'),\n    finalMeta: document.getElementById('finalMeta'),\n    endThumb: document.getElementById('endThumb'),\n    celebrateWrap: document.getElementById('celebrateWrap'),\n    celebrateText: document.getElementById('celebrateText'),\n    confetti: document.getElementById('confetti'),\n    endReadMoreLink: document.getElementById('endReadMoreLink'),\n    endDailyPoints: document.getElementById('endDailyPoints'),\n    endDailyBadge: document.getElementById('endDailyBadge'),\n    endDailyNext: document.getElementById('endDailyNext'),\n    endDailyNextWrap: document.getElementById('endDailyNextWrap'),\n    newQuizBtn: document.getElementById('newQuizBtn'),\n    retryBtn: document.getElementById('retryBtn'),\n    badgeModal: document.getElementById('badgeModal'),\n    badgeModalClose: document.getElementById('badgeModalClose'),\n    badgeModalTitle: document.getElementById('badgeModalTitle'),\n    badgeModalIcon: document.getElementById('badgeModalIcon'),\n    badgeModalName: document.getElementById('badgeModalName'),\n    badgeModalSub: document.getElementById('badgeModalSub'),\n    badgeModalBody: document.getElementById('badgeModalBody'),\n  };\n\n  const state = {\n    quiz: null,\n    idx: 0,\n    score: 0,\n    attempt: 1,\n    disabled: new Set(),\n    finishedCurrent: false,\n    hardMode: false,\n    perfectRun: true, \/\/ true s\u00e5 lenge alt er riktig p\u00e5 f\u00f8rste fors\u00f8k\n    \/\/ history of pageids (optional, best-effort)\n    excludeIds: [],\n  };\n\n  const PROGRESS_KEY = 'gruble.kviz.progress.v2';\n  const LEGACY_DAILY_KEY = 'gruble.kviz.daily.v1';\n  const SEEN_ARTICLES_KEY = 'gruble.kviz.seenArticles.v1';\n\n  function localDateKey() {\n    const d = new Date();\n    const y = d.getFullYear();\n    const m = String(d.getMonth() + 1).padStart(2, '0');\n    const day = String(d.getDate()).padStart(2, '0');\n    return `${y}-${m}-${day}`;\n  }\n\n  function loadSeenArticles() {\n    const today = localDateKey();\n    try {\n      const raw = localStorage.getItem(SEEN_ARTICLES_KEY);\n      if (!raw) return { date: today, ids: [] };\n      const data = JSON.parse(raw);\n      if (!data || data.date !== today) return { date: today, ids: [] };\n      const ids = Array.isArray(data.ids) ? data.ids.filter(x => typeof x === 'string' && x.trim()) : [];\n      return { date: today, ids };\n    } catch (_) {\n      return { date: today, ids: [] };\n    }\n  }\n\n  function saveSeenArticles(obj) {\n    try {\n      localStorage.setItem(SEEN_ARTICLES_KEY, JSON.stringify(obj));\n    } catch (_) {}\n  }\n\n  function rememberSeenArticleId(articleId) {\n    const id = (articleId ?? '').toString().trim();\n    if (!id) return;\n    const data = loadSeenArticles();\n    const s = new Set((data.ids || []).slice(-800));\n    s.add(id);\n    const out = { date: data.date, ids: Array.from(s).slice(-800) };\n    saveSeenArticles(out);\n    return out;\n  }\n\n  function badgeStepForPoints(points) {\n    const p = Math.max(0, Number(points) || 0);\n    if (p < 100) return 10;\n    if (p < 1000) return 100;\n    \/\/ Etter 1000: skaler med st\u00f8rrelsesorden (1000\u21922000, 9000\u219210000, 12000\u219220000, osv.)\n    const mag = Math.pow(10, Math.floor(Math.log10(Math.max(1000, p))));\n    return mag;\n  }\n\n  const BADGES = [\n    { points: 10,  name: 'Avis-spiren', icon: '\ud83d\uddde\ufe0f' },\n    { points: 20,  name: 'Fakta-finner', icon: '\ud83d\udd0e' },\n    { points: 30,  name: 'Overskriftsjeger', icon: '\ud83d\udcf0' },\n    { points: 40,  name: 'Kildekritisk katt', icon: '\ud83d\udc3e' },\n    { points: 50,  name: 'Nyhetsninja', icon: '\ud83e\udd77' },\n    { points: 60,  name: 'Statistikk-speider', icon: '\ud83d\udcca' },\n    { points: 70,  name: 'Kunnskapskaptein', icon: '\ud83e\udde0' },\n    { points: 80,  name: 'Forklaringsflamme', icon: '\ud83d\udd25' },\n    { points: 90,  name: 'Redakt\u00f8r-rakett', icon: '\ud83d\ude80' },\n    { points: 100, name: 'Toppnytt-trof\u00e9', icon: '\ud83c\udfc6' },\n    { points: 200, name: 'Kommentator-komet', icon: '\u2604\ufe0f' },\n    { points: 300, name: 'Analyse-arkitekt', icon: '\ud83e\uddf1' },\n    { points: 400, name: 'Data-detektiv', icon: '\ud83d\udd75\ufe0f' },\n    { points: 500, name: 'Fakta-fyrste', icon: '\ud83d\udc51' },\n    { points: 600, name: 'Kildekompass', icon: '\ud83e\udded' },\n    { points: 700, name: 'Verdensvakt', icon: '\ud83c\udf0d' },\n    { points: 800, name: 'Ekspert-lyn', icon: '\u26a1' },\n    { points: 900, name: 'Nyhetsorakel', icon: '\ud83d\udd2e' },\n    { points: 1000, name: 'Kunnskapslegende', icon: '\ud83c\udfdb\ufe0f' },\n  ];\n\n  const EXTRA_BADGE_ICONS = ['\ud83c\udfdb\ufe0f','\ud83c\udf1f','\ud83d\ude80','\ud83d\udc51','\ud83e\udde0','\u26a1','\ud83d\udd2e','\ud83c\udf0d','\ud83d\uddde\ufe0f','\ud83d\udcda','\ud83c\udfc6','\ud83d\udef0\ufe0f','\ud83e\udded','\ud83d\udd25','\u2604\ufe0f','\ud83d\udd75\ufe0f'];\n\n  function formatPointsShort(n) {\n    const p = Math.max(0, Number(n) || 0);\n    if (p >= 1_000_000_000) return `${(p \/ 1_000_000_000).toFixed(p % 1_000_000_000 === 0 ? 0 : 1)}B`;\n    if (p >= 1_000_000) return `${(p \/ 1_000_000).toFixed(p % 1_000_000 === 0 ? 0 : 1)}M`;\n    if (p >= 10_000) return `${Math.round(p \/ 1000)}k`;\n    if (p >= 1000) return `${(p \/ 1000).toFixed(p % 1000 === 0 ? 0 : 1)}k`;\n    return String(p);\n  }\n\n  function currentBadgeThreshold(points) {\n    const p = Math.max(0, Number(points) || 0);\n    if (p < 10) return 0;\n    const step = badgeStepForPoints(p);\n    const thr = Math.floor(p \/ step) * step;\n    return Math.max(0, thr);\n  }\n\n  function badgeRankForThreshold(threshold) {\n    const th = Math.max(0, Number(threshold) || 0);\n    if (th <= 0) return 0;\n    \/\/ Base-rank: BADGES dekker opp til 1000 (19 badges).\n    if (th <= 1000) {\n      let r = 0;\n      for (const b of BADGES) {\n        if (th >= b.points) r += 1;\n      }\n      return r;\n    }\n    \/\/ Etter 1000: tell \"badges\" per st\u00f8rrelsesorden.\n    \/\/ 2000..9000 (8 steg), 10000..90000 (9 steg), 100000..900000 (9 steg), osv.\n    let extra = 0;\n    let step = 1000;\n    while (step < badgeStepForPoints(th)) {\n      extra += (step === 1000) ? 8 : 9;\n      step *= 10;\n    }\n    const curStep = badgeStepForPoints(th);\n    const n = Math.floor(th \/ curStep); \/\/ 1..9\n    extra += (curStep === 1000) ? Math.max(0, n - 1) : n;\n    return BADGES.length + extra;\n  }\n\n  function extendedBadgeForPoints(points) {\n    const p = Math.max(0, Number(points) || 0);\n    if (p < 10) return null;\n\n    const thr = currentBadgeThreshold(p);\n    \/\/ Under\/lik 1000: bruk de definerte navnene.\n    if (thr <= 1000) {\n      return badgeForPoints(p);\n    }\n\n    const rank = badgeRankForThreshold(thr);\n    const icon = EXTRA_BADGE_ICONS[(Math.max(1, rank) - 1) % EXTRA_BADGE_ICONS.length];\n    return {\n      points: thr,\n      icon,\n      name: `Kunnskapslegende ${formatPointsShort(thr)}`,\n    };\n  }\n\n  function loadProgress() {\n    try {\n      const raw = localStorage.getItem(PROGRESS_KEY);\n      if (!raw) throw new Error('no-progress');\n      const data = JSON.parse(raw);\n      if (!data) throw new Error('bad-progress');\n      return {\n        points: Number.isFinite(data.points) ? data.points : 0,\n        claimedQuizIds: Array.isArray(data.claimedQuizIds) ? data.claimedQuizIds.filter(x => typeof x === 'string') : [],\n      };\n    } catch (_) {\n      \/\/ Migrer fra gammel \"daglig\" lagring (hvis den finnes), og g\u00e5 over til permanent progresjon.\n      try {\n        const legacyRaw = localStorage.getItem(LEGACY_DAILY_KEY);\n        if (legacyRaw) {\n          const legacy = JSON.parse(legacyRaw);\n          const pts = Number.isFinite(legacy?.bestPoints) ? legacy.bestPoints\n            : (Number.isFinite(legacy?.points) ? legacy.points : 0);\n          const claimed = Array.isArray(legacy?.claimedQuizIds) ? legacy.claimedQuizIds.filter(x => typeof x === 'string') : [];\n          const out = { points: Math.max(0, pts), claimedQuizIds: claimed.slice(-1200) };\n          saveProgress(out);\n          return out;\n        }\n      } catch (_) {}\n      return { points: 0, claimedQuizIds: [] };\n    }\n  }\n\n  function saveProgress(p) {\n    try {\n      localStorage.setItem(PROGRESS_KEY, JSON.stringify(p));\n    } catch (_) {}\n  }\n\n  function badgeForPoints(points) {\n    let best = null;\n    for (const b of BADGES) {\n      if (points >= b.points) best = b;\n    }\n    if (best) return best;\n    return null;\n  }\n\n  function nextBadgePoints(points) {\n    const p = Math.max(0, Number(points) || 0);\n    const step = badgeStepForPoints(p);\n    const next = Math.ceil((p + 1) \/ step) * step;\n    return Number.isFinite(next) ? next : null;\n  }\n\n  function renderBadgeUI(points) {\n    const best = extendedBadgeForPoints(points);\n    const next = nextBadgePoints(points);\n    if (els.dailyPoints) els.dailyPoints.textContent = String(points);\n    if (els.dailyBadge) {\n      els.dailyBadge.textContent = best ? `${best.icon}` : '\u2014';\n    }\n    if (els.dailyNext) {\n      els.dailyNext.textContent = next ? String(next) : '\u2014';\n    }\n\n    if (els.endDailyPoints) els.endDailyPoints.textContent = String(points);\n    if (els.endDailyBadge) els.endDailyBadge.textContent = best ? `${best.icon} ${best.name}` : 'Ingen enn\u00e5';\n    if (els.endDailyNext) els.endDailyNext.textContent = next ? String(next) : '\u2014';\n    if (els.endDailyNextWrap) {\n      els.endDailyNextWrap.style.display = next ? '' : 'none';\n    }\n  }\n\n  function openBadgeModal(focus) {\n    const p = loadProgress();\n    const best = extendedBadgeForPoints(p.points);\n    const next = nextBadgePoints(p.points);\n    if (!els.badgeModal) return;\n\n    if (els.badgeModalIcon) els.badgeModalIcon.textContent = best ? best.icon : '\ud83c\udfc1';\n    if (els.badgeModalName) els.badgeModalName.textContent = best ? best.name : 'Ingen badge enn\u00e5';\n    if (els.badgeModalTitle) els.badgeModalTitle.textContent = 'Dine poeng og badge';\n    if (els.badgeModalSub) {\n      els.badgeModalSub.textContent = `Du har ${p.points} poeng totalt. (Lagres, og nullstilles ikke.)`;\n    }\n    if (els.badgeModalBody) {\n      const nextText = next ? `Neste badge ved ${next} poeng.` : ``;\n      els.badgeModalBody.innerHTML =\n        `<strong>Slik funker det:<\/strong><br>` +\n        `- Hver gang du fullf\u00f8rer en ny KvIz, legges poengene til totalen din.<br>` +\n        `- Ny badge ved 10, 20, \u2026, 100 poeng.<br>` +\n        `- Etter 100: ny badge ved 200, 300, \u2026, 1000 poeng.<br>` +\n        `- Etter 1000 fortsetter badges i st\u00f8rre og st\u00f8rre steg (praktisk talt uten slutt).<br>` +\n        `- Samme KvIz teller bare \u00e9n gang.<br><br>` +\n        `<strong>N\u00e5:<\/strong> ${p.points} poeng. ${nextText}`;\n    }\n\n    els.badgeModal.classList.remove('hidden');\n    \/\/ focus close for accessibility\n    els.badgeModalClose?.focus?.();\n  }\n\n  function closeBadgeModal() {\n    if (!els.badgeModal) return;\n    els.badgeModal.classList.add('hidden');\n  }\n\n  function bindOpenModal(el) {\n    if (!el) return;\n    el.addEventListener('click', () => openBadgeModal());\n    el.addEventListener('keydown', (e) => {\n      if (e.key === 'Enter' || e.key === ' ') {\n        e.preventDefault();\n        openBadgeModal();\n      }\n    });\n  }\n\n  function addPoints(delta) {\n    const p = loadProgress();\n    const nextPoints = Math.max(0, (p.points || 0) + (delta || 0));\n    const out = {\n      points: nextPoints,\n      claimedQuizIds: p.claimedQuizIds || [],\n    };\n    saveProgress(out);\n    renderBadgeUI(out.points);\n    return out;\n  }\n\n  function claimPointsForQuiz(quizId, delta) {\n    const id = (quizId ?? '').toString().trim();\n    const p = loadProgress();\n    const claimed = new Set((p.claimedQuizIds || []).slice(-1200)); \/\/ cap size (permanent, men begrenset)\n    if (!id) {\n      \/\/ Hvis vi mangler quizId, faller vi tilbake til \u00e5 ikke registrere (sikrest mot dobbeltelling).\n      return { added: false, progress: p };\n    }\n    if (claimed.has(id)) {\n      return { added: false, progress: p };\n    }\n    claimed.add(id);\n    const out = addPoints(delta);\n    out.claimedQuizIds = Array.from(claimed).slice(-1200);\n    saveProgress(out);\n    return { added: true, progress: out };\n  }\n\n  function setLinkEnabled(a, enabled, url) {\n    if (!a) return;\n    if (enabled) {\n      \/\/ N\u00e5r vi skrur p\u00e5 igjen: bruk URL-en vi f\u00e5r inn (fra state) hvis den ser gyldig ut.\n      \/\/ Dette hindrer at vi \"restorer\" til n\u00e5v\u00e6rende KvIz-side pga initial href=\"#\".\n      const u = (url ?? '').toString().trim();\n      const restore = (u && u !== '#') ? u : (a.dataset.href || '#');\n      a.href = restore;\n      a.style.pointerEvents = '';\n      a.style.opacity = '';\n      a.removeAttribute('aria-disabled');\n      a.setAttribute('target', '_blank');\n      a.setAttribute('rel', 'noopener noreferrer');\n      return;\n    }\n    \/\/ disable\n    \/\/ N\u00e5r vi skrur av: lagre helst den eksplisitte url-en (hvis gitt), ikke a.href (som kan v\u00e6re \"#\" \u2192 KvIz-side).\n    const u = (url ?? '').toString().trim();\n    a.dataset.href = (u && u !== '#') ? u : (a.href || '');\n    a.href = '#';\n    a.style.pointerEvents = 'none';\n    a.style.opacity = '0.65';\n    a.setAttribute('aria-disabled', 'true');\n    a.removeAttribute('target');\n    a.removeAttribute('rel');\n  }\n\n  function applyHardModeUI(enabled) {\n    state.hardMode = Boolean(enabled);\n\n    \/\/ Skjul\/vis tekst (sammendrag + meta) p\u00e5 start og sp\u00f8rsm\u00e5l.\n    const startSummary = els.articleSummary;\n    const startMeta = els.articleSummaryMeta;\n    const qSummary = els.qArticleSummary;\n    const qMeta = els.qArticleSummaryMeta;\n    const startReadMoreRow = els.readMoreLink?.closest?.('.readMoreRow');\n    const qReadMoreRow = els.qReadMoreLink?.closest?.('.readMoreRow');\n\n    const show = !state.hardMode;\n    if (startSummary) startSummary.style.display = show ? '' : 'none';\n    if (startMeta) startMeta.style.display = show ? '' : 'none';\n    if (qSummary) qSummary.style.display = show ? '' : 'none';\n    if (qMeta) qMeta.style.display = show ? '' : 'none';\n    if (startReadMoreRow) startReadMoreRow.style.display = show ? '' : 'none';\n    if (qReadMoreRow) qReadMoreRow.style.display = show ? '' : 'none';\n\n    \/\/ Skjul\/disable alle artikkel-lenker i bonusmodus.\n    const url = state.quiz?.article?.url || '#';\n    setLinkEnabled(els.readMoreLink, show, url);\n    setLinkEnabled(els.qReadMoreLink, show, url);\n    setLinkEnabled(els.articleLinkTitle, show, url);\n    setLinkEnabled(els.qArticleLinkTitle, show, url);\n    setLinkEnabled(els.articleLinkThumb, show, url);\n    setLinkEnabled(els.qArticleLinkThumb, show, url);\n    setLinkEnabled(els.articleLinkThumbMobile, show, url);\n    setLinkEnabled(els.qArticleLinkThumbMobile, show, url);\n  }\n\n  function show(panel) {\n    els.loadingPanel.classList.add('hidden');\n    els.startPanel.classList.add('hidden');\n    els.questionPanel.classList.add('hidden');\n    els.endPanel.classList.add('hidden');\n    panel.classList.remove('hidden');\n  }\n\n  function scrollToQuizTop() {\n    const box = document.getElementById('quizbox');\n    const doScroll = (behavior) => {\n      if (!box) {\n        window.scrollTo({ top: 0, behavior });\n        return;\n      }\n      const top = box.getBoundingClientRect().top + window.scrollY;\n      const offset = 12; \/\/ litt luft fra toppen (sticky header-friendly)\n      window.scrollTo({ top: Math.max(0, top - offset), behavior });\n    };\n\n    \/\/ F\u00f8rst \u201csmooth\u201d for brukeren\u2026\n    doScroll('smooth');\n    \/\/ \u2026s\u00e5 en liten korrigering etter at DOM\/h\u00f8yder kan ha endret seg (typisk p\u00e5 mobil).\n    requestAnimationFrame(() => doScroll('auto'));\n    setTimeout(() => doScroll('auto'), 180);\n  }\n\n  function safeText(s) {\n    return (s ?? '').toString();\n  }\n\n  function homepageForSource(source) {\n    const s = (source || '').toString().toLowerCase();\n    if (s.includes('nettavisen')) return 'https:\/\/www.nettavisen.no\/';\n    if (s.includes('tu') || s.includes('tu.no') || s.includes('teknisk ukeblad')) return 'https:\/\/www.tu.no\/';\n    if (s.includes('ssb')) return 'https:\/\/www.ssb.no\/';\n    if (s.includes('bbc')) return 'https:\/\/www.bbc.com\/news';\n    if (s.includes('un news') || s === 'un' || s.includes('un ')) return 'https:\/\/news.un.org\/';\n    if (s.includes('nasa')) return 'https:\/\/www.nasa.gov\/';\n    if (s.includes('wikipedia')) return 'https:\/\/no.wikipedia.org\/';\n    if (s.includes('forskning')) return 'https:\/\/www.forskning.no\/';\n    return null;\n  }\n\n  function titleForSource(source) {\n    const s = (source || '').toString().toLowerCase();\n    if (s.includes('nettavisen')) return 'Ta en nyhetsKvIz';\n    if (s.includes('tu') || s.includes('tu.no') || s.includes('teknisk ukeblad')) return 'Ta en nyhetsKvIz';\n    if (s.includes('bbc')) return 'Ta en nyhetsKvIz';\n    if (s.includes('un news') || s === 'un' || s.includes('un ')) return 'Ta en nyhetsKvIz';\n    if (s === 'ssb' || s.includes('ssb')) return 'Ta en statistikk-KvIz';\n    if (s.includes('wikipedia')) return 'Ta en kunnskapsKvIz';\n    if (s.includes('nasa')) return 'Ta en kunnskapsKvIz';\n    if (s.includes('forskning')) return 'Ta en forskningsKvIz';\n    return 'Ta en KvIz';\n  }\n\n  function defaultThumbForSource(source) {\n    const s = (source || '').toString().toLowerCase();\n    if (s.includes('nettavisen')) return DEFAULT_THUMBS.news;\n    if (s.includes('tu') || s.includes('tu.no') || s.includes('teknisk ukeblad')) return DEFAULT_THUMBS.news;\n    if (s.includes('bbc')) return DEFAULT_THUMBS.news;\n    if (s.includes('un news') || s === 'un' || s.includes('un ')) return DEFAULT_THUMBS.news;\n    if (s === 'ssb' || s.includes('ssb')) return DEFAULT_THUMBS.stats;\n    if (s.includes('wikipedia')) return DEFAULT_THUMBS.knowledge;\n    if (s.includes('nasa')) return DEFAULT_THUMBS.knowledge;\n    if (s.includes('forskning')) return DEFAULT_THUMBS.research;\n    return DEFAULT_THUMBS.knowledge;\n  }\n\n  function setArticleUI(article, prefix = '') {\n    const thumb = article.thumbnail || '';\n    const url = article.url || '#';\n    const title = article.title || 'Ukjent tittel';\n    const source = article.source || 'Kilde';\n    const summary = article.summary || '';\n    const summaryAi = Boolean(article.summaryAiGenerated);\n    const imageCredit = article.imageCredit || '';\n    const imageCreditUrl = article.imageCreditUrl || '';\n\n    const thumbEl = prefix ? els.qArticleThumb : els.articleThumb;\n    const wrapEl = prefix ? els.qArticleThumbWrap : els.articleThumbWrap;\n    const thumbElMobile = prefix ? els.qArticleThumbMobile : els.articleThumbMobile;\n    const wrapElMobile = prefix ? els.qArticleThumbWrapMobile : els.articleThumbWrapMobile;\n    const linkThumbEl = prefix ? els.qArticleLinkThumb : els.articleLinkThumb;\n    const linkTitleEl = prefix ? els.qArticleLinkTitle : els.articleLinkTitle;\n    const sourceLinkEl = prefix ? els.qArticleSourceLink : els.articleSourceLink;\n    const summaryEl = prefix ? els.qArticleSummary : els.articleSummary;\n    const summaryMetaEl = prefix ? els.qArticleSummaryMeta : els.articleSummaryMeta;\n    const readMoreEl = prefix ? els.qReadMoreLink : els.readMoreLink;\n    const creditRowEl = prefix ? els.qImgCreditRow : els.articleImgCreditRow;\n    const creditTextEl = prefix ? els.qImgCredit : els.articleImgCredit;\n    const creditLinkEl = prefix ? els.qImgCreditLink : els.articleImgCreditLink;\n\n    \/\/ Thumbnail (rettighets-sikkert):\n    \/\/ Vi viser kun v\u00e5re egne standardbilder (ikke eksterne artikkelbilder), uansett kilde.\n    \/\/ For \"nyhetskilder\" kan vi variere dekorbildet mellom nk01\u2013nk09.\n    const s = (source || '').toString().toLowerCase();\n    const isNewsLike = s.includes('nettavisen') || s.includes('tu') || s.includes('teknisk ukeblad') || s.includes('bbc') || s.includes('un news') || s === 'un' || s.includes('un ');\n    if (isNewsLike) {\n      if (!article._newsDecorThumb) {\n        const seed = (article.id || article.url || article.title || '') + '';\n        article._newsDecorThumb = pickNewsDecorThumb(seed);\n      }\n    }\n    const thumbToUse = isNewsLike ? (article._newsDecorThumb || DEFAULT_THUMBS.news) : defaultThumbForSource(source);\n\n    if (wrapEl) wrapEl.classList.remove('isHidden');\n    if (wrapElMobile) wrapElMobile.classList.remove('isHidden');\n\n    if (thumbEl) { thumbEl.src = thumbToUse; thumbEl.alt = title; }\n    if (thumbElMobile) { thumbElMobile.src = thumbToUse; thumbElMobile.alt = title; }\n\n    \/\/ Marker nk-dekor for litt \u201czoom inn\u201d via CSS (fjerner evt innebygd luft i bildet)\n    const isDecor = isNewsLike && (thumbToUse || '').toString().includes('\/nk');\n    if (thumbEl) thumbEl.dataset.newsDecor = isDecor ? '1' : '';\n    if (thumbElMobile) thumbElMobile.dataset.newsDecor = isDecor ? '1' : '';\n    if (wrapEl) wrapEl.classList.toggle('isSquareThumb', Boolean(isDecor));\n    if (wrapElMobile) wrapElMobile.classList.toggle('isSquareThumb', Boolean(isDecor));\n\n    const showCredit = false;\n    if (!thumbToUse) {\n      \/\/ Sikkerhet: hvis default ikke finnes av en eller annen grunn, skjul omr\u00e5det.\n      if (wrapEl) wrapEl.classList.remove('isHidden');\n      if (wrapElMobile) wrapElMobile.classList.remove('isHidden');\n\n      if (wrapEl) wrapEl.classList.add('isHidden');\n      if (wrapElMobile) wrapElMobile.classList.add('isHidden');\n\n      if (thumbEl) { thumbEl.removeAttribute('src'); thumbEl.alt = ''; }\n      if (thumbElMobile) { thumbElMobile.removeAttribute('src'); thumbElMobile.alt = ''; }\n    }\n\n    linkThumbEl.href = url;\n    \/\/ mobile link\n    if (!prefix && els.articleLinkThumbMobile) els.articleLinkThumbMobile.href = url;\n    if (prefix && els.qArticleLinkThumbMobile) els.qArticleLinkThumbMobile.href = url;\n    linkTitleEl.href = url;\n    linkTitleEl.textContent = title;\n    if (sourceLinkEl) {\n      sourceLinkEl.textContent = source;\n      const home = homepageForSource(source);\n      sourceLinkEl.href = home || url;\n    }\n    \/\/ Render sammendrag som avsnitt (skolevennlig).\n    if (summaryEl) {\n      summaryEl.innerHTML = '';\n      const parts = summary.split(\/\\n\\s*\\n\/).map(s => s.trim()).filter(Boolean);\n      (parts.length ? parts : [summary]).forEach(p => {\n        const para = document.createElement('p');\n        para.className = 'summaryP';\n        para.textContent = p;\n        summaryEl.appendChild(para);\n      });\n    }\n    if (summaryMetaEl) {\n      summaryMetaEl.textContent = summaryAi\n        ? 'Sammendraget er laget av KI. Les saken i sin helhet for \u00e5 sjekke at alt stemmer.'\n        : '';\n    }\n    if (readMoreEl) readMoreEl.href = url;\n\n    \/\/ Fotokreditering: skjules (vi viser ikke eksterne artikkelbilder).\n    if (creditRowEl && creditTextEl && creditLinkEl) {\n      if (showCredit) {\n        creditRowEl.classList.remove('isHidden');\n        creditTextEl.textContent = imageCredit;\n        creditLinkEl.href = imageCreditUrl || url;\n      } else {\n        creditRowEl.classList.add('isHidden');\n        creditTextEl.textContent = '';\n        creditLinkEl.href = '#';\n      }\n    }\n  }\n\n  function scoringForAttempt(attempt) {\n    if (attempt === 1) return 2;\n    if (attempt === 2) return 1;\n    return 0;\n  }\n\n  function renderQuestion() {\n    const q = state.quiz.questions[state.idx];\n    state.attempt = 1;\n    state.disabled = new Set();\n    state.finishedCurrent = false;\n\n    const total = state.quiz?.questions?.length || 3;\n    els.progressText.textContent = `Oppgave ${state.idx + 1}\/${total}`;\n    els.scoreText.textContent = String(state.score);\n    \/\/ P\u00e5 siste oppgave gir \"Resultat\" mer mening enn \"Neste\".\n    els.nextBtn.textContent = (state.idx >= total - 1) ? 'Resultat' : 'Neste';\n\n    els.qText.textContent = safeText(q.question);\n    els.explain.classList.add('hidden');\n    els.explain.textContent = '';\n    els.nextBtn.classList.add('hidden');\n    els.quitBtn.classList.remove('hidden');\n\n    els.choices.innerHTML = '';\n    q.choices.forEach((choice, i) => {\n      const btn = document.createElement('button');\n      btn.className = 'choiceBtn';\n      btn.type = 'button';\n      btn.textContent = choice;\n      btn.addEventListener('click', () => choose(i, btn));\n      els.choices.appendChild(btn);\n    });\n  }\n\n  function lockChoices() {\n    [...els.choices.querySelectorAll('button')].forEach(b => b.disabled = true);\n  }\n\n  function markCorrect(correctIndex) {\n    const buttons = [...els.choices.querySelectorAll('button')];\n    if (buttons[correctIndex]) buttons[correctIndex].classList.add('correct');\n  }\n\n  function choose(choiceIndex, btnEl) {\n    if (state.finishedCurrent) return;\n    if (state.disabled.has(choiceIndex)) return;\n\n    state.disabled.add(choiceIndex);\n    btnEl.disabled = true;\n\n    const q = state.quiz.questions[state.idx];\n    const isCorrect = choiceIndex === q.correctIndex;\n    if (isCorrect) {\n      btnEl.classList.add('correct');\n      markCorrect(q.correctIndex);\n      const base = scoringForAttempt(state.attempt);\n      const bonus = state.hardMode ? 1 : 0;\n      const add = base + bonus;\n      if (state.attempt !== 1) state.perfectRun = false;\n      state.score += add;\n      els.scoreText.textContent = String(state.score);\n      state.finishedCurrent = true;\n      lockChoices();\n      if (q.explanation) {\n        els.explain.textContent = q.explanation;\n        els.explain.classList.remove('hidden');\n      }\n      els.nextBtn.classList.remove('hidden');\n      return;\n    }\n\n    btnEl.classList.add('wrong');\n    state.attempt += 1;\n\n    if (state.attempt > 3) {\n      \/\/ Ingen flere fors\u00f8k: vis fasit, 0 poeng.\n      state.perfectRun = false;\n      state.finishedCurrent = true;\n      markCorrect(q.correctIndex);\n      lockChoices();\n      if (q.explanation) {\n        els.explain.textContent = q.explanation;\n        els.explain.classList.remove('hidden');\n      }\n      els.nextBtn.classList.remove('hidden');\n    }\n  }\n\n  function renderConfetti() {\n    if (!els.confetti) return;\n    els.confetti.innerHTML = '';\n    const colors = ['#7c3aed', '#ec4899', '#22c55e', '#f59e0b', '#38bdf8', '#f43f5e'];\n    const count = 36;\n    for (let i = 0; i < count; i++) {\n      const d = document.createElement('div');\n      d.className = 'confettiPiece';\n      const left = Math.random() * 100;\n      const delay = Math.random() * 250;\n      const dur = 900 + Math.random() * 700;\n      const w = 6 + Math.random() * 10;\n      const h = 10 + Math.random() * 16;\n      d.style.left = `${left}%`;\n      d.style.width = `${w}px`;\n      d.style.height = `${h}px`;\n      d.style.background = colors[Math.floor(Math.random() * colors.length)];\n      d.style.animationDelay = `${delay}ms`;\n      d.style.animationDuration = `${dur}ms`;\n      d.style.transform = `rotate(${Math.random() * 180}deg)`;\n      els.confetti.appendChild(d);\n    }\n  }\n\n  function goNext() {\n    if (!state.quiz) return;\n    const total = state.quiz?.questions?.length || 3;\n    if (state.idx < total - 1) {\n      state.idx += 1;\n      renderQuestion();\n      return;\n    }\n    \/\/ end\n    let final = state.score;\n    const earnedPerfectBonus = state.hardMode && state.perfectRun;\n    if (earnedPerfectBonus) final += 1;\n    els.finalScore.textContent = String(final);\n\n    \/\/ Poeng + badge (lagres permanent)\n    claimPointsForQuiz(state.quiz?.quizId, final);\n    const title = state.quiz.article?.title ? `Sak: ${state.quiz.article.title}` : '';\n    if (state.hardMode) {\n      els.finalMeta.textContent = `${title}${title ? ' \u2022 ' : ''}Bonusmodus aktiv`;\n    } else {\n      els.finalMeta.textContent = title;\n    }\n    if (els.endThumb) {\n      const src = defaultThumbForSource(state.quiz.article?.source);\n      els.endThumb.src = src;\n      els.endThumb.alt = 'KvIz-tema';\n    }\n    if (els.endReadMoreLink) {\n      els.endReadMoreLink.href = state.quiz.article?.url || '#';\n    }\n    if (els.celebrateWrap) {\n      if (earnedPerfectBonus) {\n        els.celebrateWrap.classList.remove('hidden');\n        if (els.celebrateText) els.celebrateText.textContent = 'Helt perfekt!';\n        renderConfetti();\n      } else {\n        els.celebrateWrap.classList.add('hidden');\n        if (els.confetti) els.confetti.innerHTML = '';\n      }\n    }\n    show(els.endPanel);\n    \/\/ P\u00e5 mobil: hopp til toppen av quizen slik at sluttplakaten vises (ikke footer).\n    scrollToQuizTop();\n  }\n\n  function resetForRetry() {\n    state.idx = 0;\n    state.score = 0;\n    state.attempt = 1;\n    state.disabled = new Set();\n    state.finishedCurrent = false;\n    state.perfectRun = true;\n  }\n\n  function typewriteParagraph(el, text, speedMs, onDone) {\n    \/\/ Typewriter for a single paragraph. Returns a controller with skip().\n    const full = (text ?? '').toString();\n    let i = 0;\n    let stopped = false;\n    el.textContent = '';\n\n    function tick() {\n      if (stopped) return;\n      i += 2; \/\/ 2 chars per tick for speed\n      if (i >= full.length) {\n        el.textContent = full;\n        onDone?.();\n        return;\n      }\n      el.textContent = full.slice(0, i);\n      setTimeout(tick, speedMs);\n    }\n    setTimeout(tick, speedMs);\n\n    return {\n      skip() {\n        stopped = true;\n        el.textContent = full;\n        onDone?.();\n      }\n    };\n  }\n\n  function renderSummaryWithTypewriter(containerEl, summaryText) {\n    if (!containerEl) return { skip(){} };\n    containerEl.innerHTML = '';\n    const parts = (summaryText || '').split(\/\\n\\s*\\n\/).map(s => s.trim()).filter(Boolean);\n    const paras = parts.length ? parts : [(summaryText || '').trim()].filter(Boolean);\n\n    const controllers = [];\n    let idx = 0;\n\n    const skipAll = () => {\n      controllers.forEach(c => c?.skip?.());\n      \/\/ Ensure full render\n      containerEl.innerHTML = '';\n      paras.forEach(p => {\n        const para = document.createElement('p');\n        para.className = 'summaryP';\n        para.textContent = p;\n        containerEl.appendChild(para);\n      });\n    };\n\n    const next = () => {\n      if (idx >= paras.length) return;\n      const para = document.createElement('p');\n      para.className = 'summaryP';\n      containerEl.appendChild(para);\n      const ctl = typewriteParagraph(para, paras[idx], 14, () => {\n        idx += 1;\n        next();\n      });\n      controllers.push(ctl);\n    };\n\n    next();\n    \/\/ Sammendraget skal bare vises som tekst uten ekstra hint\/tooltip.\n    containerEl.style.cursor = '';\n    containerEl.removeAttribute('title');\n    containerEl.onclick = null;\n\n    return { skip: skipAll };\n  }\n\n  async function fetchQuiz() {\n    show(els.loadingPanel);\n    \/\/ Varier dekorbildet i loading\/qGen (nyhetsbilde)\n    applyNewsDecorThumb(Date.now().toString(36));\n    els.loadingSub.textContent = 'Dette tar vanligvis noen sekunder.';\n    if (els.quizTitle) els.quizTitle.textContent = 'Ta en KvIz';\n    els.startBtn.disabled = true;\n    els.anotherBtn.disabled = true;\n    if (els.hardModeToggle) els.hardModeToggle.disabled = true;\n\n    try {\n      \/\/ 1) Hent sak + sammendrag f\u00f8rst (raskere UX)\n      const { res, text: raw } = await fetchWithTimeout(QUIZ_ENDPOINT, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({\n          stage: 'summary',\n          excludeIds: state.excludeIds.slice(-20),\n          excludeArticleIds: loadSeenArticles().ids.slice(-400),\n        })\n      }, 45000);\n      let data = null;\n      try { data = JSON.parse(raw); } catch (_) {}\n\n      if (!res.ok) {\n        const msg = data?.details || data?.error || `HTTP ${res.status}`;\n        throw new Error(msg);\n      }\n      if (!data) throw new Error('Svar fra server var ikke JSON (sannsynlig 404 eller PHP-feil).');\n      if (!data?.article) throw new Error('Feil format fra server');\n\n      state.quiz = data;\n      resetForRetry();\n      if (els.quizTitle) els.quizTitle.textContent = titleForSource(data?.article?.source);\n\n      const pageid = data.article?.pageid;\n      if (Number.isInteger(pageid)) state.excludeIds.push(pageid);\n      if (data?.article?.id) rememberSeenArticleId(data.article.id);\n\n      \/\/ Render artikkel, men typewrite sammendraget\n      setArticleUI(data.article);\n      \/\/ Replace summary with typewriter (startplakat)\n      renderSummaryWithTypewriter(els.articleSummary, data.article?.summary || '');\n      \/\/ behold valgt bonusmodus n\u00e5r ny sak lastes\n      applyHardModeUI(Boolean(els.hardModeToggle?.checked));\n      show(els.startPanel);\n      els.loadingSub.textContent = '';\n\n      \/\/ 2) Hent sp\u00f8rsm\u00e5l i bakgrunnen mens brukeren leser\n      els.startBtn.disabled = true;\n      if (els.qGenRow) els.qGenRow.classList.remove('hidden');\n      if (els.qGenText) els.qGenText.textContent = 'Lager sp\u00f8rsm\u00e5l\u2026';\n      try {\n        const { res: qRes, text: qRaw } = await fetchWithTimeout(QUIZ_ENDPOINT, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application\/json' },\n          body: JSON.stringify({\n            stage: 'questions',\n            studentSummary: data.article?.summary || '',\n          })\n        }, 45000);\n        let qData = null;\n        try { qData = JSON.parse(qRaw); } catch (_) {}\n        if (!qRes.ok) {\n          const msg = qData?.details || qData?.error || `HTTP ${qRes.status}`;\n          throw new Error(msg);\n        }\n        if (!qData?.questions || !Array.isArray(qData.questions) || qData.questions.length !== 3) {\n          throw new Error('Feil format p\u00e5 sp\u00f8rsm\u00e5l');\n        }\n        state.quiz.questions = qData.questions;\n        if (els.qGenRow) els.qGenRow.classList.add('hidden');\n      } catch (err) {\n        \/\/ Vis feilen p\u00e5 startplakaten og la bruker velge ny sak.\n        if (els.qGenRow) els.qGenRow.classList.remove('hidden');\n        const isAbort = (err?.name === 'AbortError') || (String(err?.message || '').toLowerCase().includes('abort'));\n        if (els.qGenText) {\n          els.qGenText.textContent = isAbort\n            ? 'Dette tok for lang tid \u00e5 lage sp\u00f8rsm\u00e5l. Trykk \u201cVelg en annen sak\u201d.'\n            : `Klarte ikke \u00e5 lage sp\u00f8rsm\u00e5l: ${err?.message || err}`;\n        }\n      } finally {\n        els.startBtn.textContent = 'Start KvIz';\n        \/\/ Kun enable hvis sp\u00f8rsm\u00e5l faktisk er klare (ellers f\u00e5r vi \"d\u00f8d\" knapp)\n        els.startBtn.disabled = !(Array.isArray(state.quiz?.questions) && state.quiz.questions.length === 3);\n      }\n    } catch (e) {\n      const isAbort = (e?.name === 'AbortError') || (String(e?.message || '').toLowerCase().includes('abort'));\n      \/\/ Vis faktisk feilmelding, ellers er det umulig \u00e5 feils\u00f8ke.\n      els.loadingSub.textContent = isAbort\n        ? 'Dette tok for lang tid. Trykk \u201cVelg en annen sak\u201d for \u00e5 pr\u00f8ve p\u00e5 nytt.'\n        : `Klarte ikke \u00e5 lage KvIz akkurat n\u00e5: ${e?.message || e}`;\n      \/\/ En enkel \u201cretry\u201d via klikk p\u00e5 loading-panelet\n      els.loadingPanel.onclick = () => {\n        els.loadingPanel.onclick = null;\n        \/\/ Retry = ny henting, s\u00e5 vi resetter Bonusmodus.\n        startNewQuiz();\n      };\n    } finally {\n      \/\/ Start-knapp kan bli re-enabled etter at sp\u00f8rsm\u00e5l er klare (se over)\n      els.anotherBtn.disabled = false;\n      if (els.hardModeToggle) els.hardModeToggle.disabled = false;\n    }\n  }\n\n  function startNewQuiz() {\n    \/\/ Bonusmodus skal ikke \u201cbli med\u201d til en helt ny quiz.\n    if (els.hardModeToggle) els.hardModeToggle.checked = false;\n    applyHardModeUI(false);\n    scrollToQuizTop();\n    fetchQuiz();\n  }\n\n  if (els.hardModeToggle) {\n    els.hardModeToggle.addEventListener('change', () => {\n      applyHardModeUI(Boolean(els.hardModeToggle.checked));\n      scrollToQuizTop();\n    });\n  }\n\n  els.startBtn.addEventListener('click', () => {\n    if (!state.quiz) return;\n    if (!Array.isArray(state.quiz.questions) || state.quiz.questions.length !== 3) return;\n    setArticleUI(state.quiz.article, 'q');\n    applyHardModeUI(Boolean(els.hardModeToggle?.checked));\n    show(els.questionPanel);\n    renderQuestion();\n  });\n\n  els.anotherBtn.addEventListener('click', () => {\n    startNewQuiz();\n  });\n\n  els.nextBtn.addEventListener('click', goNext);\n\n  els.quitBtn.addEventListener('click', () => {\n    \/\/ tilbake til startplakat med samme sak\n    if (!state.quiz) return;\n    setArticleUI(state.quiz.article);\n    applyHardModeUI(Boolean(els.hardModeToggle?.checked));\n    show(els.startPanel);\n  });\n\n  els.newQuizBtn.addEventListener('click', () => startNewQuiz());\n\n  els.retryBtn.addEventListener('click', () => {\n    if (!state.quiz) return;\n    resetForRetry();\n    setArticleUI(state.quiz.article, 'q');\n    applyHardModeUI(Boolean(els.hardModeToggle?.checked));\n    show(els.questionPanel);\n    renderQuestion();\n  });\n\n  \/\/ Auto: hent random sak ved lasting.\n  \/\/ Init badge UI\n  try {\n    const p = loadProgress();\n    renderBadgeUI(p.points);\n  } catch (_) {}\n\n  \/\/ Badge modal wiring\n  bindOpenModal(els.dailyPointsPill);\n  bindOpenModal(els.dailyBadgePill);\n  bindOpenModal(els.dailyNextPill);\n  els.badgeModalClose?.addEventListener?.('click', closeBadgeModal);\n  els.badgeModal?.addEventListener?.('click', (e) => {\n    if (e.target === els.badgeModal) closeBadgeModal();\n  });\n  document.addEventListener('keydown', (e) => {\n    if (e.key === 'Escape') closeBadgeModal();\n  });\n\n  fetchQuiz();\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>F\u00e5 nyheter og kunnskap p\u00e5 en ny og spennende m\u00e5te. Oppdatert fra time til time. KI lager sp\u00f8rsm\u00e5l p\u00e5 direkten.<\/p>\n","protected":false},"author":2,"featured_media":42617,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71,99,10,41,94,78,7,42],"tags":[],"post_folder":[],"class_list":["post-42628","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-gratis","category-kunnskap","category-norsk","category-nyheter","category-pop","category-profilert","category-quiz","category-voksen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Live KvIz - Gruble.net<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gruble.net\/kviz-2\/\" \/>\n<meta property=\"og:locale\" content=\"nb_NO\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Live KvIz - Gruble.net\" \/>\n<meta property=\"og:description\" content=\"F\u00e5 nyheter og kunnskap p\u00e5 en ny og spennende m\u00e5te. Oppdatert fra time til time. KI lager sp\u00f8rsm\u00e5l p\u00e5 direkten.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gruble.net\/kviz-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Gruble.net\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Gruble.net\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-05T21:09:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-18T10:36:26+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gruble.net\/wp-content\/uploads\/lessmart.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Stig Hamstad\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Skrevet av\" \/>\n\t<meta name=\"twitter:data1\" content=\"Stig Hamstad\" \/>\n\t<meta name=\"twitter:label2\" content=\"Ansl. lesetid\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutter\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/\"},\"author\":{\"name\":\"Stig Hamstad\",\"@id\":\"https:\\\/\\\/gruble.net\\\/#\\\/schema\\\/person\\\/713eaee8c60258dd79836b2ce3743569\"},\"headline\":\"Live KvIz\",\"datePublished\":\"2026-02-05T21:09:01+00:00\",\"dateModified\":\"2026-02-18T10:36:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/\"},\"wordCount\":233,\"publisher\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gruble.net\\\/wp-content\\\/uploads\\\/lessmart.jpg\",\"articleSection\":[\"Gratis\",\"Kunnskap\",\"Norsk\",\"Nyheter\",\"Popul\u00e6rt\",\"Profilert\",\"Quiz\",\"Voksen\"],\"inLanguage\":\"nb-NO\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/\",\"url\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/\",\"name\":\"Live KvIz - Gruble.net\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gruble.net\\\/wp-content\\\/uploads\\\/lessmart.jpg\",\"datePublished\":\"2026-02-05T21:09:01+00:00\",\"dateModified\":\"2026-02-18T10:36:26+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#breadcrumb\"},\"inLanguage\":\"nb-NO\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"nb-NO\",\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gruble.net\\\/wp-content\\\/uploads\\\/lessmart.jpg\",\"contentUrl\":\"https:\\\/\\\/gruble.net\\\/wp-content\\\/uploads\\\/lessmart.jpg\",\"width\":1536,\"height\":1024,\"caption\":\"Man og kvinne leser p\u00e5 mobilskjerm og pc-skjerm.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gruble.net\\\/kviz-2\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Hjem\",\"item\":\"https:\\\/\\\/gruble.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Live KvIz\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gruble.net\\\/#website\",\"url\":\"https:\\\/\\\/gruble.net\\\/\",\"name\":\"Gruble.net\",\"description\":\"Spill deg til kunnskap og sett kunnskapen p\u00e5 spill!\",\"publisher\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gruble.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"nb-NO\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/gruble.net\\\/#organization\",\"name\":\"Gruble.net\",\"url\":\"https:\\\/\\\/gruble.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"nb-NO\",\"@id\":\"https:\\\/\\\/gruble.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/gruble.net\\\/wp-content\\\/uploads\\\/logo-1-e1717058548444.png\",\"contentUrl\":\"https:\\\/\\\/gruble.net\\\/wp-content\\\/uploads\\\/logo-1-e1717058548444.png\",\"width\":483,\"height\":149,\"caption\":\"Gruble.net\"},\"image\":{\"@id\":\"https:\\\/\\\/gruble.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/Gruble.net\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/gruble.net\\\/#\\\/schema\\\/person\\\/713eaee8c60258dd79836b2ce3743569\",\"name\":\"Stig Hamstad\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"nb-NO\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7e9060851f3f4d21de8e999d31b1d4646ce70f48ae4f93b9ee6a4a3121b6f40c?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7e9060851f3f4d21de8e999d31b1d4646ce70f48ae4f93b9ee6a4a3121b6f40c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7e9060851f3f4d21de8e999d31b1d4646ce70f48ae4f93b9ee6a4a3121b6f40c?s=96&d=mm&r=g\",\"caption\":\"Stig Hamstad\"},\"sameAs\":[\"https:\\\/\\\/gruble.net\"],\"url\":\"https:\\\/\\\/gruble.net\\\/author\\\/stig-hamstad-2\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Live KvIz - Gruble.net","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:\/\/gruble.net\/kviz-2\/","og_locale":"nb_NO","og_type":"article","og_title":"Live KvIz - Gruble.net","og_description":"F\u00e5 nyheter og kunnskap p\u00e5 en ny og spennende m\u00e5te. Oppdatert fra time til time. KI lager sp\u00f8rsm\u00e5l p\u00e5 direkten.","og_url":"https:\/\/gruble.net\/kviz-2\/","og_site_name":"Gruble.net","article_publisher":"https:\/\/www.facebook.com\/Gruble.net","article_published_time":"2026-02-05T21:09:01+00:00","article_modified_time":"2026-02-18T10:36:26+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/gruble.net\/wp-content\/uploads\/lessmart.jpg","type":"image\/jpeg"}],"author":"Stig Hamstad","twitter_card":"summary_large_image","twitter_misc":{"Skrevet av":"Stig Hamstad","Ansl. lesetid":"5 minutter"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gruble.net\/kviz-2\/#article","isPartOf":{"@id":"https:\/\/gruble.net\/kviz-2\/"},"author":{"name":"Stig Hamstad","@id":"https:\/\/gruble.net\/#\/schema\/person\/713eaee8c60258dd79836b2ce3743569"},"headline":"Live KvIz","datePublished":"2026-02-05T21:09:01+00:00","dateModified":"2026-02-18T10:36:26+00:00","mainEntityOfPage":{"@id":"https:\/\/gruble.net\/kviz-2\/"},"wordCount":233,"publisher":{"@id":"https:\/\/gruble.net\/#organization"},"image":{"@id":"https:\/\/gruble.net\/kviz-2\/#primaryimage"},"thumbnailUrl":"https:\/\/gruble.net\/wp-content\/uploads\/lessmart.jpg","articleSection":["Gratis","Kunnskap","Norsk","Nyheter","Popul\u00e6rt","Profilert","Quiz","Voksen"],"inLanguage":"nb-NO"},{"@type":"WebPage","@id":"https:\/\/gruble.net\/kviz-2\/","url":"https:\/\/gruble.net\/kviz-2\/","name":"Live KvIz - Gruble.net","isPartOf":{"@id":"https:\/\/gruble.net\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gruble.net\/kviz-2\/#primaryimage"},"image":{"@id":"https:\/\/gruble.net\/kviz-2\/#primaryimage"},"thumbnailUrl":"https:\/\/gruble.net\/wp-content\/uploads\/lessmart.jpg","datePublished":"2026-02-05T21:09:01+00:00","dateModified":"2026-02-18T10:36:26+00:00","breadcrumb":{"@id":"https:\/\/gruble.net\/kviz-2\/#breadcrumb"},"inLanguage":"nb-NO","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gruble.net\/kviz-2\/"]}]},{"@type":"ImageObject","inLanguage":"nb-NO","@id":"https:\/\/gruble.net\/kviz-2\/#primaryimage","url":"https:\/\/gruble.net\/wp-content\/uploads\/lessmart.jpg","contentUrl":"https:\/\/gruble.net\/wp-content\/uploads\/lessmart.jpg","width":1536,"height":1024,"caption":"Man og kvinne leser p\u00e5 mobilskjerm og pc-skjerm."},{"@type":"BreadcrumbList","@id":"https:\/\/gruble.net\/kviz-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Hjem","item":"https:\/\/gruble.net\/"},{"@type":"ListItem","position":2,"name":"Live KvIz"}]},{"@type":"WebSite","@id":"https:\/\/gruble.net\/#website","url":"https:\/\/gruble.net\/","name":"Gruble.net","description":"Spill deg til kunnskap og sett kunnskapen p\u00e5 spill!","publisher":{"@id":"https:\/\/gruble.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gruble.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"nb-NO"},{"@type":"Organization","@id":"https:\/\/gruble.net\/#organization","name":"Gruble.net","url":"https:\/\/gruble.net\/","logo":{"@type":"ImageObject","inLanguage":"nb-NO","@id":"https:\/\/gruble.net\/#\/schema\/logo\/image\/","url":"https:\/\/gruble.net\/wp-content\/uploads\/logo-1-e1717058548444.png","contentUrl":"https:\/\/gruble.net\/wp-content\/uploads\/logo-1-e1717058548444.png","width":483,"height":149,"caption":"Gruble.net"},"image":{"@id":"https:\/\/gruble.net\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Gruble.net"]},{"@type":"Person","@id":"https:\/\/gruble.net\/#\/schema\/person\/713eaee8c60258dd79836b2ce3743569","name":"Stig Hamstad","image":{"@type":"ImageObject","inLanguage":"nb-NO","@id":"https:\/\/secure.gravatar.com\/avatar\/7e9060851f3f4d21de8e999d31b1d4646ce70f48ae4f93b9ee6a4a3121b6f40c?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/7e9060851f3f4d21de8e999d31b1d4646ce70f48ae4f93b9ee6a4a3121b6f40c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7e9060851f3f4d21de8e999d31b1d4646ce70f48ae4f93b9ee6a4a3121b6f40c?s=96&d=mm&r=g","caption":"Stig Hamstad"},"sameAs":["https:\/\/gruble.net"],"url":"https:\/\/gruble.net\/author\/stig-hamstad-2\/"}]}},"_links":{"self":[{"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/posts\/42628","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/comments?post=42628"}],"version-history":[{"count":7,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/posts\/42628\/revisions"}],"predecessor-version":[{"id":42635,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/posts\/42628\/revisions\/42635"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/media\/42617"}],"wp:attachment":[{"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/media?parent=42628"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/categories?post=42628"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/tags?post=42628"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/gruble.net\/wp-json\/wp\/v2\/post_folder?post=42628"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}