{"id":2914,"date":"2026-05-24T16:10:22","date_gmt":"2026-05-24T16:10:22","guid":{"rendered":"https:\/\/speedpuzzling.nl\/en\/?page_id=2914"},"modified":"2026-05-24T16:13:07","modified_gmt":"2026-05-24T16:13:07","slug":"results-dutch-jigsaw-nationals-2026","status":"publish","type":"page","link":"https:\/\/speedpuzzling.nl\/en\/results-dutch-jigsaw-nationals-2026\/","title":{"rendered":"Results &#8211; Dutch Jigsaw Nationals 2026"},"content":{"rendered":"\n<div class=\"wp-block-stackable-hero alignfull stk-block-hero stk-has-bottom-separator stk-block stk-107a08b stk-block-background is-style-default stk--has-background-overlay\" data-v=\"2\" data-block-id=\"107a08b\"><style>.stk-107a08b-inner-blocks{justify-content:flex-start !important;}.stk-107a08b {background-color:var(--theme-palette-color-9, #222e56) !important;background-image:url(https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/02\/460671321_549495830749176_5449918812236957648_n.jpg) !important;background-position:bottom center !important;background-size:custom !important;margin-bottom:0px !important;overflow:visible !important;}.stk-107a08b:before{background-color:var(--theme-palette-color-9, #222e56) !important;opacity:0.8 !important;}.stk-107a08b .stk-container{overflow:visible !important;}.stk-107a08b .stk-block-hero__content{min-height:500px !important;align-items:center !important;display:flex !important;}.stk-107a08b > .stk-separator__bottom svg{fill:var(--theme-palette-color-6, #f9fafb) !important;}.stk-107a08b > .stk-separator__bottom .stk-separator__wrapper{height:120px !important;}@media screen and (max-width:689px){.stk-107a08b {overflow:visible !important;}.stk-107a08b .stk-container{overflow:visible !important;}.stk-107a08b .stk-block-hero__content{min-height:225px !important;}}<\/style><div class=\"stk-block-hero__content stk-content-align stk-107a08b-column alignfull stk-container stk-107a08b-container stk--no-background stk--no-padding\"><div class=\"stk-block-content stk-inner-blocks has-text-align-center stk--column-flex stk-107a08b-inner-blocks\">\n<div class=\"wp-block-stackable-spacer stk-block-spacer stk--no-padding stk-block stk-8185a51\" data-block-id=\"8185a51\"><style>.stk-8185a51 {height:240px !important;}@media screen and (max-width:689px){.stk-8185a51 {height:110px !important;}}<\/style><\/div>\n\n\n\n<div class=\"wp-block-stackable-heading stk-block-heading stk-block-heading--v2 stk-block stk-d81670c stk-block-background\" id=\"results-br-dutch-jigsaw-nationals-2026\" data-block-id=\"d81670c\"><style>.stk-d81670c .stk-block-heading__bottom-line{height:0px !important;}.stk-d81670c {background-color:#00000000 !important;min-height:0px !important;align-items:center !important;display:flex !important;}.stk-d81670c:before{background-color:#00000000 !important;}.stk-d81670c .stk-block-heading__text{font-size:60px !important;color:var(--theme-palette-color-7, #FDFDFD) !important;font-weight:900 !important;font-family:\"Coolvetica\", Sans-serif !important;letter-spacing:3.3px !important;}@media screen and (max-width:999px){.stk-d81670c .stk-block-heading__text{font-size:38px !important;letter-spacing:3.3px !important;}}@media screen and (max-width:689px){.stk-d81670c .stk-block-heading__text{font-size:25px !important;}}<\/style><h2 class=\"stk-block-heading__text has-text-color has-text-align-center\">Results<br>Dutch Jigsaw Nationals 2026<\/h2><\/div>\n<\/div><\/div><div class=\"stk-separator stk-separator__bottom\"><div class=\"stk-separator__wrapper\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 1600 200\" class=\"stk-separator__layer-1\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path d=\"M1610.5 189.1s-128.2-82.6-138.2-89.2c-17.1-11.3-37.2-15.5-87-18.1-49.7-2.6-753.6-40.7-783.9-42.3-30.3-1.5-81.1-1.3-121.1 8.2S-9.5 163.2-9.5 163.2v50h1620v-24.1z\"><\/path><\/svg><\/div><\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<div class=\"wp-block-stackable-tabs alignfull stk-block-tabs stk-block stk-1054b4c\" data-initial-tab=\"1\" data-block-id=\"1054b4c\"><style>.stk-1054b4c {--tabs-gap:0px !important;}.stk-1054b4c .stk-block-tab-content .stk-block-content .stk-block-column[hidden]{display:none !important;}<\/style><div class=\"stk-row stk-inner-blocks stk-block-content stk-block-tabs--horizontal stk-block-tabs--fade stk-content-align stk-1054b4c-column alignfull\">\n<div class=\"wp-block-stackable-tab-content stk-block-tab-content stk-block stk-6adffc9\" data-block-id=\"6adffc9\"><div class=\"stk-row stk-inner-blocks stk-block-content stk-content-align stk-6adffc9-column\">\n<div class=\"wp-block-stackable-column stk-block-column stk-column stk-block stk-ef1eef8\" data-v=\"4\" id=\"teams\" data-block-id=\"ef1eef8\"><style>.stk-ef1eef8-container{max-width:1250px !important;min-width:auto !important;margin-right:auto !important;margin-left:auto !important;}<\/style><div class=\"stk-column-wrapper stk-block-column__content stk-container stk-ef1eef8-container stk--no-background stk--no-padding\"><div class=\"stk-block-content stk-inner-blocks stk-ef1eef8-inner-blocks\">\n<div class=\"wp-block-stackable-card stk-block-card stk-block stk-404219e is-style-default\" data-v=\"2\" data-block-id=\"404219e\"><style>.stk-404219e .stk-block-card__image{height:10px !important;}<\/style><div class=\"stk--no-padding stk-container stk-404219e-container stk-hover-parent\"><figure class=\"stk-block-card__image stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-1124\" src=\"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png\" width=\"3333\" height=\"3333\" srcset=\"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png 3333w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-300x300.png 300w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-1024x1024.png 1024w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-150x150.png 150w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-768x768.png 768w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-1536x1536.png 1536w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-2048x2048.png 2048w, https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3-12x12.png 12w\" sizes=\"auto, (max-width: 3333px) 100vw, 3333px\" \/><\/figure><div class=\"stk-container-padding stk-block-card__content\"><div class=\"stk-block-content stk-inner-blocks stk-404219e-inner-blocks\">\n<div class=\"wp-block-stackable-text stk-block-text stk-block stk-3d7eec3\" data-block-id=\"3d7eec3\"><p class=\"stk-block-text__text\">\n<div id=\"spnl-ranking-widget\">\n    <style>\n    \/* NOTE: All styles should be in CSS classes, not inline. *\/\n    \/* Tabs + ranking controls toolbar *\/\n    .spnl-ranking-toolbar {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        gap: 10px;\n        width: 100%;\n        margin-bottom: 15px;\n    }\n    #spnl-round-buttons {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        gap: 10px;\n        margin-bottom: 0;\n        justify-content: center;\n        width: 100%;\n    }\n    .spnl-round-button-group {\n        display: flex;\n        flex-wrap: nowrap;\n        gap: 8px;\n        justify-content: center;\n        align-items: center;\n        max-width: 100%;\n    }\n    .spnl-round-button-row {\n        display: flex;\n        flex-wrap: wrap;\n        gap: 10px;\n        justify-content: center;\n        align-items: center;\n        max-width: 100%;\n    }\n    #spnl-ranking-controls {\n        display: none;\n        flex-direction: row;\n        flex-wrap: wrap;\n        gap: 12px 20px;\n        margin-bottom: 0;\n        justify-content: center;\n        align-items: center;\n        width: 100%;\n        box-sizing: border-box;\n    }\n    .spnl-control-group {\n        display: inline-flex;\n        align-items: center;\n        gap: 10px;\n        flex-wrap: nowrap;\n        overflow: visible;\n    }\n    #spnl-definition-control {\n        overflow: visible;\n    }\n    .spnl-control-label {\n        font-weight: 600;\n        font-size: 14px;\n        color: #222e56;\n        white-space: nowrap;\n        flex-shrink: 0;\n    }\n    .spnl-select {\n        border: none;\n        background-color: #EDEFF2;\n        padding: 12px 44px 12px 28px;\n        cursor: pointer;\n        font-weight: 600;\n        font-size: 14px;\n        color: #222e56;\n        border-radius: 50px;\n        min-height: 48px;\n        height: auto;\n        min-width: 160px;\n        max-width: 320px;\n        line-height: 1.5;\n        box-sizing: border-box;\n        overflow: visible;\n        appearance: none;\n        -webkit-appearance: none;\n        background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23222e56' d='M1 1l5 5 5-5'\/%3E%3C\/svg%3E\");\n        background-repeat: no-repeat;\n        background-position: right 18px center;\n        transition: background-color 0.3s ease, color 0.3s ease;\n    }\n    .spnl-select:hover,\n    .spnl-select:focus {\n        background-color: #e0e0e0;\n        outline: none;\n    }\n    .spnl-toggle {\n        display: inline-flex;\n        align-items: center;\n        gap: 12px;\n        cursor: pointer;\n        user-select: none;\n    }\n    .spnl-toggle input {\n        position: absolute;\n        opacity: 0;\n        width: 0;\n        height: 0;\n    }\n    .spnl-toggle-track {\n        width: 52px;\n        height: 28px;\n        background: #EDEFF2;\n        border-radius: 50px;\n        position: relative;\n        flex-shrink: 0;\n        transition: background-color 0.3s ease;\n    }\n    .spnl-toggle-track::after {\n        content: \"\";\n        position: absolute;\n        top: 3px;\n        left: 3px;\n        width: 22px;\n        height: 22px;\n        background: #fff;\n        border-radius: 50%;\n        transition: transform 0.3s ease;\n        box-shadow: 0 1px 3px rgba(0,0,0,0.15);\n    }\n    .spnl-toggle input:checked + .spnl-toggle-track {\n        background: #f0881f;\n    }\n    .spnl-toggle input:checked + .spnl-toggle-track::after {\n        transform: translateX(24px);\n    }\n    .spnl-toggle-text {\n        font-weight: 600;\n        font-size: 14px;\n        color: #222e56;\n    }\n    .spnl-toggle input:focus-visible + .spnl-toggle-track {\n        outline: 3px solid #ffa833;\n        outline-offset: 2px;\n    }\n    .spnl-ranking-section-header {\n        display: flex;\n        align-items: center;\n        gap: 8px;\n        margin: 20px 0 12px 0;\n        padding: 10px 16px;\n        background: #f8f9fb;\n        border-radius: 12px;\n        border: 1px solid #eee;\n        width: 100%;\n        box-sizing: border-box;\n    }\n    .spnl-ranking-section-header:first-child {\n        margin-top: 0;\n    }\n    .spnl-ranking-section-title {\n        font-size: 1.05em;\n        font-weight: 700;\n        color: #222e56;\n    }\n    .spnl-ranking-section-count {\n        font-size: 0.95em;\n        font-weight: 600;\n        color: #004080;\n    }\n    .spnl-ranking-section-row td {\n        padding: 16px 8px 8px 8px !important;\n        background: #f8f9fb !important;\n        border: none !important;\n    }\n    .spnl-table tr.spnl-not-finished-row,\n    .spnl-table tr.spnl-not-finished-row td {\n        background-color: #f8f9fb !important;\n    }\n    .spnl-table tr.spnl-not-finished-row td .spnl-table-puzzle-cell-inner {\n        background: transparent !important;\n        border: none !important;\n        box-shadow: none !important;\n        min-height: 0;\n        padding: 0;\n    }\n    .spnl-table tr.spnl-not-finished-row td.spnl-not-finished-puzzle-col {\n        padding: 0 18px;\n    }\n    \/* Base button style *\/\n    .spnl-round-tab {\n        border: none; \/* removed black border *\/\n        background: #EDEFF2; \/* light gray for inactive *\/\n        padding: 18px 28px; \/* less vertical padding *\/\n        cursor: pointer;\n        font-weight: 600;\n        font-size: 14px;\n        color: #222e56; \/* dark gray text *\/\n        border-radius: 50px; \/* pill shape *\/\n        user-select: none;\n        transition: background-color 0.3s ease, color 0.3s ease;\n        box-shadow: none;\n        line-height: 1.2;\n        min-height: 42px;\n    }\n    \/* Hover for non-active *\/\n    .spnl-round-tab:hover:not(.spnl-round-tab--active) {\n        background-color: #e0e0e0;\n        color: #222e56;\n    }\n    \/* Active tab style *\/\n    .spnl-round-tab--active {\n        background-color: #f0881f; \/* orange *\/\n        color: white;\n        cursor: default;\n    }\n    \/* Center tab label text *\/\n    .spnl-round-tab-label {\n        text-align: center;\n    }\n    \/* Ranking output container styling *\/\n    #spnl-ranking-output {\n        min-height: 300px;\n        transition: min-height 0.3s ease;\n        margin-top: 20px;\n        overflow-x: auto;\n    }\n    \/* Focus outline for accessibility *\/\n    .spnl-round-tab:focus-visible {\n        outline: 3px solid #ffa833;\n        outline-offset: 2px;\n    }\n    .spnl-timer-bar { display: flex; gap: 30px; align-items: center; margin-bottom: 20px; }\n    .spnl-timer-label { font-weight: bold; color: #222e56; }\n    .spnl-timer-value { font-family: monospace; font-size: 1.3em; color: #f0881f; }\n    .spnl-puzzle-row-img-wrap {\n        flex: 0 0 auto;\n        width: 36px;\n        height: 36px;\n        border-radius: 4px;\n        border: 1px solid #ccc;\n        overflow: hidden;\n        background: #fff;\n        display: block;\n    }\n    .spnl-puzzle-row-img {\n        width: 100%;\n        height: 100%;\n        object-fit: cover;\n        object-position: center;\n        display: block;\n        border: none;\n        border-radius: 0;\n    }\n    .spnl-puzzle-row-time { font-size: 0.9em; color: #888; text-align: center; }\n\n    \/* Timer card style (copied\/adapted from timer.blade.php) *\/\n    .spnl-timer-card {\n        background: #004080;\n        border-radius: 16px;\n        box-shadow: none;\n        border: none;\n        margin-right: 19px;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        min-height: 56px;\n        margin-top: -10px;\n        max-width: 235px;\n        width: 235px;\n        margin-left: auto;\n    }\n    .spnl-timer-inner {\n        width: 100%;\n        height: 100%;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n    }\n    .spnl-timer-display {\n        font-family: 'Inter', 'Roboto Mono', 'Menlo', 'Monaco', 'Consolas', monospace;\n        font-variant-numeric: tabular-nums;\n        min-width: 120px;\n        display: inline-block;\n        font-size: 2em;\n        color: #fff;\n        text-align: center;\n        font-weight: 700;\n        letter-spacing: 0.08em;\n        line-height: 1.1;\n        white-space: nowrap;\n        overflow: hidden;\n        text-overflow: ellipsis;\n    }\n    \/* Custom extracted classes *\/\n    .spnl-header-outer { width: 100%; margin-bottom: 0; }\n    .spnl-header-two-col {\n        display: flex;\n        flex-direction: row;\n        align-items: flex-start;\n        width: 100%;\n        margin-top: 24px;\n    }\n    .spnl-header-left {\n        flex: 0 0 50%;\n        display: flex;\n        flex-direction: column;\n        gap: 8px;\n    }\n    .spnl-header-right {\n        flex: 0 0 50%;\n        display: flex;\n        flex-direction: column;\n        gap: 16px;\n    }\n    .spnl-header-title-row {\n        display: flex;\n        flex-direction: row;\n        align-items: flex-end;\n        justify-content: space-between;\n        width: 100%;\n        margin-bottom: 24px;\n    }\n    .spnl-header-title-main {\n        font-size: 2.1em;\n        font-weight: 900;\n        text-align: left;\n        color: #222e56;\n        letter-spacing: 0.01em;\n        flex: 1 1 0;\n    }\n    .spnl-header-title-timer {\n        flex: 0 0 auto;\n        display: flex;\n        align-items: flex-end;\n        justify-content: flex-end;\n        width: 280px;\n        margin-left: auto;\n        margin-bottom: 0;\n    }\n    .spnl-info-row { display: flex; align-items: center; gap: 12px; font-size: 1.1em; color: #222e56; }\n    .spnl-info-icon { width: 20px; height: 20px; color: #004080; }\n    .spnl-info-label { font-weight: 600; padding-top: 6px;}\n    .spnl-info-value { color: #004080; }\n    .spnl-puzzle-cards {\n        display: flex;\n        flex-direction: row;\n        align-items: stretch;\n        gap: 16px;\n        width: 100%;\n    }\n    .spnl-puzzle-card {\n        flex: 1 1 0;\n        background: #fff;\n        border: none;\n        border-radius: 12px;\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        justify-content: flex-start;\n        box-shadow: 0 2px 8px rgba(0,0,0,0.04);\n        padding: 16px;\n        box-sizing: border-box;\n    }\n    .spnl-puzzle-card-header {\n        width: 100%;\n        margin: 0 auto 8px auto;\n        display: flex;\n        flex-direction: row-reverse;\n        align-items: center;\n        justify-content: flex-end;\n    }\n    .spnl-puzzle-card-img { width: 100%; height: 120px; object-fit: cover; border-radius: 6px; margin-bottom: 0; display: block; border: 1.5px solid #eee; cursor: pointer; transition: box-shadow 0.2s; }\n    .spnl-puzzle-card-img:hover { box-shadow: 0 0 0 3px #f0881f44; }\n    .spnl-puzzle-card-name { font-size: 1em; font-weight: 700; text-align: left; word-break: break-word; margin: 10px 0 4px 0; width: 100%; padding-left: 4px; }\n    .spnl-puzzle-card-brand-row { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 8px; font-size: 1em; color: #444; text-align: left; width: 100%; padding-left: 4px; }\n    .spnl-puzzle-card-brand { flex: 1 1 0; text-align: left; }\n    .spnl-puzzle-card-pieces {\n        flex: 0 0 auto;\n        display: flex;\n        align-items: center;\n        gap: 5px;\n        text-align: right;\n    }\n    .spnl-table-header { border-bottom: 1px solid #ccc; }\n    .spnl-table-header-left { text-align: left; min-width:30px; max-width:30px; }\n    .spnl-table-header-name { text-align: left; width:45%; }\n    .spnl-table-header-time { text-align: right; width:15%;  }\n    .spnl-table-puzzle-header { text-align: center; width: 188px; border-bottom: 1px solid #ccc; }\n    .spnl-table {\n        border-collapse: separate;\n        border-spacing: 0;\n        width: 100%;\n        margin-bottom: 15px;\n        margin: 0 auto;\n        border: none;\n        table-layout: fixed;\n    }\n    col.spnl-col-rank { width: 52px; }\n    col.spnl-col-qualified { width: 28px; }\n    col.spnl-col-puzzle { width: 188px; }\n    col.spnl-col-time { width: 200px; }\n    .spnl-table tr, .spnl-table td, .spnl-table th, .spnl-table-header {\n        border: none !important;\n    }\n    .spnl-table-header, .spnl-table-header-left, .spnl-table-header-name, .spnl-table-header-time, .spnl-table-header.spnl-table-header-name {\n        padding-left: 18px;\n        padding-right: 18px;\n        box-sizing: border-box;\n    }\n    .spnl-table td {\n        padding-left: 18px;\n        padding-right: 18px;\n        box-sizing: border-box;\n    }\n    .spnl-table tr:nth-child(even) td {\n        background: #f8f9fb;\n    }\n    .spnl-table tr:nth-child(odd) td {\n        background: #fff;\n    }\n    .spnl-table-puzzle-cell-wrap {\n        display: flex;\n        flex-direction: row;\n        align-items: center;\n        justify-content: flex-end;\n        gap: 8px;\n        width: 100%;\n        min-width: 0;\n    }\n    .spnl-table-puzzle-cell-inner {\n        display: flex;\n        flex-direction: row;\n        align-items: center;\n        justify-content: flex-end;\n        text-align: right;\n        flex: 0 0 auto;\n        width: auto;\n        min-width: 132px;\n        max-width: none;\n        background: #f8f8f8;\n        border-radius: 8px;\n        padding: 6px 10px;\n        box-sizing: border-box;\n        border: 1px solid #eee;\n        margin: 0;\n        min-height: 42px;\n        gap: 8px;\n        flex-wrap: nowrap;\n        overflow: visible;\n    }\n    .spnl-table-puzzle-cell-inner .spnl-puzzle-row-img-wrap {\n        flex-shrink: 0;\n    }\n    .spnl-table-puzzle-cell-inner .spnl-time-span {\n        font-size: 14px;\n        line-height: 1.2;\n        flex: 0 0 auto;\n        min-width: 0;\n        white-space: nowrap;\n        font-variant-numeric: tabular-nums;\n        color: #222e56;\n        font-weight: 600;\n    }\n    .spnl-table-puzzle-meta-slot {\n        flex: 0 0 38px;\n        width: 38px;\n        min-width: 38px;\n        display: flex;\n        align-items: center;\n        justify-content: flex-start;\n        gap: 2px;\n        overflow: visible;\n    }\n    .spnl-table-puzzle-meta-slot .spnl-time-meta-icons,\n    .spnl-table-puzzle-meta-slot .spnl-time-meta-icons--empty {\n        width: 100%;\n        min-height: 20px;\n        display: inline-flex;\n        align-items: center;\n        justify-content: flex-start;\n        gap: 2px;\n    }\n    .spnl-finish-time-row {\n        display: inline-flex;\n        align-items: center;\n        justify-content: flex-end;\n        gap: 5px;\n        flex-wrap: nowrap;\n        white-space: nowrap;\n        font-size: inherit;\n        line-height: 1.15;\n    }\n    .spnl-finish-time-row .spnl-time-meta-icons {\n        flex: 0 0 auto;\n        display: inline-flex;\n        align-items: center;\n        height: 1.15em;\n    }\n    .spnl-finish-time-row .spnl-result-meta-btn {\n        width: 20px;\n        height: 20px;\n        flex-shrink: 0;\n    }\n    .spnl-finish-time-row .spnl-result-meta-icon {\n        font-size: 16px;\n        line-height: 1;\n        display: block;\n    }\n    .spnl-finish-time-row .spnl-time-meta-icons--empty {\n        display: none;\n    }\n    .spnl-time-row {\n        display: inline-flex;\n        align-items: center;\n        justify-content: flex-end;\n        gap: 4px;\n        flex: 1 1 auto;\n        min-width: 0;\n    }\n    .spnl-time-span {\n        font-size: 14px;\n        line-height: 1.2;\n        color: #222e56;\n        font-weight: 600;\n        margin-right: 0;\n        text-align: right;\n        font-variant-numeric: tabular-nums;\n        white-space: nowrap;\n    }\n    .spnl-time-meta-icons {\n        display: inline-flex;\n        align-items: center;\n        gap: 2px;\n        flex-shrink: 0;\n        overflow: visible;\n    }\n    .spnl-result-meta-btn {\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        width: 20px;\n        height: 20px;\n        padding: 0;\n        margin: 0;\n        border: none;\n        border-radius: 50%;\n        background: transparent;\n        cursor: pointer;\n        -webkit-tap-highlight-color: transparent;\n        transition: background-color 0.15s ease;\n    }\n    .spnl-result-meta-btn:hover,\n    .spnl-result-meta-btn:focus-visible {\n        background: #eef3f9;\n        outline: none;\n    }\n    .spnl-result-meta-icon {\n        font-size: 14px;\n        line-height: 1;\n        color: #004080;\n    }\n    .spnl-result-meta-icon--mfg {\n        color: #e53935;\n    }\n    .spnl-result-meta-btn--mfg {\n        width: 22px;\n        height: 22px;\n        overflow: visible;\n    }\n    .spnl-result-meta-btn--mfg:hover,\n    .spnl-result-meta-btn--mfg:focus-visible {\n        background: #fdeaea;\n    }\n    .spnl-puzzle-piece-icon-svg {\n        width: 20px;\n        height: 20px;\n        display: block;\n        flex-shrink: 0;\n        overflow: visible;\n    }\n    .spnl-puzzle-piece-icon-svg path {\n        fill: none;\n        stroke: currentColor;\n        stroke-width: 1.75;\n        stroke-linejoin: round;\n        stroke-linecap: round;\n    }\n    .spnl-puzzle-piece-icon-svg--mfg {\n        color: #e53935;\n    }\n    .spnl-result-dialog[hidden] {\n        display: none !important;\n    }\n    .spnl-result-dialog {\n        position: fixed;\n        inset: 0;\n        z-index: 100001;\n        display: flex;\n        flex-direction: column;\n        justify-content: flex-end;\n    }\n    .spnl-result-dialog-backdrop {\n        position: absolute;\n        inset: 0;\n        background: rgba(0, 0, 0, 0.35);\n        border: none;\n        padding: 0;\n        cursor: pointer;\n    }\n    .spnl-result-dialog-panel {\n        position: relative;\n        z-index: 1;\n        background: #fff;\n        border-radius: 16px 16px 0 0;\n        padding: 20px 24px 24px;\n        width: 100%;\n        max-height: min(70vh, 420px);\n        overflow-y: auto;\n        box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.18);\n        box-sizing: border-box;\n    }\n    .spnl-result-dialog-header {\n        display: flex;\n        align-items: flex-start;\n        justify-content: space-between;\n        gap: 12px;\n        margin-bottom: 14px;\n    }\n    .spnl-result-dialog-title {\n        margin: 0;\n        font-size: 17px;\n        font-weight: 700;\n        color: #004080;\n        line-height: 1.3;\n    }\n    .spnl-result-dialog-close {\n        flex-shrink: 0;\n        border: none;\n        background: #EDEFF2;\n        color: #222e56;\n        width: 36px;\n        height: 36px;\n        border-radius: 50px;\n        font-size: 22px;\n        line-height: 1;\n        cursor: pointer;\n        font-weight: 600;\n    }\n    .spnl-result-dialog-close:hover {\n        background: #e0e0e0;\n    }\n    .spnl-result-dialog-body {\n        font-size: 15px;\n        line-height: 1.5;\n        color: #222e56;\n        white-space: pre-wrap;\n        word-break: break-word;\n    }\n    .spnl-mobile-time-row {\n        display: inline-flex;\n        align-items: center;\n        gap: 5px;\n        font-size: 16px;\n        line-height: 1.15;\n        color: #004080;\n        font-weight: 600;\n        font-variant-numeric: tabular-nums;\n        white-space: nowrap;\n    }\n    .spnl-mobile-time-row .spnl-result-meta-btn {\n        width: 20px;\n        height: 20px;\n    }\n    .spnl-mobile-time-row .spnl-result-meta-icon {\n        font-size: 16px;\n        line-height: 1;\n        display: block;\n    }\n    .spnl-flag-img {\n        width: 30px;\n        height: 20px;\n        margin: 0 6px 0 0;\n        padding: 0;\n        border-radius: 0;\n        border: none;\n        object-fit: contain;\n        display: block;\n        flex-shrink: 0;\n        box-sizing: content-box;\n    }\n    .spnl-flag-img--global {\n        width: 22px;\n        height: 16px;\n        margin-right: 6px;\n        vertical-align: middle;\n        border-radius: 2px;\n        object-fit: contain;\n        display: inline-block;\n    }\n    .spnl-qualified-badge-slot {\n        flex: 0 0 22px;\n        width: 22px;\n        min-width: 22px;\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        align-self: center;\n        flex-shrink: 0;\n        line-height: 0;\n    }\n    .spnl-qualified-badge {\n        width: 20px;\n        height: 20px;\n        border-radius: 50%;\n        background: #dcefdc;\n        color: #3a7d44;\n        font-size: 11px;\n        font-weight: 700;\n        line-height: 1;\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        flex-shrink: 0;\n        letter-spacing: -0.02em;\n    }\n    .spnl-finish-cell {\n        display: flex;\n        flex-direction: column;\n        align-items: flex-end;\n        justify-content: center;\n        gap: 2px;\n        min-width: 60px;\n        width: 100%;\n        box-sizing: border-box;\n        font-size: 16px;\n    }\n    .spnl-finish-time {\n        font-size: inherit;\n        line-height: 1.15;\n        color: #004080;\n        font-weight: 700;\n        font-variant-numeric: tabular-nums;\n        white-space: nowrap;\n        display: inline-flex;\n        align-items: center;\n    }\n    .spnl-finish-pieces {\n        display: inline-flex;\n        align-items: center;\n        justify-content: flex-end;\n        gap: 4px;\n        font-size: 0.9em;\n        color: #1672b4;\n        margin-top: 2px;\n        line-height: 1;\n    }\n    .spnl-finish-pieces .spnl-puzzle-piece-icon {\n        font-size: 1em;\n        line-height: 1;\n    }\n    .spnl-finish-diff {\n        white-space: nowrap;\n        font-size: 0.85em;\n        line-height: 1.2;\n    }\n    .spnl-finish-diff-prev { color: #f0881f; }\n    .spnl-finish-diff-first { color: #1672b4; }\n    .spnl-finish-diff-sep { color: gray; }\n    .spnl-pieces-span { color:#f0881f;font-size:0.95em; }\n    .spnl-table-empty-puzzle { text-align:left; min-width:100px; max-width:180px; }\n    .spnl-starttijd-label-icon { font-size:1.2em; }\n    .spnl-tijd-label-extra { text-align:left; margin-top:2px; }\n    .spnl-table-cell-dynamic {  \/* width will be set inline by JS, but other styles here *\/ }\n    .spnl-header-card {\n        background: #fff;\n        border-radius: 24px;\n        box-shadow: 0 2px 12px rgba(0,0,0,0.10);\n        padding: 32px 32px;\n        margin-bottom: 24px;\n        width: 100%;\n        box-sizing: border-box;\n    }\n    .spnl-table-header, .spnl-table-cell {\n        font-size: 0.97em;\n        padding: 6px 8px;\n    }\n    .spnl-table-header-time, .spnl-table-cell.time-col {\n        text-align: right;\n        min-width: 160px;\n        max-width: 160px;\n        font-size: 1.05em;\n    }\n    .spnl-table .puzzle-col.time-col {\n        width: 188px;\n        min-width: 188px;\n        max-width: 188px;\n        font-size: 0.97em;\n    }\n    .spnl-table-header-left, .spnl-table-header-name, .spnl-table-header-time {\n        vertical-align: middle;\n    }\n    .spnl-table-header-left, .spnl-table-cell.spnl-table-header-left {\n        text-align: left;\n        padding-left: 12px;\n        width: 36px;\n        min-width: 36px;\n        max-width: 36px;\n        color: #222e56;\n    }\n    .spnl-table-header-name, .spnl-table-header.spnl-table-header-name {\n        text-align: left;\n        min-width: 320px;\n        max-width: 520px;\n        width: 50%;\n    }\n    .spnl-participant-cell {\n        min-width: 325px;\n        max-width: 325px;\n    }\n    .spnl-participants-row.team .spnl-participant-cell {\n        min-width: 0;\n        max-width: none;\n        overflow: hidden;\n    }\n    .spnl-participants-row.team .spnl-participant-name {\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n        min-width: 0;\n        flex: 1 1 auto;\n    }\n\n    .spnl-team-cell {\n        overflow: hidden;\n        padding: 0 8px 0 0;\n        vertical-align: middle;\n    }\n\n    .spnl-table-header-time, .spnl-table-cell.time-col {\n        padding-right: 4px;\n    }\n    .spnl-table tr {\n        height: 71px;\n    }\n    .spnl-table td {\n        padding: 6px 0;\n    }\n    .spnl-table td.spnl-team-cell,\n    .spnl-table td.spnl-data-label-rank,\n    .spnl-table td.spnl-qualified-col {\n        vertical-align: middle;\n    }\n    .spnl-team-name-row {\n        display: block;\n        width: 100%;\n        box-sizing: border-box;\n        margin-bottom: 0;\n        padding-left: 8px;\n        white-space: nowrap;\n        overflow: hidden;\n        text-overflow: ellipsis;\n    }\n    .spnl-team-name-row-inner {\n        display: flex;\n        align-items: center;\n        gap: 10px;\n        font-weight: 500;\n        font-size: 1.1em;\n        flex-wrap: nowrap;\n        width: 100%;\n        justify-content: space-between;\n    }\n    .spnl-team-name {\n        font-size: 1.13em;\n        color: #222e56;\n        font-weight: 500;\n        font-style: normal;\n        overflow: hidden;\n        display: flex;\n        align-items: center;\n        margin-left: -2px;\n        width: 100%;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n        word-break: normal;\n    }\n    .spnl-solo-name-row {\n        display: flex;\n        align-items: center;\n        width: 100%;\n        box-sizing: border-box;\n        margin-bottom: 0;\n        padding-left: 8px;\n        height: 48px;\n        margin-top: 4px;\n    }\n    .spnl-solo-name-row-inner {\n        display: flex;\n        align-items: center;\n        gap: 8px;\n        font-weight: 500;\n        font-size: 1em;\n        flex-wrap: nowrap;\n        width: 100%;\n    }\n    .spnl-solo-name-row-inner > span:not(.spnl-solo-name),\n    .spnl-team-name-row-inner > span:not(.spnl-team-name) {\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        align-self: center;\n        flex-shrink: 0;\n        line-height: 0;\n    }\n    .spnl-solo-name {\n        font-size: 1em;\n        color: #222e56;\n        font-weight: 500;\n        font-style: normal;\n        overflow: hidden;\n        display: flex;\n        align-items: center;\n        margin-left: -2px;\n        width: 100%;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n        word-break: normal;\n    }\n    .spnl-participant-flag {\n        width: 22px;\n        height: 16px;\n        margin-right: 6px;\n        vertical-align: middle;\n        border-radius: 2px;\n        object-fit: contain;\n    }\n    .spnl-participant-name {\n        font-size: 15px;\n        color: #222e56;\n        font-weight: 400;\n        white-space: nowrap;\n        overflow: hidden;\n        text-overflow: ellipsis;\n        display: flex;\n        align-items: center;\n    }\n    .spnl-data-label-rank {\n        width: 52px;\n        min-width: 52px;\n        max-width: 52px;\n        text-align: left;\n        padding-left: 15px !important;\n        white-space: nowrap;\n    }\n    .spnl-qualified-col {\n        width: 28px;\n        min-width: 28px;\n        max-width: 28px;\n        padding: 0 4px !important;\n        text-align: center;\n        vertical-align: middle;\n    }\n    .spnl-qualified-col .spnl-qualified-badge {\n        margin: 0 auto;\n    }\n    .spnl-data-label-time {\n        width: 200px;\n        min-width: 200px;\n        max-width: 200px;\n        text-align: right;\n        padding-right: 8px !important;\n    }\n\n    \/* Puzzle columns: equal fixed width; cards pinned to the right edge *\/\n    .spnl-table td.puzzle-col {\n        padding-left: 0 !important;\n        padding-right: 4px !important;\n        overflow: hidden;\n    }\n    .spnl-table .puzzle-col,\n    .spnl-table .spnl-table-header.spnl-table-puzzle-header {\n        width: 188px;\n        min-width: 188px;\n        max-width: 188px;\n        text-align: right;\n        justify-content: flex-end;\n        box-sizing: border-box;\n    }\n    .spnl-participants-row {\n        display: flex;\n        flex-direction: row;\n        width: 100%;\n        justify-content: flex-start;\n        align-items: stretch;\n        margin-top: 2px;\n    }\n    .spnl-participants-row.duo {\n        min-height: 36px;\n        height: 36px;\n        margin-top: 0px;\n        gap: 0;\n    }\n    .spnl-participants-row.duo .spnl-participant-cell {\n        flex: 1 1 0;\n        min-width: 0;\n        max-width: none;\n        overflow: hidden;\n    }\n    .spnl-participants-row.duo .spnl-participant-name {\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n        min-width: 0;\n        flex: 1 1 auto;\n    }\n    .spnl-participants-row.team {\n        flex-direction: column;\n        min-height: 60px;\n        height: 60px;\n        gap: 2px;\n    }\n    .spnl-participants-row.team .spnl-participant-row {\n        display: flex;\n        flex-direction: row;\n        gap: 0;\n        width: 100%;\n    }\n    \/* Member flags align with team flag (same row padding) *\/\n    .spnl-participants-row.spnl-participants-row--aligned {\n        padding-left: 0;\n        box-sizing: border-box;\n    }\n    .spnl-participant-cell {\n        display: flex;\n        align-items: center;\n        gap: 6px;\n        font-size: 14px;\n        padding: 0 8px;\n        border: none;\n        justify-content: flex-start;\n        flex: 1 1 0;\n    }\n    \/* Duo: wider participant columns, narrower puzzle columns *\/\n    .spnl-table.duo-mode .spnl-table-header-name,\n    .spnl-table.duo-mode .spnl-table-cell.spnl-table-header-name {\n        min-width: 230px;\n        max-width: 320px;\n        width: 30%;\n    }\n    .spnl-table.duo-mode .puzzle-col {\n        width: 188px;\n        min-width: 188px;\n        max-width: 188px;\n    }\n    .spnl-participants-2col {\n        display: flex;\n        flex-direction: row;\n        gap: 12px;\n        width: 100%;\n        margin-top: 2px;\n    }\n    .spnl-participants-col {\n        flex: 1 1 0;\n        display: flex;\n        flex-direction: column;\n        gap: 2px;\n    }\n    .spnl-participant-row {\n        display: flex;\n        align-items: center;\n        gap: 4px;\n        font-size: 13px;\n        margin-bottom: 2px;\n    }\n    .spnl-participant-name {\n        color: #222e56;\n        font-weight: 400;\n    }\n    .spnl-stats-wrapper {\n        display: flex;\n        flex-direction: row;\n        gap: 16px;\n        align-items: center;\n        flex-wrap: wrap;\n    }\n    \/* --- Responsive\/mobile media queries --- *\/\n    @media (max-width: 900px) {\n      .spnl-header-two-col {\n        flex-direction: column;\n        min-height: unset;\n      }\n      \/* Make info blocks stack vertically *\/\n      div[style*=\"margin-top: 24px; display: flex; gap: 16px;\"] {\n        flex-direction: column !important;\n      }\n      div[style*=\"margin-top: 24px; display: flex; gap: 16px;\"] > div {\n        width: 100% !important;\n      }\n      .spnl-header-left, .spnl-header-right {\n        min-width: 0;\n        max-width: 100%;\n        width: 100%;\n      }\n      .spnl-header-right {\n        align-items: stretch;\n        min-width: 0;\n      }\n      .spnl-puzzle-cards {\n        display: flex;\n        flex-direction: column;\n        align-items: stretch;\n        gap: 16px;\n        width: 100%;\n      }\n      .spnl-puzzle-card {\n        min-width: 0;\n        max-width: 100%;\n        width: 100%;\n        margin-bottom: 8px;\n      }\n      .spnl-header-title-row {\n        flex-direction: column;\n        align-items: flex-start;\n        gap: 10px;\n      }\n      .spnl-header-title-main {\n        margin-bottom: 18px !important;\n        text-align: center !important;\n        font-size: 1.35em !important;\n        display: block !important;\n        width: 100% !important;\n      }\n      .spnl-header-title-timer {\n        margin-top: 10px !important;\n        display: flex !important;\n        justify-content: center !important;\n        align-items: center !important;\n        text-align: center !important;\n        width: 100% !important;\n      }\n      .spnl-timer-card {\n        margin: 0 auto !important;\n      }\n      .spnl-timer-display {\n        font-size: 2.1em !important;\n      }\n\n      \/* Mobile ranking card styles *\/\n      .spnl-mobile-ranking-card-full {\n        background: #fff;\n        border-radius: 16px;\n        box-shadow: 0 2px 8px rgba(0,0,0,0.06);\n        padding: 16px 12px;\n        margin-bottom: 16px;\n        width: 100%;\n        box-sizing: border-box;\n      }\n\n      \/* Team and participant styles \u2014 flag + name, aligned with rank\/puzzle column *\/\n      .spnl-mobile-team-name-row,\n      .spnl-mobile-participant-cell {\n        display: flex !important;\n        flex-direction: row;\n        align-items: center;\n        gap: 8px;\n        width: 100%;\n        max-width: 100%;\n        box-sizing: border-box;\n        min-width: 0;\n        min-height: 26px;\n        padding: 0;\n        position: static;\n      }\n      .spnl-mobile-team-name-row {\n        font-size: 1.13em;\n        font-weight: 600;\n        margin-bottom: 4px;\n      }\n      .spnl-mobile-rank-row {\n        display: flex;\n        align-items: center;\n        gap: 8px;\n        padding: 0;\n      }\n      .spnl-mobile-rank-row .spnl-qualified-badge-slot {\n        flex: 0 0 auto;\n        width: auto;\n        min-width: 0;\n      }\n      .spnl-mobile-team-name-row .spnl-flag-img,\n      .spnl-mobile-participant-cell .spnl-flag-img {\n        position: static;\n        transform: none;\n        flex: 0 0 26px;\n        width: 26px !important;\n        height: 18px !important;\n        margin: 0 !important;\n        border-radius: 2px !important;\n        object-fit: contain !important;\n        display: block !important;\n      }\n      .spnl-mobile-team-name-row .spnl-flag-img--global,\n      .spnl-mobile-participant-cell .spnl-flag-img--global {\n        flex-basis: 22px;\n        width: 22px !important;\n        height: 16px !important;\n      }\n\n      .spnl-mobile-participants-section {\n        margin: 0 0 12px 0;\n        display: flex;\n        flex-direction: column;\n        gap: 4px;\n        padding-left: 0;\n        width: 100%;\n        box-sizing: border-box;\n      }\n      .spnl-mobile-name-value {\n        padding-left: 0;\n      }\n      .spnl-mobile-rank-row,\n      .spnl-mobile-finish-time,\n      .spnl-mobile-finish-pieces {\n        padding-left: 0 !important;\n      }\n\n      .spnl-mobile-puzzles-section {\n        width: 100%;\n        box-sizing: border-box;\n        min-width: 0;\n      }\n\n      .spnl-mobile-puzzle-row {\n        display: flex;\n        align-items: center;\n        gap: 8px;\n        width: 100%;\n        margin-bottom: 8px;\n      }\n      .spnl-mobile-puzzle-card {\n        flex: 1 1 auto;\n        min-width: 0;\n        display: flex;\n        align-items: center;\n        gap: 12px;\n        background: #f8f8f8;\n        border-radius: 8px;\n        padding: 8px;\n        border: 1px solid #eee;\n        box-sizing: border-box;\n      }\n      .spnl-mobile-puzzle-meta-slot {\n        flex: 0 0 46px;\n        width: 46px;\n        min-width: 46px;\n        display: flex;\n        align-items: center;\n        justify-content: flex-start;\n        overflow: visible;\n      }\n      .spnl-mobile-puzzle-meta-slot .spnl-time-meta-icons,\n      .spnl-mobile-puzzle-meta-slot .spnl-time-meta-icons--empty {\n        width: 100%;\n        min-height: 20px;\n        display: inline-flex;\n        align-items: center;\n        justify-content: flex-start;\n        gap: 2px;\n      }\n\n      .spnl-mobile-value {\n        width: 100%;\n        max-width: 100%;\n        box-sizing: border-box;\n        min-width: 0;\n        flex: 1 1 0;\n      }\n\n      .spnl-mobile-card-inner {\n        width: 100%;\n        max-width: 100%;\n        box-sizing: border-box;\n        min-width: 0;\n      }\n\n      .spnl-mobile-participants-section .spnl-participant-cell {\n        margin-bottom: 4px !important;\n        min-height: 26px;\n        flex: none !important;\n        width: 100% !important;\n        max-width: 100% !important;\n      }\n\n      .spnl-mobile-team-name,\n      .spnl-mobile-participant-name,\n      .spnl-mobile-puzzle-name {\n        white-space: normal !important;\n        word-break: break-word !important;\n        overflow-wrap: break-word !important;\n        text-overflow: initial !important;\n        overflow: visible !important;\n        min-width: 0 !important;\n        padding-right: 8px !important;\n        box-sizing: border-box !important;\n      }\n\n      .spnl-mobile-team-name,\n      .spnl-mobile-participant-name {\n        display: block;\n        min-width: 0;\n        max-width: 100%;\n        width: auto;\n        flex: 1 1 auto;\n      }\n\n      .spnl-mobile-puzzle-name {\n        width: 100%;\n        max-width: 100%;\n      }\n\n      .spnl-mobile-team-name {\n        \/* font-size: 1.13em; *\/\n        font-weight: 600;\n        color: #222e56;\n      }\n\n      .spnl-mobile-puzzle-name {\n        font-size: 0.95em;\n        font-weight: 500;\n        color: #222e56;\n      }\n\n      .spnl-mobile-participant-name {\n        font-size: 0.92em;\n        font-weight: 500;\n        color: #222e56;\n      }\n\n      \/* Override desktop participant name styles for mobile wrapping *\/\n      .spnl-participant-name {\n        white-space: normal !important;\n        word-break: break-word !important;\n        overflow-wrap: break-word !important;\n        text-overflow: initial !important;\n        overflow: visible !important;\n        min-width: 0 !important;\n        flex: 1 1 0 !important;\n      }\n\n      .spnl-participants-section .spnl-participant-cell,\n      .spnl-mobile-participants-section .spnl-participant-cell {\n        min-width: 0 !important;\n        max-width: 100% !important;\n      }\n\n      .spnl-stats-wrapper {\n        flex-direction: column;\n        gap: 4px;\n        align-items: flex-start;\n      }\n\n      .spnl-header-title-main {\n        font-size: 1.15em !important;\n        margin-bottom: 16px !important;\n      }\n\n      .spnl-timer-display {\n        font-size: 1.7em !important;\n      }\n\n      .spnl-mobile-ranking-card-full {\n        padding: 14px 10px;\n        border-radius: 14px;\n        margin-bottom: 14px;\n      }\n\n      .spnl-mobile-team-name-row {\n        font-size: 1.02em;\n      }\n\n      .spnl-mobile-puzzle-name {\n        font-size: 0.9em;\n      }\n\n      .spnl-mobile-participant-name {\n        font-size: 0.90em;\n      }\n\n      .spnl-mobile-card-inner.spnl-mobile-card-grid {\n        gap: 0.4em;\n      }\n\n      .spnl-ranking-toolbar {\n        gap: 10px;\n        padding: 0 2vw;\n      }\n\n      #spnl-round-buttons {\n        flex-direction: column;\n        gap: 10px;\n        padding: 0;\n      }\n\n      .spnl-round-button-row {\n        flex-direction: column;\n        width: 100%;\n        gap: 10px;\n      }\n\n      .spnl-round-button-group {\n        flex-direction: column;\n        width: 100%;\n        flex-wrap: nowrap;\n      }\n\n      .spnl-round-tab {\n        width: 100%;\n        min-width: 0;\n        font-size: 1em;\n        padding: 14px 10px;\n      }\n\n      #spnl-ranking-controls {\n        flex-direction: column;\n        align-items: stretch;\n        gap: 10px;\n        padding: 0;\n      }\n      .spnl-control-group {\n        width: 100%;\n        justify-content: flex-start;\n      }\n      .spnl-select {\n        flex: 1;\n        min-width: 0;\n        max-width: none;\n        width: auto;\n      }\n    }\n\n    @media (max-width: 600px) {\n      .spnl-header-card {\n        padding: 16px 12px;\n        border-radius: 12px;\n      }\n      \/* Ensure info blocks stack vertically *\/\n      div[style*=\"margin-top: 24px; display: flex; gap: 16px;\"] {\n        flex-direction: column !important;\n        gap: 8px !important;\n      }\n      div[style*=\"margin-top: 24px; display: flex; gap: 16px;\"] > div {\n        width: 100% !important;\n      }\n\n      .spnl-header-title-main {\n        font-size: 1.15em !important;\n        margin-bottom: 16px !important;\n      }\n\n      .spnl-timer-display {\n        font-size: 1.7em !important;\n      }\n\n      .spnl-mobile-ranking-card-full {\n        padding: 14px 10px;\n        border-radius: 14px;\n        margin-bottom: 14px;\n      }\n\n      .spnl-mobile-team-name-row {\n        font-size: 1.02em;\n      }\n\n      .spnl-mobile-puzzle-name {\n        font-size: 0.9em;\n      }\n\n      .spnl-mobile-participant-name {\n        font-size: 0.90em;\n      }\n\n      .spnl-mobile-card-inner.spnl-mobile-card-grid {\n        gap: 0.4em;\n      }\n\n      .spnl-ranking-toolbar {\n        gap: 10px;\n        padding: 0 2vw;\n      }\n\n      #spnl-round-buttons {\n        flex-direction: column;\n        gap: 10px;\n        padding: 0;\n      }\n\n      .spnl-round-button-row {\n        flex-direction: column;\n        width: 100%;\n        gap: 10px;\n      }\n\n      .spnl-round-button-group {\n        flex-direction: column;\n        width: 100%;\n        flex-wrap: nowrap;\n      }\n\n      .spnl-round-tab {\n        width: 100%;\n        min-width: 0;\n        font-size: 1em;\n        padding: 14px 10px;\n      }\n\n      #spnl-ranking-controls {\n        flex-direction: column;\n        align-items: stretch;\n        gap: 10px;\n        padding: 0;\n      }\n      .spnl-control-group {\n        width: 100%;\n        justify-content: flex-start;\n      }\n      .spnl-select {\n        flex: 1;\n        min-width: 0;\n        max-width: none;\n        width: auto;\n      }\n    }\n    .spnl-team-name {\n        font-size: 1.13em;\n        color: #222e56;\n        font-weight: 500;\n        font-style: normal;\n        overflow: hidden;\n        display: flex;\n        align-items: center;\n        margin-left: -2px;\n        width: 100%;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n        word-break: normal;\n    }\n    .spnl-team-name-row .spnl-flag-img,\n    .spnl-team-name-row .spnl-flag-img--global,\n    .spnl-solo-name-row .spnl-flag-img,\n    .spnl-solo-name-row .spnl-flag-img--global,\n    .spnl-participant-cell .spnl-flag-img {\n        width: 22px;\n        height: 16px;\n        margin-right: 0;\n        vertical-align: middle;\n        border-radius: 2px;\n        object-fit: contain;\n        display: block;\n        flex-shrink: 0;\n        border: none;\n    }\n    .spnl-team-name-row .spnl-flag-img--global,\n    .spnl-solo-name-row .spnl-flag-img--global,\n    .spnl-participant-cell .spnl-flag-img--global {\n        width: 22px;\n        height: 16px;\n        margin-right: 0;\n        vertical-align: middle;\n        border-radius: 2px;\n        object-fit: contain;\n        display: block;\n        flex-shrink: 0;\n        border: none;\n      }\n    .spnl-lightbox-overlay {\n        position: fixed;\n        top: 0; left: 0; right: 0; bottom: 0;\n        background: rgba(0,0,0,0.85);\n        z-index: 9999;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        cursor: zoom-out;\n        animation: fadeIn 0.2s;\n    }\n    .spnl-lightbox-img {\n        max-width: 90vw;\n        max-height: 90vh;\n        border-radius: 12px;\n        box-shadow: 0 4px 32px rgba(0,0,0,0.25);\n        background: #fff;\n        padding: 8px;\n        cursor: auto;\n        animation: popIn 0.2s;\n    }\n    @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n    @keyframes popIn { from { transform: scale(0.95); opacity: 0; } to { transform: scale(1); opacity: 1; } }\n    .spnl-table tr:nth-child(even) {\n        background: #f8f9fb;\n    }\n    .spnl-table tr:nth-child(odd) {\n        background: #fff;\n    }\n    .spnl-disqualified-row,\n    .spnl-disqualified-row td,\n    .spnl-disqualified-row th,\n    .spnl-disqualified-row .spnl-team-cell,\n    .spnl-disqualified-row .spnl-participant-cell,\n    .spnl-disqualified-row .spnl-data-label-rank,\n    .spnl-disqualified-row .spnl-data-label-time,\n    .spnl-disqualified-row td .spnl-table-puzzle-cell-inner {\n        \/* background: #ffcccc !important; *\/\n        \/* box-shadow: none !important; *\/\n    }\n    .spnl-disqualified-row td .spnl-table-puzzle-cell-inner {\n        \/* background: #f8a8a8 !important; *\/\n        \/* border: 1px solid #e57373 !important; *\/\n    }\n    .spnl-disqualified-label {\n        display: flex;\n        align-items: center;\n        justify-content: flex-end;\n        background: #e53935;\n        color: #fff;\n        font-size: 0.80em;\n        font-weight: 700;\n        border-radius: 8px;\n        padding: 2px 10px;\n        margin-left: 12px;\n        letter-spacing: 0.04em;\n        vertical-align: middle;\n        min-width: 120px;\n        height: 28px;\n    }\n    .spnl-disqualified-cross {\n        color: #e53935;\n        font-size: 1.05em;\n        vertical-align: middle;\n        display: inline-block;\n        line-height: 1;\n        position: relative;\n        top: 1px;\n        margin-left: -2px;\n        font-family: inherit;\n    }\n    .spnl-loading {\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        width: 100%;\n        padding: 40px 16px;\n        box-sizing: border-box;\n    }\n    .spnl-loading--inline {\n        padding: 16px;\n    }\n    .spnl-spinner {\n        width: 36px;\n        height: 36px;\n        border: 3px solid #e8ecf2;\n        border-top-color: #004080;\n        border-radius: 50%;\n        animation: spnl-spin 0.75s linear infinite;\n        flex-shrink: 0;\n    }\n    .spnl-spinner--sm {\n        width: 26px;\n        height: 26px;\n        border-width: 2px;\n    }\n    @keyframes spnl-spin {\n        to { transform: rotate(360deg); }\n    }\n    .spnl-sr-only {\n        position: absolute;\n        width: 1px;\n        height: 1px;\n        padding: 0;\n        margin: -1px;\n        overflow: hidden;\n        clip: rect(0, 0, 0, 0);\n        white-space: nowrap;\n        border: 0;\n    }\n    @media (min-width: 640px) {\n        .spnl-result-dialog {\n            justify-content: center;\n            align-items: center;\n            padding: 24px;\n        }\n        .spnl-result-dialog-panel {\n            border-radius: 16px;\n            width: min(100%, 540px);\n            max-height: min(80vh, 480px);\n        }\n    }\n    <\/style>\n\n    <div class=\"spnl-ranking-toolbar\">\n    <div id=\"spnl-round-buttons\" role=\"tablist\" aria-label=\"Rounds\"><\/div>\n    <div id=\"spnl-ranking-controls\">\n        <div class=\"spnl-control-group\" id=\"spnl-definition-control\">\n            <select id=\"spnl-ranking-definition-select\" class=\"spnl-select\"><\/select>\n        <\/div>\n        <div class=\"spnl-control-group\" id=\"spnl-intermediate-control\">\n            <label class=\"spnl-toggle\" for=\"spnl-intermediate-toggle\">\n                <input type=\"checkbox\" id=\"spnl-intermediate-toggle\">\n                <span class=\"spnl-toggle-track\" aria-hidden=\"true\"><\/span>\n                <span class=\"spnl-toggle-text\" id=\"spnl-intermediate-toggle-text\"><\/span>\n            <\/label>\n        <\/div>\n    <\/div>\n    <\/div>\n    <div id=\"spnl-ranking-output\"><\/div>\n    <div id=\"spnl-result-dialog\" class=\"spnl-result-dialog\" hidden>\n        <button type=\"button\" class=\"spnl-result-dialog-backdrop\" aria-label=\"\"><\/button>\n        <div class=\"spnl-result-dialog-panel\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"spnl-result-dialog-title\">\n            <div class=\"spnl-result-dialog-header\">\n                <h3 id=\"spnl-result-dialog-title\" class=\"spnl-result-dialog-title\"><\/h3>\n                <button type=\"button\" class=\"spnl-result-dialog-close\" aria-label=\"\">&times;<\/button>\n            <\/div>\n            <div class=\"spnl-result-dialog-body\"><\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n    var spnlApiBase = \"https:\\\/\\\/puzzled.events\\\/\";\n    var spnlCompetitionUuid = \"019cba8d-d004-717c-9f4d-45a80ed4d4d3\";\n    var competitionRoundsById = {};\n\n    function spnlLanguage() {\n        return window.location.pathname.indexOf('\/en\/') !== -1 ? 'en-GB' : 'nl-NL';\n    }\n\n    function spnlApiUrl(path) {\n        var url = spnlApiBase + String(path).replace(\/^\\\/\/, '');\n        var sep = url.indexOf('?') >= 0 ? '&' : '?';\n        return url + sep + 'language=' + encodeURIComponent(spnlLanguage());\n    }\n\n    \/\/ UI translations (labels not provided by API)\n    function isEnglish() {\n        return spnlLanguage() === 'en-GB';\n    }\n    var translations = {\n        nl: {\n            participants: \"Deelnemers:\",\n            duos: \"Duo's:\",\n            teams: \"Teams:\",\n            finished: \"Gefinisht:\",\n            disqualified: \"Gediskwalificeerd:\",\n            disqualifiedLabel: \"GEDISKWALIFICEERD\",\n            showIntermediate: \"Toon tussentijds\",\n            notFinished: \"Niet gefinisht:\",\n            finishedSection: \"Gefinisht\",\n            notFinishedSection: \"Niet gefinisht\",\n            qualified: \"Gekwalificeerd\",\n            loading: \"Laden\u2026\",\n            remark: \"Opmerking\",\n            viewRemark: \"Opmerking bekijken\",\n            puzzleMissingPiecesTitle: \"Ontbrekende stukjes\",\n            puzzleMissingPieces: \"De puzzel mist {count} stukjes\",\n            close: \"Sluiten\"\n        },\n        en: {\n            participants: \"Participants:\",\n            duos: \"Pairs:\",\n            teams: \"Teams:\",\n            finished: \"Finished:\",\n            disqualified: \"Disqualified:\",\n            disqualifiedLabel: \"DISQUALIFIED\",\n            showIntermediate: \"Show intermediate\",\n            notFinished: \"Not finished:\",\n            finishedSection: \"Finished\",\n            notFinishedSection: \"Not finished\",\n            qualified: \"Qualified\",\n            loading: \"Loading\u2026\",\n            remark: \"Remark\",\n            viewRemark: \"View remark\",\n            puzzleMissingPiecesTitle: \"Missing pieces\",\n            puzzleMissingPieces: \"The puzzle is missing {count} pieces\",\n            close: \"Close\"\n        }\n    };\n    function t(key) {\n        var lang = isEnglish() ? 'en' : 'nl';\n        return translations[lang][key] || key;\n    }\n    \n    \/\/ Translate round names from JSON data\n    function translateRoundName(name) {\n        if (!name || !isEnglish()) return name;\n        \/\/ Common translations for round names\n        return name\n            .replace(\/Ronde\\s+(\\d+)\/gi, 'Round $1')\n            .replace(\/Ronde\/gi, 'Round')\n            .replace(\/Finale\/gi, 'Final')\n            .replace(\/Duo's\/gi, 'Pairs')\n            .replace(\/Duo\/gi, 'Pair');\n    }\n    \n    \/\/ Timer and formatting helpers (global)\n    function pad2(n) { return n < 10 ? '0' + n : n; }\n    function formatTime(seconds) {\n        if (typeof seconds === 'string' && seconds.indexOf(':') !== -1) {\n            \/\/ If already formatted, ensure it's HH:MM:SS\n            var parts = seconds.split(':');\n            while (parts.length < 3) parts.unshift('00');\n            return parts.map(function(p) { return p.length < 2 ? '0' + p : p; }).join(':');\n        }\n        seconds = Math.max(0, parseInt(seconds, 10) || 0);\n        var h = Math.floor(seconds \/ 3600);\n        var m = Math.floor((seconds % 3600) \/ 60);\n        var s = seconds % 60;\n        return (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n    }\n    function formatTimeShort(seconds) {\n        if (typeof seconds === 'string' && seconds.indexOf(':') !== -1) {\n            var parts = seconds.split(':');\n            while (parts.length < 2) parts.unshift('00');\n            \/\/ Only MM:SS\n            return (parts[1].length < 2 ? '0' + parts[1] : parts[1]) + ':' + (parts[2] && parts[2].length < 2 ? '0' + parts[2] : (parts[2] || '00'));\n        }\n        seconds = Math.max(0, parseInt(seconds, 10) || 0);\n        var m = Math.floor(seconds \/ 60);\n        var s = seconds % 60;\n        return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n    }\n    \/\/ Format for orange '+diff to previous' (always mm:ss)\n    function formatDiffPrev(seconds) {\n        if (typeof seconds !== 'number') seconds = parseInt(seconds, 10) || 0;\n        seconds = Math.max(0, seconds);\n        var m = Math.floor(seconds \/ 60);\n        var s = seconds % 60;\n        return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n    }\n    \/\/ Format for blue '+diff to first' (hh:mm:ss if over 1 hour, else mm:ss)\n    function formatDiffFirst(seconds) {\n        if (typeof seconds !== 'number') seconds = parseInt(seconds, 10) || 0;\n        seconds = Math.max(0, seconds);\n        if (seconds >= 3600) {\n            var h = Math.floor(seconds \/ 3600);\n            var m = Math.floor((seconds % 3600) \/ 60);\n            var s = seconds % 60;\n            return (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n        } else {\n            var m = Math.floor(seconds \/ 60);\n            var s = seconds % 60;\n            return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n        }\n    }\n    function formatHM(date) {\n        if (!date) return '-';\n        return pad2(date.getHours()) + ':' + pad2(date.getMinutes());\n    }\n\n    function formatDate(date) {\n        if (!date) return '-';\n        return pad2(date.getDate()) + '-' + pad2(date.getMonth() + 1) + '-' + date.getFullYear();\n    }\n\n    function spnlPuzzleImageSizeUrl(url, size) {\n        if (!url) return \"\";\n        var target = size === \"large\" ? \"large\" : \"medium\";\n        return url\n            .replace(\/-small(\\.(png|jpe?g|webp|gif))\/i, \"-\" + target + \"$1\")\n            .replace(\/-medium(\\.(png|jpe?g|webp|gif))\/i, target === \"large\" ? \"-large$1\" : \"-medium$1\");\n    }\n\n    function spnlPuzzleImageUrl(puzzle, size) {\n        if (!puzzle || !puzzle.image) return \"\";\n        var url = typeof puzzle.image === \"string\" ? puzzle.image : (puzzle.image.url || \"\");\n        return spnlPuzzleImageSizeUrl(url, size || \"medium\");\n    }\n\n    function spnlMemberDisplayName(member) {\n        if (!member) return \"-\";\n        return [member.first_name, member.insertion, member.last_name].filter(Boolean).join(\" \") || \"-\";\n    }\n\n    function spnlCoerceBool(value) {\n        if (value === true || value === 1) return true;\n        if (value === false || value === 0 || value === null || value === undefined) return false;\n        if (typeof value === \"string\") {\n            var normalized = value.trim().toLowerCase();\n            if (normalized === \"true\" || normalized === \"1\" || normalized === \"yes\") return true;\n            if (normalized === \"false\" || normalized === \"0\" || normalized === \"no\" || normalized === \"\") return false;\n        }\n        return !!value;\n    }\n\n    \/\/ Intermediate: provisional true = not finished, provisional false = finished.\n    function spnlEntryIsProvisional(entry) {\n        if (!entry || typeof entry !== \"object\") return false;\n        var value = entry.provisional;\n        if (value === undefined && entry.is_provisional !== undefined) value = entry.is_provisional;\n        if (value === undefined || value === null) return false;\n        return spnlCoerceBool(value);\n    }\n\n    function spnlEntryIsExcludedFromRanking(entry) {\n        if (!entry || typeof entry !== \"object\") return false;\n        var value = entry.excluded_from_ranking;\n        if (value === undefined && entry.is_excluded_from_ranking !== undefined) value = entry.is_excluded_from_ranking;\n        if (value === undefined && entry.exclude_from_ranking !== undefined) value = entry.exclude_from_ranking;\n        if (value === undefined && entry.excluded !== undefined) value = entry.excluded;\n        if (value === undefined && entry.result_data && typeof entry.result_data === \"object\") {\n            var rd = entry.result_data;\n            if (rd.excluded_from_ranking !== undefined) value = rd.excluded_from_ranking;\n            else if (rd.is_excluded_from_ranking !== undefined) value = rd.is_excluded_from_ranking;\n            else if (rd.exclude_from_ranking !== undefined) value = rd.exclude_from_ranking;\n        }\n        return spnlCoerceBool(value);\n    }\n\n    function spnlPuzzleManufacturingErrorPieces(puzzle) {\n        if (!puzzle) return 0;\n        var value = puzzle.manufacturing_error_pieces;\n        if (value == null && puzzle.manufacturing_missing_pieces != null) value = puzzle.manufacturing_missing_pieces;\n        if (value == null && puzzle.manufacturer_error_pieces != null) value = puzzle.manufacturer_error_pieces;\n        if (value == null && puzzle.manufacturing_error != null) value = puzzle.manufacturing_error;\n        return spnlCoercePositiveInt(value);\n    }\n\n    function spnlPuzzleHasMeta(puzzle) {\n        if (!puzzle) return false;\n        return !!(spnlExtractTextValue(puzzle.annotation) || spnlPuzzleManufacturingErrorPieces(puzzle) > 0);\n    }\n\n    function spnlPuzzlePieceIconHtml(extraClass) {\n        var cls = \"spnl-puzzle-piece-icon-svg\" + (extraClass ? \" \" + extraClass : \"\");\n        return \"<svg class='\" + cls + \"' viewBox='0 0 24 24' aria-hidden='true' focusable='false' overflow='visible'>\" +\n            \"<g transform='translate(12 12) rotate(45) scale(0.72) translate(-12 -12)'>\" +\n            \"<path d='M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-2 .9-2 2v3.8h1.5c1.38 0 2.5 1.12 2.5 2.5S4.88 15.8 3.5 15.8H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z'\/>\" +\n            \"<\/g><\/svg>\";\n    }\n\n    function spnlExtractTextValue(value) {\n        if (value == null) return \"\";\n        if (typeof value === \"string\") return value.trim();\n        if (typeof value === \"number\") return String(value);\n        if (typeof value === \"object\") {\n            var lang = spnlLanguage();\n            if (value[lang]) return String(value[lang]).trim();\n            if (value[\"en-GB\"]) return String(value[\"en-GB\"]).trim();\n            if (value[\"nl-NL\"]) return String(value[\"nl-NL\"]).trim();\n            var keys = Object.keys(value);\n            return keys.length ? String(value[keys[0]]).trim() : \"\";\n        }\n        return \"\";\n    }\n\n    function spnlEscapeAttr(str) {\n        return String(str == null ? \"\" : str)\n            .replace(\/&\/g, \"&amp;\")\n            .replace(\/\"\/g, \"&quot;\")\n            .replace(\/<\/g, \"&lt;\")\n            .replace(\/>\/g, \"&gt;\");\n    }\n\n    function spnlCoercePositiveInt(value) {\n        if (value == null || value === \"\") return 0;\n        var n = parseInt(value, 10);\n        return isNaN(n) || n <= 0 ? 0 : n;\n    }\n\n    function spnlFindResultPuzzleMeta(resultPuzzles, puzzle) {\n        if (!puzzle || !Array.isArray(resultPuzzles)) return null;\n        var puzzleId = puzzle.puzzle_id || puzzle.id;\n        if (!puzzleId) return null;\n        for (var i = 0; i < resultPuzzles.length; i++) {\n            var rp = resultPuzzles[i];\n            if (!rp) continue;\n            if (rp.puzzle_id === puzzleId || rp.id === puzzleId) return rp;\n        }\n        return null;\n    }\n\n    function spnlMergePuzzleWithResultData(puzzle, resultPuzzles) {\n        var merged = Object.assign({}, puzzle || {});\n        var meta = spnlFindResultPuzzleMeta(resultPuzzles, merged);\n        if (meta) {\n            if (meta.annotation != null && merged.annotation == null) merged.annotation = meta.annotation;\n            if (meta.manufacturing_error_pieces != null && merged.manufacturing_error_pieces == null) {\n                merged.manufacturing_error_pieces = meta.manufacturing_error_pieces;\n            }\n            if (meta.manufacturing_missing_pieces != null && merged.manufacturing_error_pieces == null) {\n                merged.manufacturing_error_pieces = meta.manufacturing_missing_pieces;\n            }\n            if (meta.manufacturer_error_pieces != null && merged.manufacturing_error_pieces == null) {\n                merged.manufacturing_error_pieces = meta.manufacturer_error_pieces;\n            }\n        }\n        return merged;\n    }\n\n    function spnlTimeMetaIconsHtml(opts) {\n        opts = opts || {};\n        var html = \"\";\n        var annotation = spnlExtractTextValue(opts.annotation);\n        var mfgPieces = spnlCoercePositiveInt(opts.manufacturingErrorPieces);\n        if (mfgPieces > 0) {\n            var mfgBody = t(\"puzzleMissingPieces\").replace(\"{count}\", String(mfgPieces));\n            html += \"<button type='button' class='spnl-result-meta-btn spnl-result-meta-btn--mfg' aria-label='\" + spnlEscapeAttr(mfgBody) +\n                \"' data-spnl-dialog-title='\" + spnlEscapeAttr(t(\"puzzleMissingPiecesTitle\")) +\n                \"' data-spnl-dialog-body='\" + spnlEscapeAttr(mfgBody) +\n                \"'>\" + spnlPuzzlePieceIconHtml(\"spnl-puzzle-piece-icon-svg--mfg\") + \"<\/button>\";\n        } else if (annotation) {\n            html += \"<button type='button' class='spnl-result-meta-btn spnl-result-meta-btn--info' aria-label='\" + spnlEscapeAttr(t(\"viewRemark\")) +\n                \"' data-spnl-dialog-title='\" + spnlEscapeAttr(t(\"remark\")) +\n                \"' data-spnl-dialog-body='\" + spnlEscapeAttr(annotation) +\n                \"'><span class='material-icons spnl-result-meta-icon' aria-hidden='true'>info<\/span><\/button>\";\n        }\n        if (!html) {\n            return \"<span class='spnl-time-meta-icons spnl-time-meta-icons--empty' aria-hidden='true'><\/span>\";\n        }\n        return \"<span class='spnl-time-meta-icons'>\" + html + \"<\/span>\";\n    }\n\n    function spnlPuzzleDesktopCellHtml(timeStr, metaHtml, imgUrl) {\n        var cardInner = (imgUrl ? (\"<span class='spnl-puzzle-row-img-wrap'><img class='spnl-puzzle-row-img' src='\" + imgUrl + \"' alt=''><\/span>\") : \"\") +\n            \"<span class='spnl-time-span'>\" + timeStr + \"<\/span>\";\n        return \"<div class='spnl-table-puzzle-cell-wrap'>\" +\n            \"<div class='spnl-table-puzzle-cell-inner'>\" + cardInner + \"<\/div>\" +\n            \"<div class='spnl-table-puzzle-meta-slot'>\" + (metaHtml || \"<span class='spnl-time-meta-icons spnl-time-meta-icons--empty' aria-hidden='true'><\/span>\") + \"<\/div>\" +\n            \"<\/div>\";\n    }\n\n    function spnlTimeRowHtml(timeText, metaHtml, timeClass) {\n        return \"<span class='spnl-time-row'>\" + (metaHtml || \"\") +\n            \"<span class='\" + (timeClass || \"spnl-time-span\") + \"'>\" + timeText + \"<\/span><\/span>\";\n    }\n\n    function spnlExtractResultAnnotation(entry) {\n        if (!entry || typeof entry !== \"object\") return \"\";\n        var sources = [\n            entry.annotation,\n            entry.remark,\n            entry.result_data && entry.result_data.annotation,\n            entry.result_data && entry.result_data.remark,\n            entry.result && entry.result.annotation,\n            entry.result && entry.result.remark,\n            entry.result && entry.result.result_data && entry.result.result_data.annotation\n        ];\n        for (var i = 0; i < sources.length; i++) {\n            var text = spnlExtractTextValue(sources[i]);\n            if (text) return text;\n        }\n        return \"\";\n    }\n\n    function spnlAdaptEntry(entry) {\n        var team = entry.team || {};\n        var members = team.members || entry.participants || [];\n        var participants = members.map(function(m) {\n            var name = spnlMemberDisplayName(m);\n            return { name: name, display_name: name, nationality: m.nationality };\n        });\n        var resultData = entry.result_data && typeof entry.result_data === \"object\" ? entry.result_data : {};\n        var resultPuzzles = Array.isArray(resultData.puzzles) ? resultData.puzzles : [];\n        var puzzles = (Array.isArray(entry.puzzles) ? entry.puzzles : []).map(function(p) {\n            return spnlMergePuzzleWithResultData(p, resultPuzzles);\n        });\n        return {\n            team: team,\n            team_name: team.name || entry.team_name || \"\",\n            team_nationality: team.nationality || entry.team_nationality || \"\",\n            participants: participants,\n            puzzles: puzzles,\n            pieces: entry.pieces,\n            time: entry.time,\n            rank: entry.rank,\n            index: entry.index,\n            is_disqualified: entry.is_disqualified,\n            has_qualified: !!entry.has_qualified,\n            provisional: spnlEntryIsProvisional(entry),\n            excluded_from_ranking: spnlEntryIsExcludedFromRanking(entry),\n            time_to_first: entry.time_to_first,\n            time_to_previous: entry.time_to_previous,\n            result_annotation: spnlExtractResultAnnotation(entry)\n        };\n    }\n\n    function spnlRankingSectionHeaderHtml(title, count) {\n        return \"<div class='spnl-ranking-section-header'><span class='spnl-ranking-section-title'>\" + title + \"<\/span><span class='spnl-ranking-section-count'>(\" + count + \")<\/span><\/div>\";\n    }\n\n    function spnlQualifiedBadgeHtml(hasQualified) {\n        if (!hasQualified) {\n            return \"\";\n        }\n        return \"<span class='spnl-qualified-badge-slot'><span class='spnl-qualified-badge' title='\" + t(\"qualified\") + \"'>Q<\/span><\/span>\";\n    }\n\n    function spnlDesktopTableColgroupHtml(isSoloCategory, puzzleColCount) {\n        var html = \"<colgroup>\";\n        html += \"<col class='spnl-col-rank'>\";\n        html += \"<col class='spnl-col-qualified'>\";\n        if (isSoloCategory) {\n            html += \"<col class='spnl-col-name'>\";\n        } else {\n            html += \"<col class='spnl-col-name'>\";\n            html += \"<col class='spnl-col-name'>\";\n        }\n        for (var i = 0; i < puzzleColCount; i++) {\n            html += \"<col class='spnl-col-puzzle'>\";\n        }\n        html += \"<col class='spnl-col-time'>\";\n        html += \"<\/colgroup>\";\n        return html;\n    }\n\n    function spnlQualifiedCellHtml(hasQualified) {\n        if (!hasQualified) {\n            return \"<td class='spnl-qualified-col'><\/td>\";\n        }\n        return \"<td class='spnl-qualified-col'><span class='spnl-qualified-badge' title='\" + spnlEscapeAttr(t(\"qualified\")) + \"'>Q<\/span><\/td>\";\n    }\n\n    function spnlExtractRoundFromPayload(payload) {\n        if (!payload || typeof payload !== \"object\") return {};\n        if (payload.round && typeof payload.round === \"object\") return payload.round;\n        if (payload.id) {\n            var round = {};\n            Object.keys(payload).forEach(function(key) {\n                if (key !== \"puzzles\") round[key] = payload[key];\n            });\n            return round;\n        }\n        return {};\n    }\n\n    function spnlMergeRoundMeta(target, source) {\n        if (!source) return target || {};\n        var merged = Object.assign({}, target || {});\n        [\"number_of_teams\", \"category\", \"name\", \"start_datetime\", \"end_datetime\",\n            \"actual_start_datetime\", \"actual_end_datetime\", \"has_finished\", \"show_puzzles\", \"competition_name\"\n        ].forEach(function(key) {\n            if ((merged[key] == null || merged[key] === \"\") && source[key] != null) {\n                merged[key] = source[key];\n            }\n        });\n        return merged;\n    }\n\n    function spnlRoundTeamCount(round) {\n        if (!round || round.number_of_teams == null || round.number_of_teams === \"\") return \"\u2013\";\n        return round.number_of_teams;\n    }\n\n    function spnlLoadingHtml(inline) {\n        var wrapClass = inline ? \"spnl-loading spnl-loading--inline\" : \"spnl-loading\";\n        var spinnerClass = inline ? \"spnl-spinner spnl-spinner--sm\" : \"spnl-spinner\";\n        return \"<div class='\" + wrapClass + \"' role='status' aria-live='polite' aria-busy='true'>\" +\n            \"<span class='\" + spinnerClass + \"' aria-hidden='true'><\/span>\" +\n            \"<span class='spnl-sr-only'>\" + t(\"loading\") + \"<\/span>\" +\n            \"<\/div>\";\n    }\n\n    function spnlSetLoading(el, inline) {\n        if (el) el.innerHTML = spnlLoadingHtml(!!inline);\n    }\n\n    function spnlEntryDiffs(entry, i, parseTime, firstTime, prevTime) {\n        var plusPrev = \"\";\n        var plusFirst = \"\";\n        if (entry.time_to_previous != null && entry.time_to_previous > 0) {\n            plusPrev = \"+\" + formatDiffPrev(entry.time_to_previous);\n        } else if (i > 0) {\n            var thisTime = parseTime(entry.time);\n            if (thisTime !== null && prevTime !== null) {\n                var diffPrev = thisTime - prevTime;\n                if (diffPrev > 0) plusPrev = \"+\" + formatDiffPrev(diffPrev);\n            }\n        }\n        if (entry.time_to_first != null && entry.time_to_first > 0) {\n            plusFirst = \"+\" + formatDiffFirst(entry.time_to_first);\n        } else if (i > 0) {\n            var thisTimeFirst = parseTime(entry.time);\n            if (thisTimeFirst !== null && firstTime !== null) {\n                var diffFirst = thisTimeFirst - firstTime;\n                if (diffFirst > 0) plusFirst = \"+\" + formatDiffFirst(diffFirst);\n            }\n        }\n        return { plusPrev: plusPrev, plusFirst: plusFirst };\n    }\n\n    function spnlRoundCategoryGroupKey(round) {\n        var cat = round && round.category ? String(round.category).toLowerCase().trim() : \"\";\n        if (cat === \"duo\" || cat === \"duos\") return \"pair\";\n        return cat || \"other\";\n    }\n\n    function spnlGroupRoundsByCategory(rounds) {\n        var groups = [];\n        var indexByKey = {};\n        rounds.forEach(function(round) {\n            var key = spnlRoundCategoryGroupKey(round);\n            if (indexByKey[key] === undefined) {\n                indexByKey[key] = groups.length;\n                groups.push({ key: key, rounds: [] });\n            }\n            groups[indexByKey[key]].rounds.push(round);\n        });\n        return groups;\n    }\n\n    function spnlBuildRoundButtonRows(roundGroups) {\n        var rows = [];\n        roundGroups.forEach(function(group) {\n            if (group.rounds.length > 1) {\n                rows.push([group]);\n            } else if (!rows.length) {\n                rows.push([group]);\n            } else {\n                rows[rows.length - 1].push(group);\n            }\n        });\n        return rows;\n    }\n\n    document.addEventListener(\"DOMContentLoaded\", function() {\n        var container = document.getElementById(\"spnl-round-buttons\");\n        var output = document.getElementById(\"spnl-ranking-output\");\n        var rankingWidget = document.getElementById(\"spnl-ranking-widget\");\n        var resultDialog = document.getElementById(\"spnl-result-dialog\");\n        var resultDialogTitle = document.getElementById(\"spnl-result-dialog-title\");\n        var resultDialogBody = resultDialog ? resultDialog.querySelector(\".spnl-result-dialog-body\") : null;\n        var resultDialogBackdrop = resultDialog ? resultDialog.querySelector(\".spnl-result-dialog-backdrop\") : null;\n        var resultDialogClose = resultDialog ? resultDialog.querySelector(\".spnl-result-dialog-close\") : null;\n\n        function spnlLockPageScroll() {\n            var scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n            if (scrollbarWidth > 0) document.body.style.paddingRight = scrollbarWidth + \"px\";\n            document.body.style.overflow = \"hidden\";\n        }\n\n        function spnlUnlockPageScroll() {\n            document.body.style.overflow = \"\";\n            document.body.style.paddingRight = \"\";\n        }\n\n        function spnlCloseResultDialog() {\n            if (!resultDialog) return;\n            resultDialog.hidden = true;\n            spnlUnlockPageScroll();\n        }\n\n        function spnlOpenResultDialog(title, body) {\n            if (!resultDialog || !resultDialogTitle || !resultDialogBody) return;\n            resultDialogTitle.textContent = title || \"\";\n            resultDialogBody.textContent = body || \"\";\n            resultDialog.hidden = false;\n            spnlLockPageScroll();\n            if (resultDialogClose) resultDialogClose.focus();\n        }\n\n        if (resultDialogBackdrop) {\n            resultDialogBackdrop.setAttribute(\"aria-label\", t(\"close\"));\n            resultDialogBackdrop.addEventListener(\"click\", spnlCloseResultDialog);\n        }\n        if (resultDialogClose) {\n            resultDialogClose.setAttribute(\"aria-label\", t(\"close\"));\n            resultDialogClose.addEventListener(\"click\", spnlCloseResultDialog);\n        }\n        document.addEventListener(\"keydown\", function(e) {\n            if (e.key === \"Escape\" && resultDialog && !resultDialog.hidden) spnlCloseResultDialog();\n        });\n        if (rankingWidget) {\n            rankingWidget.addEventListener(\"click\", function(e) {\n                var btn = e.target.closest(\"[data-spnl-dialog-body]\");\n                if (!btn) return;\n                e.preventDefault();\n                e.stopPropagation();\n                spnlOpenResultDialog(btn.getAttribute(\"data-spnl-dialog-title\"), btn.getAttribute(\"data-spnl-dialog-body\"));\n            });\n        }\n\n        spnlSetLoading(container, true);\n\n         fetch(spnlApiUrl('public\/data\/competition\/' + spnlCompetitionUuid + '\/rounds'))\n            .then(function(response) {\n                if (!response.ok) throw new Error('HTTP ' + response.status);\n                return response.json();\n            })\n            .then(function(result) {\n                var rounds = result.data || [];\n                if (!rounds.length) {\n                    container.innerHTML = \"No rounds found.\";\n                    return;\n                }\n\n                container.innerHTML = \"\";\n                competitionRoundsById = {};\n                var roundGroups = spnlGroupRoundsByCategory(rounds);\n                var roundRows = spnlBuildRoundButtonRows(roundGroups);\n                roundRows.forEach(function(rowGroups) {\n                    var rowEl = document.createElement(\"div\");\n                    rowEl.className = \"spnl-round-button-row\";\n                    rowEl.setAttribute(\"role\", \"presentation\");\n                    rowGroups.forEach(function(group) {\n                        rowEl.appendChild(spnlCreateRoundGroupElement(group, container));\n                    });\n                    container.appendChild(rowEl);\n                });\n                var firstBtn = container.querySelector(\"button.spnl-round-tab\");\n                if (firstBtn) {\n                    firstBtn.classList.add(\"spnl-round-tab--active\");\n                    firstBtn.setAttribute(\"aria-selected\", \"true\");\n                    firstBtn.setAttribute(\"tabindex\", \"0\");\n                    selectRound(rounds[0].id);\n                }\n            })\n            .catch(function(err) {\n                console.error(\"Fetch error:\", err);\n                container.innerHTML = \"Error loading rounds.\";\n            });\n\n        var rankingControls = document.getElementById(\"spnl-ranking-controls\");\n        var definitionControl = document.getElementById(\"spnl-definition-control\");\n        var rankingDefinitionSelect = document.getElementById(\"spnl-ranking-definition-select\");\n        var intermediateToggle = document.getElementById(\"spnl-intermediate-toggle\");\n        var intermediateToggleText = document.getElementById(\"spnl-intermediate-toggle-text\");\n        var roundDataCache = null;\n        var rankingDefinitions = [];\n        var activeRoundId = null;\n        var activeDefinitionId = null;\n        var activeRankingMode = \"ranking\";\n\n        rankingDefinitionSelect.setAttribute(\"aria-label\", isEnglish() ? \"Category\" : \"Categorie\");\n        intermediateToggleText.textContent = t(\"showIntermediate\");\n\n        function pickDefaultDefinition(definitions) {\n            for (var i = 0; i < definitions.length; i++) {\n                if (definitions[i].identifier === \"ranking\") return definitions[i];\n            }\n            return definitions[0] || null;\n        }\n\n        function renderRankingControls(definitions, selectedDefinitionId, isIntermediate) {\n            rankingControls.style.display = \"flex\";\n            definitionControl.style.display = definitions.length > 1 ? \"flex\" : \"none\";\n            rankingDefinitionSelect.innerHTML = \"\";\n            definitions.forEach(function(def) {\n                var opt = document.createElement(\"option\");\n                opt.value = def.id;\n                opt.textContent = def.name || def.identifier;\n                rankingDefinitionSelect.appendChild(opt);\n            });\n            rankingDefinitionSelect.value = selectedDefinitionId;\n            intermediateToggle.checked = isIntermediate;\n        }\n\n        rankingDefinitionSelect.addEventListener(\"change\", function() {\n            activeDefinitionId = rankingDefinitionSelect.value;\n            if (activeRoundId) loadRanking(activeRoundId, activeDefinitionId, activeRankingMode);\n        });\n\n        intermediateToggle.addEventListener(\"change\", function() {\n            activeRankingMode = intermediateToggle.checked ? \"intermediate\" : \"ranking\";\n            if (activeRoundId && activeDefinitionId) {\n                loadRanking(activeRoundId, activeDefinitionId, activeRankingMode);\n            }\n        });\n\n        function rankingDataUrl(roundId, definitionId, mode) {\n            var path = \"public\/data\/round\/\" + roundId + \"\/ranking\/\" + definitionId;\n            if (mode === \"intermediate\") path += \"\/intermediate\";\n            return spnlApiUrl(path);\n        }\n\n        function spnlBindRoundTab(btn, round, tabContainer) {\n            btn.onclick = function(event) {\n                event.preventDefault();\n                tabContainer.querySelectorAll(\".spnl-round-tab\").forEach(function(b) {\n                    b.classList.remove(\"spnl-round-tab--active\");\n                    b.setAttribute(\"aria-selected\", \"false\");\n                    b.setAttribute(\"tabindex\", \"-1\");\n                });\n                btn.classList.add(\"spnl-round-tab--active\");\n                btn.setAttribute(\"aria-selected\", \"true\");\n                btn.setAttribute(\"tabindex\", \"0\");\n                selectRound(round.id);\n            };\n        }\n\n        function spnlCreateRoundGroupElement(group, tabContainer) {\n            var groupEl = document.createElement(\"div\");\n            groupEl.className = \"spnl-round-button-group\";\n            groupEl.setAttribute(\"role\", \"presentation\");\n            group.rounds.forEach(function(round) {\n                if (round && round.id) competitionRoundsById[round.id] = round;\n                var btn = document.createElement(\"button\");\n                btn.className = \"spnl-round-tab\";\n                btn.setAttribute(\"role\", \"tab\");\n                btn.setAttribute(\"aria-selected\", \"false\");\n                btn.setAttribute(\"tabindex\", \"-1\");\n                btn.textContent = round.name || '';\n                spnlBindRoundTab(btn, round, tabContainer);\n                groupEl.appendChild(btn);\n            });\n            return groupEl;\n        }\n\n        function selectRound(roundId) {\n            activeRoundId = roundId;\n            activeDefinitionId = null;\n            activeRankingMode = \"ranking\";\n            spnlSetLoading(output);\n            rankingControls.style.display = \"none\";\n            roundDataCache = null;\n\n            Promise.all([\n                fetch(spnlApiUrl(\"public\/data\/round\/\" + roundId)),\n                fetch(spnlApiUrl(\"public\/data\/round\/\" + roundId + \"\/ranking-definitions\"))\n            ])\n            .then(function(responses) {\n                return Promise.all(responses.map(function(r) {\n                    if (!r.ok) throw new Error(\"HTTP \" + r.status);\n                    return r.json();\n                }));\n            })\n            .then(function(results) {\n                var roundPayload = results[0].data || {};\n                rankingDefinitions = results[1].data || [];\n                var round = spnlExtractRoundFromPayload(roundPayload);\n                round = spnlMergeRoundMeta(round, competitionRoundsById[roundId]);\n                roundDataCache = {\n                    round: round,\n                    puzzles: Array.isArray(roundPayload.puzzles) ? roundPayload.puzzles : []\n                };\n                if (!rankingDefinitions.length) {\n                    output.innerHTML = \"No ranking available.\";\n                    return;\n                }\n                var defaultDef = pickDefaultDefinition(rankingDefinitions);\n                activeDefinitionId = defaultDef.id;\n                renderRankingControls(rankingDefinitions, activeDefinitionId, false);\n                loadRanking(roundId, activeDefinitionId, activeRankingMode);\n            })\n            .catch(function(err) {\n                console.error(\"Round load error:\", err);\n                output.innerHTML = \"Error loading round data.\";\n            });\n        }\n\n        function loadRanking(roundId, definitionId, mode) {\n            spnlSetLoading(output);\n            activeDefinitionId = definitionId;\n            activeRankingMode = mode || \"ranking\";\n            renderRankingControls(rankingDefinitions, activeDefinitionId, activeRankingMode === \"intermediate\");\n\n            fetch(rankingDataUrl(roundId, definitionId, activeRankingMode))\n                .then(function(res) {\n                    if (!res.ok) throw new Error('HTTP ' + res.status);\n                    return res.json();\n                })\n                .then(function(data) {\n                    var rankingPayload = data.data || {};\n                    var ranking = Array.isArray(rankingPayload.rankings)\n                        ? rankingPayload.rankings\n                        : (Array.isArray(rankingPayload.ranking) ? rankingPayload.ranking : []);\n                    var puzzles = Array.isArray(rankingPayload.puzzles)\n                        ? rankingPayload.puzzles\n                        : (roundDataCache && roundDataCache.puzzles ? roundDataCache.puzzles : []);\n                    if (!roundDataCache) {\n                        output.innerHTML = \"No ranking data available.\";\n                        return;\n                    }\n                    renderRankingView({\n                        round: roundDataCache.round,\n                        puzzles: puzzles,\n                        ranking: ranking,\n                        rankingName: rankingPayload.name || \"\",\n                        rankingMode: activeRankingMode,\n                        current_time: rankingPayload.current_time || null\n                    });\n                })\n                .catch(function(error) {\n                    console.error(\"Error fetching ranking:\", error);\n                    output.innerHTML = \"Error loading ranking data.\";\n                });\n        }\n\n        function renderRankingView(data) {\n            if (!data || !data.round || !data.round.id) {\n                output.innerHTML = \"No ranking data available.\";\n                return;\n            }\n            var puzzles = Array.isArray(data.puzzles) ? data.puzzles : [];\n            var ranking = Array.isArray(data.ranking) ? data.ranking : [];\n            var round = spnlMergeRoundMeta(data.round, competitionRoundsById[data.round.id]);\n            var teamCount = spnlRoundTeamCount(round);\n            var rankingName = data.rankingName || \"\";\n            var isIntermediateView = data.rankingMode === \"intermediate\";\n            var actualStart = round.actual_start_datetime || null;\n            var actualEnd = round.actual_end_datetime || null;\n            var currentTime = data.current_time || null;\n                    var html = \"\";\n\n                    puzzles.sort(function(a, b) {\n                        var orderA = a.order != null ? a.order : Infinity;\n                        var orderB = b.order != null ? b.order : Infinity;\n                        return orderA - orderB;\n                    });\n\n                    \/\/ Always define these variables\n                    var plannedStart = round.start_datetime ? new Date(round.start_datetime) : null;\n                    var plannedEnd = round.end_datetime ? new Date(round.end_datetime) : null;\n                    var actualStart = round.actual_start_datetime ? new Date(round.actual_start_datetime) : null;\n                    var actualEnd = round.actual_end_datetime ? new Date(round.actual_end_datetime) : null;\n\n                    function formatHM(date) {\n                        if (!date) return '-';\n                        return pad2(date.getHours()) + ':' + pad2(date.getMinutes());\n                    }\n\n                    function formatDate(date) {\n                        if (!date) return '-';\n                        return pad2(date.getDate()) + '-' + pad2(date.getMonth() + 1) + '-' + date.getFullYear();\n                    }\n\n                    \/\/ Move round header outside and update left side content\n                    html += \"<link href='https:\/\/fonts.googleapis.com\/icon?family=Material+Icons' rel='stylesheet'>\";\n\n                    \/\/ Always render the timer, even if actualStart is not set\n                    html += \"<div class='spnl-header-card'><div class='spnl-header-outer'>\";\n                    html += \"<div class='spnl-header-title-row'>\";\n                    var titleParts = [];\n                    if (round.competition_name) titleParts.push(round.competition_name);\n                    if (round.name) titleParts.push(round.name);\n                    if (rankingName) titleParts.push(rankingName);\n                    html += \"<div class='spnl-header-title-main' style='text-align:left;'>\" + titleParts.join(\" \u2013 \") + \"<\/div>\";\n                        html += \"<div class='spnl-header-title-timer'><div class='spnl-timer-card'><span id='spnl-live-timer' class='spnl-timer-display' data-start='\" + (actualStart ? actualStart.toISOString() : \"\") + \"' data-end='\" + (actualEnd ? actualEnd.toISOString() : \"\") + \"'><\/span><\/div><\/div>\";\n                    html += \"<\/div>\";\n\n                    \/\/ Calculate finishers and disqualified counts\n                    var finishersCount;\n                    var notFinishedCount = 0;\n                    if (isIntermediateView) {\n                        finishersCount = ranking.filter(function(entry) {\n                            return !spnlEntryIsProvisional(entry) && !entry.is_disqualified;\n                        }).length;\n                        notFinishedCount = ranking.filter(function(entry) {\n                            return spnlEntryIsProvisional(entry) && !entry.is_disqualified;\n                        }).length;\n                    } else {\n                        finishersCount = ranking.filter(function(entry) {\n                            return entry.time &&\n                                   entry.time !== \"-\" &&\n                                   !entry.is_disqualified &&\n                                   !entry.pieces;\n                        }).length;\n                    }\n                    var disqualifiedCount = ranking.filter(function(entry) {\n                        return entry.is_disqualified;\n                    }).length;\n\n                    html += \"<div style='margin-top: 24px; display: flex; gap: 16px;'>\";\n                    \/\/ Left column\n                    html += \"<div style='flex: 1; display: flex; flex-direction: column; gap: 8px;'>\";\n                    \/\/ Planned schedule\n                    html += \"<div class='spnl-info-row' style='display: flex; align-items: center; gap: 12px; background: #f8f8f8; border-radius: 8px; padding: 8px; border: 1px solid #eee;'>\" +\n                        \"<span class='material-icons spnl-info-icon' style='color: #004080; width: 40px; text-align: center;'>event<\/span>\" +\n                        \"<span class='spnl-info-label' style='font-size: 0.95em; font-weight: 500; color: #222e56;'>\" + formatDate(plannedStart) + \", \" + formatHM(plannedStart) + \" - \" + formatHM(plannedEnd) + \"<\/span>\" +\n                        \"<\/div>\";\n                    \/\/ Actual schedule\n                    html += \"<div class='spnl-info-row' style='display: flex; align-items: center; gap: 12px; background: #f8f8f8; border-radius: 8px; padding: 8px; border: 1px solid #eee;'>\" +\n                        \"<span class='material-icons spnl-info-icon' style='color: #004080; width: 40px; text-align: center;'>schedule<\/span>\" +\n                        \"<span class='spnl-info-label' style='font-size: 0.95em; font-weight: 500; color: #222e56;'>\" + formatHM(actualStart) + \" - \" + formatHM(actualEnd) + \"<\/span>\" +\n                        \"<\/div>\";\n                    html += \"<\/div>\";\n\n                    \/\/ Right column\n                    html += \"<div style='flex: 1; display: flex; flex-direction: column; gap: 8px;'>\";\n                    \/\/ Team count\n                    var teamIcon = round.category === 'solo' ? 'person' : (round.category === 'pair' ? 'group' : 'groups');\n                    html += \"<div class='spnl-info-row' style='display: flex; align-items: center; gap: 12px; background: #f8f8f8; border-radius: 8px; padding: 8px; border: 1px solid #eee;'>\" +\n                        \"<span class='material-icons spnl-info-icon' style='color: #004080; width: 40px; text-align: center;'>\" + teamIcon + \"<\/span>\" +\n                        \"<div class='spnl-info-label' style='display: flex; gap: 8px; font-size: 0.95em; font-weight: 500; color: #222e56;'>\";\n\n                    if (round.category === 'solo') {\n                        html += \"<div>\" + t('participants') + \"<\/div><div id='participants-count'>\" + teamCount + \"<\/div>\";\n                    } else if (round.category === 'pair') {\n                        html += \"<div>\" + t('duos') + \"<\/div><div id='duos-count'>\" + teamCount + \"<\/div>\";\n                    } else {\n                        html += \"<div>\" + t('teams') + \"<\/div><div id='teams-count'>\" + teamCount + \"<\/div>\";\n                    }\n\n                    html += \"<\/div><\/div>\";\n                    \/\/ Stats info\n                    html += \"<div class='spnl-info-row' style='display: flex; align-items: center; gap: 12px; background: #f8f8f8; border-radius: 8px; padding: 8px; border: 1px solid #eee;'>\" +\n                        \"<span class='material-icons spnl-info-icon' style='color: #004080; width: 40px; text-align: center;'>info<\/span>\" +\n                        \"<div class='spnl-stats-wrapper'>\" +\n                            \"<div class='spnl-info-label' style='display: flex; gap: 8px; font-size: 0.95em; font-weight: 500; color: #222e56;'>\" +\n                                \"<span>\" + t('finished') + \"<\/span><div id='finishers-count'>\" + finishersCount + \"<\/div>\" +\n                            \"<\/div>\" +\n                            (isIntermediateView && notFinishedCount > 0 ?\n                            \"<div class='spnl-info-label' style='display: flex; gap: 8px; font-size: 0.95em; font-weight: 500; color: #222e56;'>\" +\n                                \"<span>\" + t('notFinished') + \"<\/span><div id='not-finished-count'>\" + notFinishedCount + \"<\/div>\" +\n                            \"<\/div>\" : \"\") +\n                            (disqualifiedCount > 0 ?\n                            \"<div class='spnl-info-label' style='display: flex; gap: 8px; font-size: 0.95em; font-weight: 500; color: #222e56;'>\" +\n                                \"<span>\" + t('disqualified') + \"<\/span><div id='disqualified-count'>\" + disqualifiedCount + \"<\/div>\" +\n                            \"<\/div>\" : \"\") +\n                        \"<\/div>\" +\n                    \"<\/div>\";\n                    html += \"<\/div>\";\n                    html += \"<\/div>\";\n                    html += \"<div class='spnl-header-two-col'>\";\n                        html += \"<\/div>\";\n                    \/\/ Right: Puzzles\n                    html += \"<div class='spnl-header-right'>\";\n                    html += \"<div class='spnl-puzzle-cards'>\";\n                    if (puzzles.length) {\n                        puzzles.forEach(function(puzzle, idx) {\n                            var imgUrl = spnlPuzzleImageUrl(puzzle, \"medium\");\n                            var imgUrlLarge = spnlPuzzleImageUrl(puzzle, \"large\");\n                            html += \"<div class='spnl-puzzle-card'>\" +\n                                \"<div class='spnl-puzzle-card-header'>\" +\n                                    (imgUrl ? (\"<img class='spnl-puzzle-card-img' src='\" + imgUrl + \"' alt='\" + (puzzle.name || \"\") + \"' data-large='\" + imgUrlLarge + \"' data-idx='\" + idx + \"'>\") : \"\") +\n                                \"<\/div>\" +\n                                \"<div class='spnl-puzzle-card-name'>\" + (puzzle.name || \"\") + \"<\/div>\" +\n                                \"<div class='spnl-puzzle-card-brand-row'>\" +\n                                    \"<span class='spnl-puzzle-card-brand'>\" + (puzzle.brand ? puzzle.brand : \"\") + \"<\/span>\" +\n                                    (puzzle.pieces ? (\"<span class='spnl-puzzle-card-pieces'><span class='material-icons spnl-puzzle-piece-icon'>extension<\/span> \" + puzzle.pieces + \"<\/span>\") : \"\") +\n                                \"<\/div>\" +\n                            \"<\/div>\";\n                        });\n                    }\n                    html += \"<\/div>\";\n                    html += \"<\/div>\";\n                    html += \"<\/div>\";\n                    html += \"<\/div><\/div>\";\n\n                    if (ranking.length) {\n                        var isSolo = (round.category && round.category.toLowerCase() === 'solo');\n                        var isMobileView = window.innerWidth <= 900;\n                        var tableColspan = (isSolo ? 3 : 4) + Math.max(puzzles.length, puzzles.length === 1 ? 2 : puzzles.length) + 1;\n                        var rankingSections = [{ title: null, entries: ranking, key: \"all\" }];\n                        if (isIntermediateView) {\n                            var finishedEntries = ranking.filter(function(e) {\n                                return !spnlEntryIsProvisional(e) && !e.is_disqualified;\n                            });\n                            var notFinishedEntries = ranking.filter(function(e) {\n                                return spnlEntryIsProvisional(e) && !e.is_disqualified;\n                            });\n                            rankingSections = [];\n                            if (finishedEntries.length) {\n                                rankingSections.push({ title: t(\"finishedSection\"), entries: finishedEntries, key: \"normal\" });\n                            }\n                            if (notFinishedEntries.length) {\n                                rankingSections.push({ title: t(\"notFinishedSection\"), entries: notFinishedEntries, key: \"notFinished\" });\n                            }\n                        }\n                        if (!isMobileView) {\n                            var desktopPuzzleColCount = Math.max(puzzles.length, puzzles.length === 1 ? 2 : puzzles.length);\n                            html += \"<table class='spnl-table\" + (isSolo ? \" spnl-solo-mode\" : \"\") + \"'>\";\n                            html += spnlDesktopTableColgroupHtml(isSolo, desktopPuzzleColCount);\n                        }\n                        rankingSections.forEach(function(section) {\n                            if (!section.entries.length) return;\n                            if (section.title) {\n                                if (isMobileView) {\n                                    html += spnlRankingSectionHeaderHtml(section.title, section.entries.length);\n                                } else {\n                                    html += \"<tr class='spnl-ranking-section-row'><td colspan='\" + tableColspan + \"'>\" + spnlRankingSectionHeaderHtml(section.title, section.entries.length) + \"<\/td><\/tr>\";\n                                }\n                            }\n                            var index = 1;\n                            var firstTime = null;\n                            var prevTime = null;\n                            var prevCompletionTime = null;\n                            var prevRank = null;\n                            section.entries.forEach(function(rawEntry, i) {\n                            var entry = spnlAdaptEntry(rawEntry);\n                            \/\/ Sort puzzles by completion_time for this entry\n                            if (Array.isArray(entry.puzzles)) {\n                                entry.puzzles.sort(function(a, b) {\n                                    function timeToSeconds(t) {\n                                        if (!t) return Infinity;\n                                        var parts = t.split(\":\").map(Number);\n                                        if (parts.length === 3) return parts[0]*3600 + parts[1]*60 + parts[2];\n                                        if (parts.length === 2) return parts[0]*60 + parts[1];\n                                        return Infinity;\n                                    }\n                                    var timeA = timeToSeconds(a.completion_time);\n                                    var timeB = timeToSeconds(b.completion_time);\n                                    return timeA - timeB;\n                                });\n                            }\n\n                            var name = isSolo && Array.isArray(entry.participants) && entry.participants.length ? entry.participants[0].name : (entry.team_name || \"\");\n                            var nationality = isSolo && Array.isArray(entry.participants) && entry.participants.length ? entry.participants[0].nationality : (entry.team_nationality || \"\");\n                            var flag = \"\";\n                            if (nationality) {\n                                if (nationality.toLowerCase() === 'global') {\n                                    flag = \"<img src='https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/earth-globe.png' alt='' class='spnl-flag-img spnl-flag-img--global'>\";\n                                } else {\n                                    flag = \"<img src='https:\/\/flagcdn.com\/w20\/\"+nationality.toLowerCase()+\".png' alt='' class='spnl-flag-img'>\";\n                                }\n                            }\n                            var finalTime = entry.time || \"-\";\n                            var pieces = entry.pieces;\n                            function parseTime(t) {\n                                if (!t || t === \"-\") return null;\n                                if (typeof t === 'number') return t;\n                                var parts = t.split(\":\").map(Number);\n                                if (parts.length === 3) return parts[0]*3600 + parts[1]*60 + parts[2];\n                                if (parts.length === 2) return parts[0]*60 + parts[1];\n                                return null;\n                            }\n                            var thisTime = parseTime(entry.time);\n                            if (i === 0) {\n                                firstTime = thisTime;\n                                prevTime = thisTime;\n                            }\n                            var diffs = spnlEntryDiffs(entry, i, parseTime, firstTime, prevTime);\n                            var plusPrev = diffs.plusPrev;\n                            var plusFirst = diffs.plusFirst;\n                            \/\/ If no time, show max time and pieces if available\n                            if (!entry.time || entry.time === \"-\") {\n                                if (round && round.actual_end_datetime) {\n                                    var maxTime = parseTime(formatTime((new Date(round.actual_end_datetime) - new Date(round.actual_start_datetime))\/1000));\n                                    finalTime = formatTime(maxTime);\n                                }\n                                if (entry.pieces) {\n                                    finalTime += \"<br><span class='spnl-pieces-span'>pieces: \" + entry.pieces + \"<\/span>\";\n                                }\n                            }\n                            prevTime = thisTime;\n                            var isExcludedFromRanking = !!entry.excluded_from_ranking;\n                            var currentRank = isExcludedFromRanking ? null : (entry.rank || entry.position || index);\n                            var showRank = !isExcludedFromRanking;\n                            if (showRank && prevRank !== null && currentRank === prevRank) {\n                                showRank = false;\n                            }\n                            if (!isExcludedFromRanking) {\n                                prevRank = currentRank;\n                            }\n                            var isNotFinishedRow = section.key === \"notFinished\";\n                            var puzzleColCount = Math.max(puzzles.length, puzzles.length === 1 ? 2 : puzzles.length);\n                            var puzzleCells = \"\";\n                            if (isNotFinishedRow) {\n                                puzzleCells = \"<td class='spnl-table-cell spnl-not-finished-puzzle-col' colspan='\" + puzzleColCount + \"'><\/td>\";\n                            } else {\n                                var puzzleCellsArr = (Array.isArray(entry.puzzles) ? entry.puzzles : []).map(function(puzzle, idx) {\n                                    var globalPuzzle = puzzles.find(function(p) { return p.id === puzzle.puzzle_id; });\n                                    var imgUrl = globalPuzzle ? spnlPuzzleImageUrl(globalPuzzle) : \"\";\n                                    var puzzleName = globalPuzzle && globalPuzzle.name ? globalPuzzle.name : 'Puzzle';\n                                    var timeStr = puzzle.elapsed_time || puzzle.completion_time || \"-\";\n                                    var puzzleMeta = spnlTimeMetaIconsHtml({\n                                        annotation: puzzle.annotation,\n                                        manufacturingErrorPieces: spnlPuzzleManufacturingErrorPieces(puzzle)\n                                    });\n                                    return \"<td class='spnl-table-cell spnl-table-cell-dynamic time-col puzzle-col' data-label='\" + puzzleName + \"'>\" +\n                                        spnlPuzzleDesktopCellHtml(timeStr, puzzleMeta, imgUrl) + \"<\/td>\";\n                                });\n                                if (puzzles.length === 1) {\n                                    while (puzzleCellsArr.length < 2) {\n                                        puzzleCellsArr.unshift(\"<td class='spnl-table-cell spnl-table-cell-dynamic time-col puzzle-col'><\/td>\");\n                                    }\n                                } else {\n                                    while (puzzleCellsArr.length < puzzles.length) {\n                                        puzzleCellsArr.push(\"<td class='spnl-table-cell spnl-table-cell-dynamic time-col puzzle-col'><\/td>\");\n                                    }\n                                }\n                                puzzleCells = puzzleCellsArr.join(\"\");\n                            }\n\n                            \/\/ Compose finish cell: time, then +prev | +first\n                            function formatDiff(val) {\n                                if (!val) return \"-\";\n                                var v = val.replace('+','');\n                                var parts = v.split(':').map(Number);\n                                var seconds = 0;\n                                if (parts.length === 3) {\n                                    seconds = parts[0]*3600 + parts[1]*60 + parts[2];\n                                } else if (parts.length === 2) {\n                                    seconds = parts[0]*60 + parts[1];\n                                } else if (parts.length === 1) {\n                                    seconds = parts[0];\n                                }\n                                if (seconds >= 3600) {\n                                    \/\/ Show as hh:mm:ss\n                                    var h = Math.floor(seconds \/ 3600);\n                                    var m = Math.floor((seconds % 3600) \/ 60);\n                                    var s = seconds % 60;\n                                    return (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n                                } else {\n                                    \/\/ Show as mm:ss\n                                    var m = Math.floor(seconds \/ 60);\n                                    var s = seconds % 60;\n                                    return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;\n                                }\n                            }\n                            var finishMeta = spnlTimeMetaIconsHtml({ annotation: entry.result_annotation });\n                            var finishTimeRow = \"<span class='spnl-finish-time-row'>\" + finishMeta +\n                                \"<span class='spnl-finish-time'>\" + formatTime(entry.time) + \"<\/span><\/span>\";\n                            var finishCell = \"\";\n                            if (entry.pieces != null) {\n                                finishCell = \"<div class='spnl-finish-cell'>\" + finishTimeRow +\n                                    \"<span class='spnl-finish-pieces'><span class='material-icons spnl-puzzle-piece-icon'>extension<\/span>\" + entry.pieces + \"<\/span><\/div>\";\n                            } else {\n                                finishCell = \"<div class='spnl-finish-cell'>\" + finishTimeRow;\n                                if (plusPrev || plusFirst) {\n                                    finishCell += \"<div class='spnl-finish-diff'>\" +\n                                        (plusPrev ? (\"<span class='spnl-finish-diff-prev'>\" + plusPrev + \"<\/span>\") : \"\") + ((plusPrev && plusFirst) ? \" <span class='spnl-finish-diff-sep'>|<\/span> \" : \"\") + (plusFirst ? (\"<span class='spnl-finish-diff-first'>\" + plusFirst + \"<\/span>\") : \"\") + \"<\/div>\";\n                                }\n                                finishCell += \"<\/div>\";\n                            }\n                            \/\/ If disqualified, replace --:--:-- with label\n                            if (entry.is_disqualified) {\n                                finishCell = \"<div class='spnl-finish-cell'><span class='spnl-disqualified-label'>\" + t('disqualifiedLabel') + \"<\/span><\/div>\";\n                            }\n\n                            \/\/ --- PARTICIPANTS BELOW TEAM\/DUO NAME ---\n                            var qualifiedBadge = spnlQualifiedBadgeHtml(entry.has_qualified);\n                            var teamCellHtml = \"\";\n                            var hasTeamNameRow = false;\n                            if (isSolo) {\n                                teamCellHtml = \"<div class='spnl-solo-name-row'><div class='spnl-solo-name-row-inner'><span>\" + flag + \"<\/span><span class='spnl-solo-name'>\" + name + \"<\/span><\/div><\/div>\";\n                            } else {\n                                \/\/ Duo\/Team: only show team name if present\n                                if (name && name.trim() !== \"\") {\n                                    hasTeamNameRow = true;\n                                    teamCellHtml = \"<div class='spnl-team-name-row'><div class='spnl-team-name-row-inner'><span>\" + flag + \"<\/span><span class='spnl-team-name'>\" + name + \"<\/span><\/div><\/div>\";\n                                }\n                                \/\/ Show participants below\n                                if (Array.isArray(entry.participants) && entry.participants.length) {\n                                    var participantsAlignClass = hasTeamNameRow ? \" spnl-participants-row--aligned\" : \"\";\n                                    if (entry.participants.length === 2) {\n                                        \/\/ Duo: two participants, one row\n                                        var participantsHtml = entry.participants.map(function(p) {\n                                            var pflag = '';\n                                            if (p.nationality) {\n                                                if (p.nationality.toLowerCase() === 'global') {\n                                                    pflag = \"<img src='https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/earth-globe.png' alt='' class='spnl-flag-img'>\";\n                                                } else {\n                                                    pflag = \"<img src='https:\/\/flagcdn.com\/w40\/\"+p.nationality.toLowerCase()+\".png' alt='' class='spnl-flag-img'>\";\n                                                }\n                                            }\n                                            var pname = p.display_name || p.name || '-';\n                                            return \"<div class='spnl-participant-cell'>\" + pflag + \"<span class='spnl-participant-name'>\" + pname + \"<\/span><\/div>\";\n                                        }).join('');\n                                        teamCellHtml += \"<div class='spnl-participants-row duo\" + participantsAlignClass + \"'>\" + participantsHtml + \"<\/div>\";\n                                    } else if (entry.participants.length === 4 || entry.participants.length === 3) {\n                                        \/\/ Team: 2x2 grid, fill empty if only 3\n                                        var rows = [[], []];\n                                        for (var i = 0; i < 4; i++) {\n                                            var p = entry.participants[i];\n                                            if (p) {\n                                                var pflag = '';\n                                                if (p.nationality) {\n                                                    if (p.nationality.toLowerCase() === 'global') {\n                                                        pflag = \"<img src='https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/earth-globe.png' alt='' class='spnl-flag-img'>\";\n                                                    } else {\n                                                        pflag = \"<img src='https:\/\/flagcdn.com\/w40\/\"+p.nationality.toLowerCase()+\".png' alt='' class='spnl-flag-img'>\";\n                                                    }\n                                                }\n                                                var pname = p.display_name || p.name || '-';\n                                                var cell = \"<div class='spnl-participant-cell'>\" + pflag + \"<span class='spnl-participant-name'>\" + pname + \"<\/span><\/div>\";\n                                                if (i < 2) rows[0].push(cell); else rows[1].push(cell);\n                                            } else {\n                                                \/\/ Empty cell for missing participant\n                                                var emptyCell = \"<div class='spnl-participant-cell'><\/div>\";\n                                                if (i < 2) rows[0].push(emptyCell); else rows[1].push(emptyCell);\n                                            }\n                                        }\n                                        teamCellHtml += \"<div class='spnl-participants-row team\" + participantsAlignClass + \"'><div class='spnl-participant-row'>\" + rows[0].join('') + \"<\/div><div class='spnl-participant-row'>\" + rows[1].join('') + \"<\/div><\/div>\";\n                                    } else {\n                                        \/\/ Fallback: show all in one row\n                                        var participantsHtml = entry.participants.map(function(p) {\n                                            var pflag = '';\n                                            if (p.nationality) {\n                                                if (p.nationality.toLowerCase() === 'global') {\n                                                    pflag = \"<img src='https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/earth-globe.png' alt='' class='spnl-flag-img'>\";\n                                                } else {\n                                                    pflag = \"<img src='https:\/\/flagcdn.com\/w40\/\"+p.nationality.toLowerCase()+\".png' alt='' class='spnl-flag-img'>\";\n                                                }\n                                            }\n                                            var pname = p.display_name || p.name || '-';\n                                            return \"<div class='spnl-participant-cell'>\" + pflag + \"<span class='spnl-participant-name'>\" + pname + \"<\/span><\/div>\";\n                                        }).join('');\n                                        teamCellHtml += \"<div class='spnl-participants-row\" + participantsAlignClass + \"'>\" + participantsHtml + \"<\/div>\";\n                                    }\n                                }\n                            }\n\n                            \/\/ Add duo-mode class to table if duo\n                            var tableClass = isSolo ? '' : (entry.participants && entry.participants.length === 2 ? ' duo-mode' : '');\n                            var rowClasses = [];\n                            if (entry.is_disqualified) rowClasses.push(\"spnl-disqualified-row\");\n                            else if (section.key === \"notFinished\") rowClasses.push(\"spnl-not-finished-row\");\n                            var rowClassSuffix = rowClasses.length ? \" \" + rowClasses.join(\" \") : \"\";\n\n                            if (isMobileView) {\n                                \/\/ MOBILE BLOCK LAYOUT (true two-column grid, full card)\n                                html += \"<div class='spnl-mobile-ranking-card spnl-mobile-ranking-card-full\" + rowClassSuffix + \"'\";\n                                html += \">\";\n                                html += \"<div class='spnl-mobile-card-inner' style='display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start;'>\";\n                                \/\/ If disqualified, show only the label at the top, skip rank\/time\n                                if (entry.is_disqualified) {\n                                    html += \"<div style='grid-column: 1 \/ span 2; display: flex; justify-content: center; margin: 12px 0 16px 0;'><span class='spnl-disqualified-label' style='margin: 0;'>\" + t('disqualifiedLabel') + \"<\/span><\/div>\";\n                                } else if (!entry.excluded_from_ranking) {\n                                    \/\/ Rank\n                                    html += \"<div class='spnl-mobile-label' style='min-width: 80px;'>Rank:<\/div>\";\n                                    html += \"<div class='spnl-mobile-value spnl-mobile-rank-row'><span style='font-size: 1.2em; font-weight: 600; color: #222e56;'>\" + (showRank ? currentRank : \"\") + \"<\/span>\" + (entry.has_qualified ? qualifiedBadge : \"\") + \"<\/div>\";\n                                }\n                                \/\/ Team\/Name\n                                html += \"<div class='spnl-mobile-label' style='min-width: 80px;'><\/div>\";\n                                html += \"<div class='spnl-mobile-value spnl-mobile-name-value'><div class='spnl-mobile-team-name-row'>\" + flag + \"<span class='spnl-mobile-team-name'>\" + name + \"<\/span><\/div><\/div>\";\n                                \/\/ Participants (duo\/team)\n                                if (!isSolo && Array.isArray(entry.participants) && entry.participants.length) {\n                                    \/\/ REMOVE the label for participants\n                                    \/\/ html += \"<div class='spnl-mobile-label'>Participants:<\/div>\"; \/\/ REMOVE THIS LINE\n                                    html += \"<div class='spnl-mobile-label' style='min-width: 80px;'><\/div>\";\n                                    html += \"<div class='spnl-mobile-value spnl-mobile-name-value spnl-mobile-participants-section'>\";\n                                    entry.participants.forEach(function(p) {\n                                        var pflag = '';\n                                        if (p.nationality) {\n                                            if (p.nationality.toLowerCase() === 'global') {\n                                                pflag = \"<img src='https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/earth-globe.png' alt='' class='spnl-flag-img spnl-mobile-participant-flag'>\";\n                                            } else {\n                                                pflag = \"<img src='https:\/\/flagcdn.com\/w40\/\"+p.nationality.toLowerCase()+\".png' alt='' class='spnl-flag-img spnl-mobile-participant-flag'>\";\n                                            }\n                                        }\n                                        var pname = p.display_name || p.name || '-';\n                                        html += \"<div class='spnl-participant-cell spnl-mobile-participant-cell'>\" + pflag + \"<span class='spnl-mobile-participant-name'>\" + pname + \"<\/span><\/div>\";\n                                    });\n                                    html += \"<\/div>\";\n                                }\n                                \/\/ Puzzle\n                                var puzzleLabel = (Array.isArray(entry.puzzles) && entry.puzzles.length > 1) ? 'Puzzles:' : 'Puzzle:';\n                                if (Array.isArray(entry.puzzles) && entry.puzzles.length) {\n                                    html += \"<div class='spnl-mobile-label' style='min-width: 80px; padding-top: 12px;'>\" + puzzleLabel + \"<\/div>\";\n                                    html += \"<div class='spnl-mobile-value spnl-mobile-puzzles-section'>\";\n                                    entry.puzzles.forEach(function(puzzle) {\n                                        var globalPuzzle = puzzles.find(function(p) { return p.id === puzzle.puzzle_id; });\n                                        var puzzleName = globalPuzzle && globalPuzzle.name ? globalPuzzle.name : 'Puzzle';\n                                        var imgUrl = globalPuzzle ? spnlPuzzleImageUrl(globalPuzzle) : \"\";\n                                        var time = puzzle.elapsed_time || puzzle.completion_time || \"-\";\n                                        html += \"<div class='spnl-mobile-puzzle-row'>\";\n                                        html += \"<div class='spnl-mobile-puzzle-card'>\";\n                                        if (imgUrl) {\n                                            html += \"<span class='spnl-puzzle-row-img-wrap'><img class='spnl-puzzle-row-img' src='\" + imgUrl + \"' alt=''><\/span>\";\n                                        }\n                                        html += \"<div style='flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px;'>\";\n                                        html += \"<div class='spnl-mobile-puzzle-name'>\" + puzzleName + \"<\/div>\";\n                                        html += \"<div class='spnl-mobile-time-row'><span>\" + time + \"<\/span><\/div>\";\n                                        html += \"<\/div>\";\n                                        html += \"<\/div>\";\n                                        var mobilePuzzleMeta = spnlTimeMetaIconsHtml({\n                                            annotation: puzzle.annotation,\n                                            manufacturingErrorPieces: spnlPuzzleManufacturingErrorPieces(puzzle)\n                                        });\n                                        html += \"<div class='spnl-mobile-puzzle-meta-slot'>\" + mobilePuzzleMeta + \"<\/div>\";\n                                        html += \"<\/div>\";\n                                    });\n                                    html += \"<\/div>\";\n                                }\n                                \/\/ Time (skip if disqualified)\n                                if (!entry.is_disqualified) {\n                                    html += \"<div class='spnl-mobile-label' style='min-width: 80px;'>Time:<\/div>\";\n                                    var mobileFinishMeta = spnlTimeMetaIconsHtml({ annotation: entry.result_annotation });\n                                    html += \"<div class='spnl-mobile-value spnl-mobile-finish-time' style='padding: 2px 0;'><span class='spnl-mobile-time-row'>\" + mobileFinishMeta + \"<span>\" + formatTime(entry.time) + \"<\/span><\/span><\/div>\";\n\n                                    \/\/ Pieces\n                                    if (entry.pieces != null) {\n                                        html += \"<div class='spnl-mobile-label' style='min-width: 80px;'>Pieces:<\/div>\";\n                                        html += \"<div class='spnl-mobile-value spnl-mobile-finish-pieces'>\" +\n                                            \"<span class='spnl-finish-pieces' style='justify-content: flex-start; margin-top: 0;'>\" +\n                                                \"<span class='material-icons spnl-puzzle-piece-icon' style='font-size:1.1em;margin-right:4px;vertical-align:middle;'>extension<\/span>\" +\n                                                entry.pieces +\n                                            \"<\/span>\" +\n                                        \"<\/div>\";\n                                    } else if (plusPrev || plusFirst) {\n                                        html += \"<div class='spnl-mobile-label' style='min-width: 80px;'><\/div>\";\n                                        html += \"<div class='spnl-mobile-value spnl-mobile-deltas'>\" +\n                                            (plusPrev ? (\"<span class='spnl-finish-diff-prev'>\" + plusPrev + \"<\/span>\") : \"\") + ((plusPrev && plusFirst) ? \" <span class='spnl-finish-diff-sep'>|<\/span> \" : \"\") + (plusFirst ? (\"<span class='spnl-finish-diff-first'>\" + plusFirst + \"<\/span>\") : \"\") + \"<\/div>\";\n                                    }\n                                }\n                                html += \"<\/div><\/div>\";\n                            } else {\n                                \/\/ DESKTOP\/TABLET (unchanged)\n                                html += \"<tr\" + (rowClasses.length ? \" class='\" + rowClasses.join(\" \") + \"'\" : \"\") + \">\";\n                                html += \"<td class='spnl-data-label-rank'>\" + (entry.is_disqualified ? \"<span class='spnl-disqualified-cross'>\u274c<\/span>\" : (showRank && currentRank != null ? currentRank : \"\")) + \"<\/td>\";\n                                html += spnlQualifiedCellHtml(!!entry.has_qualified);\n                                html += (isSolo ?\n                                    (\"<td class='spnl-team-cell' data-label='Name'>\" + teamCellHtml + \"<\/td>\") :\n                                    (\"<td class='spnl-team-cell' data-label='Name' colspan='2'>\" + teamCellHtml + \"<\/td>\")\n                                );\n                                html += puzzleCells;\n                                html += \"<td class='spnl-data-label-time'>\" + finishCell + \"<\/td>\";\n                                html += \"<\/tr>\";\n                            }\n                        });\n                        });\n                        if (!isMobileView) {\n                            html += \"<\/table>\";\n                        }\n                    } else {\n                        html += \"<div><\/div>\";\n                    }\n                    output.innerHTML = html;\n\n                    \/\/ Timer logic (run after rendering)\n                    var timerEl = document.getElementById('spnl-live-timer');\n                    if (timerEl) {\n                        var startAttr = timerEl.getAttribute('data-start');\n                        var endAttr = timerEl.getAttribute('data-end');\n                        var start = startAttr ? new Date(startAttr) : null;\n                        var end = endAttr ? new Date(endAttr) : null;\n                        function updateTimer() {\n                            if (!startAttr) {\n                                timerEl.textContent = '00:00:00';\n                                return;\n                            }\n                            if (!start || !end || !timerEl) return;\n                            var now = new Date();\n                            var total = Math.floor((end - start) \/ 1000);\n                            var elapsed = Math.floor((now - start) \/ 1000);\n                            if (now < start) {\n                                timerEl.textContent = '00:00:00';\n                            } else if (now >= end) {\n                                timerEl.textContent = formatTime(total);\n                            } else {\n                                timerEl.textContent = formatTime(elapsed);\n                                setTimeout(updateTimer, 1000);\n                            }\n                        }\n                        updateTimer();\n                    }\n\n                    \/\/ Lightbox logic for puzzle card images\n                    var lightboxOverlay = null;\n                    function closeLightbox() {\n                        if (lightboxOverlay) {\n                            document.body.removeChild(lightboxOverlay);\n                            lightboxOverlay = null;\n                            document.removeEventListener('keydown', escListener);\n                        }\n                    }\n                    function escListener(e) {\n                        if (e.key === 'Escape') closeLightbox();\n                    }\n                    output.querySelectorAll('.spnl-puzzle-card-img').forEach(function(img) {\n                        img.addEventListener('click', function(e) {\n                            e.stopPropagation();\n                            var largeUrl = img.getAttribute('data-large');\n                            if (!largeUrl) return;\n                            closeLightbox();\n                            lightboxOverlay = document.createElement('div');\n                            lightboxOverlay.className = 'spnl-lightbox-overlay';\n                            lightboxOverlay.innerHTML = \"<img class='spnl-lightbox-img' src='\" + largeUrl + \"' alt=''>\";\n                            lightboxOverlay.onclick = closeLightbox;\n                            document.body.appendChild(lightboxOverlay);\n                            setTimeout(function() { document.addEventListener('keydown', escListener); }, 10);\n                        });\n                    });\n        }\n    });\n    <\/script>\n <\/div>\n\n\n\n<\/p><\/div>\n<\/div><\/div><\/div><\/div>\n<\/div><\/div><\/div>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>ResultsDutch Jigsaw Nationals 2026<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2914","page","type-page","status-publish","hentry"],"blocksy_meta":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Results - Dutch Jigsaw Nationals 2026<\/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:\/\/speedpuzzling.nl\/en\/results-dutch-jigsaw-nationals-2026\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:locale:alternate\" content=\"nl_NL\" \/>\n<meta property=\"og:locale:alternate\" content=\"nl_NL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Results - Dutch Jigsaw Nationals 2026\" \/>\n<meta property=\"og:description\" content=\"ResultsDutch Jigsaw Nationals 2026\" \/>\n<meta property=\"og:url\" content=\"https:\/\/speedpuzzling.nl\/en\/results-dutch-jigsaw-nationals-2026\/\" \/>\n<meta property=\"og:site_name\" content=\"Speedpuzzling The Netherlands\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/share\/19s5jqzsSg\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-24T16:13:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png\" \/>\n\t<meta property=\"og:image:width\" content=\"3333\" \/>\n\t<meta property=\"og:image:height\" content=\"3333\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/\",\"url\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/\",\"name\":\"Results - Dutch Jigsaw Nationals 2026\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/speedpuzzling.nl\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Pictogrammen-zonder-voorgrond-3.png\",\"datePublished\":\"2026-05-24T16:10:22+00:00\",\"dateModified\":\"2026-05-24T16:13:07+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/#primaryimage\",\"url\":\"https:\\\/\\\/speedpuzzling.nl\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Pictogrammen-zonder-voorgrond-3.png\",\"contentUrl\":\"https:\\\/\\\/speedpuzzling.nl\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Pictogrammen-zonder-voorgrond-3.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/results-dutch-jigsaw-nationals-2026\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/speedpuzzling.nl\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Resultaten &#8211; Dutch Jigsaw Nationals 2026\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/#website\",\"url\":\"https:\\\/\\\/speedpuzzling.nl\\\/\",\"name\":\"Speedpuzzling The Netherlands\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/speedpuzzling.nl\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/#organization\",\"name\":\"Speedpuzzling The Netherlands\",\"url\":\"https:\\\/\\\/speedpuzzling.nl\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/speedpuzzling.nl\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/cropped-logo-1.jpg\",\"contentUrl\":\"https:\\\/\\\/speedpuzzling.nl\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/cropped-logo-1.jpg\",\"width\":512,\"height\":512,\"caption\":\"Speedpuzzling The Netherlands\"},\"image\":{\"@id\":\"https:\\\/\\\/speedpuzzling.nl\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/share\\\/19s5jqzsSg\\\/\",\"https:\\\/\\\/www.instagram.com\\\/speedpuzzling.the.netherlands\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Results - Dutch Jigsaw Nationals 2026","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:\/\/speedpuzzling.nl\/en\/results-dutch-jigsaw-nationals-2026\/","og_locale":"en_GB","og_type":"article","og_title":"[:en]Results - Dutch Jigsaw Nationals 2026[:nl]Resultaten - Dutch Jigsaw Nationals 2026[:] - Speedpuzzling The Netherlands","og_description":"ResultsDutch Jigsaw Nationals 2026","og_url":"https:\/\/speedpuzzling.nl\/en\/results-dutch-jigsaw-nationals-2026\/","og_site_name":"Speedpuzzling The Netherlands","article_publisher":"https:\/\/www.facebook.com\/share\/19s5jqzsSg\/","article_modified_time":"2026-05-24T16:13:07+00:00","og_image":[{"width":3333,"height":3333,"url":"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Estimated reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/","url":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/","name":"Results - Dutch Jigsaw Nationals 2026","isPartOf":{"@id":"https:\/\/speedpuzzling.nl\/#website"},"primaryImageOfPage":{"@id":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/#primaryimage"},"image":{"@id":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/#primaryimage"},"thumbnailUrl":"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png","datePublished":"2026-05-24T16:10:22+00:00","dateModified":"2026-05-24T16:13:07+00:00","breadcrumb":{"@id":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/"]}]},{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/#primaryimage","url":"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png","contentUrl":"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/03\/Pictogrammen-zonder-voorgrond-3.png"},{"@type":"BreadcrumbList","@id":"https:\/\/speedpuzzling.nl\/results-dutch-jigsaw-nationals-2026\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/speedpuzzling.nl\/en\/"},{"@type":"ListItem","position":2,"name":"Resultaten &#8211; Dutch Jigsaw Nationals 2026"}]},{"@type":"WebSite","@id":"https:\/\/speedpuzzling.nl\/#website","url":"https:\/\/speedpuzzling.nl\/","name":"Speedpuzzling The Netherlands","description":"","publisher":{"@id":"https:\/\/speedpuzzling.nl\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/speedpuzzling.nl\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/speedpuzzling.nl\/#organization","name":"Speedpuzzling The Netherlands","url":"https:\/\/speedpuzzling.nl\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/speedpuzzling.nl\/#\/schema\/logo\/image\/","url":"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/02\/cropped-logo-1.jpg","contentUrl":"https:\/\/speedpuzzling.nl\/wp-content\/uploads\/2025\/02\/cropped-logo-1.jpg","width":512,"height":512,"caption":"Speedpuzzling The Netherlands"},"image":{"@id":"https:\/\/speedpuzzling.nl\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/share\/19s5jqzsSg\/","https:\/\/www.instagram.com\/speedpuzzling.the.netherlands\/"]}]}},"_links":{"self":[{"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/pages\/2914","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/comments?post=2914"}],"version-history":[{"count":7,"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/pages\/2914\/revisions"}],"predecessor-version":[{"id":2921,"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/pages\/2914\/revisions\/2921"}],"wp:attachment":[{"href":"https:\/\/speedpuzzling.nl\/en\/wp-json\/wp\/v2\/media?parent=2914"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}