{"id":8846,"date":"2026-03-02T18:05:17","date_gmt":"2026-03-02T17:05:17","guid":{"rendered":"https:\/\/bulldogmusik.it\/?page_id=8846"},"modified":"2026-05-30T18:47:53","modified_gmt":"2026-05-30T16:47:53","slug":"bulldogfeat-ita","status":"publish","type":"page","link":"https:\/\/bulldogmusik.it\/en\/bulldogfeat-ita\/","title":{"rendered":"BulldogFeat"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"8846\" class=\"elementor elementor-8846\">\n\t\t\t\t<div class=\"elementor-element elementor-element-73a0e0c8 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con-boxed wcf-starter-animations-none e-con e-parent\" data-id=\"73a0e0c8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-27a36a0a wcf-starter-animations-none elementor-widget elementor-widget-text-editor\" data-id=\"27a36a0a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;wcf_starter_animations&quot;:&quot;none&quot;,&quot;wcf_anim_duration&quot;:1000,&quot;wcf_anim_delay&quot;:0,&quot;wcf_anim_ease&quot;:&quot;ease&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Indovina in rapper in meno di 5 tentativi, <strong>ogni tentativo scopri altre collaborazioni.<\/strong><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2102e0 elementor-hidden-mobile e-flex e-con-boxed wcf-starter-animations-none e-con e-parent\" data-id=\"2102e0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-db783a9 elementor-widget elementor-widget-wcf--floating-elements\" data-id=\"db783a9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"wcf--floating-elements.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"wcf--floating-elements\">\r\n\t\t\t                <div class=\"floating-element wcf-live-anim-wiggle elementor-repeater-item-77e55b9   \">\r\n\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Coppa.png\" alt=\"Coppa\" \/>\t\t\t\t<\/div>\r\n\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-303b5495 elementor-hidden-mobile e-flex e-con-boxed wcf-starter-animations-none e-con e-parent\" data-id=\"303b5495\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-652bfba7 elementor-widget__width-initial e-n-tabs-mobile elementor-widget elementor-widget-n-tabs\" data-id=\"652bfba7\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;tabs_justify_horizontal&quot;:&quot;center&quot;,&quot;horizontal_scroll&quot;:&quot;disable&quot;}\" data-widget_type=\"nested-tabs.default\">\n\t\t\t\t\t\t\t<div class=\"e-n-tabs\" data-widget-number=\"1697381287\" aria-label=\"Schede. Apri gli elementi con Invio o Spazio, chiudili con Esc e naviga con i tasti freccia.\">\n\t\t\t<div class=\"e-n-tabs-heading\" role=\"tablist\">\n\t\t\t\t\t<button id=\"e-n-tab-title-16973812871\" data-tab-title-id=\"e-n-tab-title-16973812871\" class=\"e-n-tab-title\" aria-selected=\"true\" data-tab-index=\"1\" role=\"tab\" tabindex=\"0\" aria-controls=\"e-n-tab-content-16973812871\" style=\"--n-tabs-title-order: 1;\">\n\t\t\t\t\t\t<span class=\"e-n-tab-title-text\">\n\t\t\t\tGiornaliera\t\t\t<\/span>\n\t\t<\/button>\n\t\t\t\t<button id=\"tab-speciale\" data-tab-title-id=\"e-n-tab-title-16973812872\" class=\"e-n-tab-title\" aria-selected=\"false\" data-tab-index=\"2\" role=\"tab\" tabindex=\"-1\" aria-controls=\"e-n-tab-content-16973812872\" style=\"--n-tabs-title-order: 2;\">\n\t\t\t\t\t\t<span class=\"e-n-tab-title-text\">\n\t\t\t\tClassificata\t\t\t<\/span>\n\t\t<\/button>\n\t\t\t\t\t<\/div>\n\t\t\t<div class=\"e-n-tabs-content\">\n\t\t\t\t<div id=\"e-n-tab-content-16973812871\" role=\"tabpanel\" aria-labelledby=\"e-n-tab-title-16973812871\" data-tab-index=\"1\" style=\"--n-tabs-title-order: 1;\" class=\"e-active elementor-element elementor-element-30afbb8b e-con-full e-flex wcf-starter-animations-none e-con e-child\" data-id=\"30afbb8b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-69355b0d e-grid e-con-boxed wcf-starter-animations-none e-con e-child\" data-id=\"69355b0d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b1bef14 elementor-widget__width-initial e-transform elementor-widget elementor-widget-html\" data-id=\"b1bef14\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_translateX_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:-4,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"it\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>BulldogFeat Demo<\/title>\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Instrument+Sans:wght@400;500;600;700;800&family=Space+Grotesk:wght@500;700&display=swap\" rel=\"stylesheet\">\n  <style>\n    :root {\n      --bg: #000;\n      --panel: #070707;\n      --panel-2: #0b0b0b;\n      --line: rgba(255, 255, 255, 0.08);\n      --line-faint: rgba(255, 255, 255, 0.05);\n      --line-strong: rgba(241, 108, 29, 0.28);\n      --white: #f7f4ef;\n      --copy: rgba(247, 244, 239, 0.76);\n      --copy-soft: rgba(247, 244, 239, 0.56);\n      --copy-faint: rgba(247, 244, 239, 0.34);\n      --accent: #f16c1d;\n      --success: #7dc56a;\n      --danger: #ff7e59;\n      --ease: 220ms cubic-bezier(.2,.9,.2,1);\n    }\n\n    * { box-sizing: border-box; }\n\n    html,\n    body {\n      margin: 0;\n      min-height: 100%;\n      background: var(--bg);\n      color: var(--white);\n      font-family: \"Instrument Sans\", system-ui, sans-serif;\n      overflow-x: hidden;\n    }\n\n    button,\n    input,\n    iframe {\n      font: inherit;\n    }\n\n    .demo-app {\n      width: min(760px, calc(100vw - 20px));\n      margin: 0 auto;\n      padding: 18px 0 24px;\n    }\n\n    .app-shell {\n      position: relative;\n      isolation: isolate;\n      padding: 14px;\n      border: 1px solid var(--line);\n      border-radius: 22px;\n      background: linear-gradient(180deg, rgba(14, 14, 14, 0.98), rgba(7, 7, 7, 0.98));\n      overflow: visible;\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n    }\n\n    .app-shell::after {\n      content: \"\";\n      position: absolute;\n      inset: 0;\n      border-radius: inherit;\n      background-image: url(\"data:image\/svg+xml,%3Csvg%20xmlns='http:\/\/www.w3.org\/2000\/svg'%20viewBox='0%200%20180%20180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='.9'%20numOctaves='3'%20stitchTiles='stitch'\/%3E%3CfeColorMatrix%20type='saturate'%20values='0'\/%3E%3CfeComponentTransfer%3E%3CfeFuncA%20type='table'%20tableValues='0%20.58'\/%3E%3C\/feComponentTransfer%3E%3C\/filter%3E%3Crect%20width='180'%20height='180'%20filter='url(%23n)'%20opacity='1'\/%3E%3C\/svg%3E\");\n      background-size: 180px 180px;\n      mix-blend-mode: overlay;\n      opacity: 0.1;\n      pointer-events: none;\n    }\n\n    .app-shell > * {\n      position: relative;\n      z-index: 1;\n    }\n\n    .topbar {\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      gap: 0;\n      padding: 10px 8px 14px;\n    }\n\n    .top-logo {\n      display: block !important;\n      width: min(320px, 58vw);\n      height: auto;\n    }\n\n    .controls-shell {\n      margin-top: 0;\n      padding: 14px 0 14px;\n      border-top: 1px solid var(--line);\n    }\n\n    .controls-inner {\n      display: grid;\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 8px;\n    }\n\n    .shell {\n      margin-top: 0;\n      padding-top: 14px;\n      border-top: 1px solid var(--line);\n    }\n\n    .game-shell {\n      position: relative;\n      padding: 2px 0 6px;\n      overflow: visible;\n    }\n\n    .tab,\n    .ghost-button,\n    .button,\n    .secondary-button,\n    .streak-card {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      width: 100%;\n      min-width: 0;\n      min-height: 36px;\n      padding: 0 10px;\n      border-radius: 999px;\n      border: 1px solid var(--line);\n      background: rgba(255, 255, 255, 0.03);\n      color: var(--white);\n      font-size: 12px;\n      font-weight: 700;\n      text-decoration: none;\n      cursor: pointer;\n      transition: transform var(--ease), border-color var(--ease), background var(--ease), color var(--ease), opacity var(--ease);\n    }\n\n    .tab.is-active,\n    .ghost-button.is-active {\n      border-color: var(--line-strong);\n      background: rgba(241, 108, 29, 0.12);\n    }\n\n    .demo-app.is-ranked-mode #rankedModeButton.is-active,\n    .demo-app.is-ranked-mode .ghost-button.is-active {\n      border-color: rgba(149, 40, 0, 0.28);\n      background: rgba(149, 40, 0, 0.12);\n    }\n\n    .tab-ranked-mobile {\n      display: none;\n    }\n\n    .demo-app.is-ranked-mode .hide-when-ranked,\n    body.bulldogfeat-ranked-mode-active .hide-when-ranked,\n    html.bulldogfeat-ranked-mode-active .hide-when-ranked,\n    .demo-app.is-ranked-mode .hide.when.ranked,\n    body.bulldogfeat-ranked-mode-active .hide.when.ranked,\n    html.bulldogfeat-ranked-mode-active .hide.when.ranked {\n      display: none !important;\n    }\n\n    .show-when-ranked,\n    .show.when.ranked,\n    .show-when-ranked-flex,\n    .show.flex.when.ranked,\n    .show-when-ranked-grid,\n    .show.grid.when.ranked,\n    .show-when-ranked-inline {\n      display: none !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked,\n    .demo-app.is-ranked-mode .show.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.when.ranked {\n      display: block !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked-flex,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-flex,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-flex,\n    .demo-app.is-ranked-mode .show.flex.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.flex.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.flex.when.ranked {\n      display: flex !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked-grid,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-grid,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-grid,\n    .demo-app.is-ranked-mode .show.grid.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.grid.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.grid.when.ranked {\n      display: grid !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked-inline,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-inline,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-inline {\n      display: inline-flex !important;\n    }\n\n    .button,\n    .secondary-button,\n    .attempts-card,\n    .streak-card {\n      min-width: 152px;\n      min-height: 56px;\n      height: 56px;\n      padding: 0 22px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1;\n      font-weight: 700;\n      letter-spacing: 0;\n      text-transform: uppercase;\n      box-shadow: none;\n    }\n\n    .button,\n    .secondary-button.is-primary,\n    .streak-card {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #111;\n    }\n\n    .demo-app:not(.is-ranked-mode) #submitButton.button {\n      background: #f16c1d !important;\n      border-color: #f16c1d !important;\n      color: #111 !important;\n    }\n\n    .secondary-button.is-muted {\n      background: rgba(255, 255, 255, 0.03);\n      border-color: var(--line);\n      color: var(--white);\n    }\n\n    .button:hover,\n    .secondary-button:hover,\n    .streak-card.is-guest:hover {\n      background: #fff;\n      border-color: #fff;\n      color: #111;\n    }\n\n    .demo-app:not(.is-ranked-mode) #submitButton.button:hover {\n      background: #fff !important;\n      border-color: #fff !important;\n      color: #111 !important;\n    }\n\n    .tab:hover,\n    .ghost-button:hover,\n    .button:hover,\n    .secondary-button:hover,\n    .streak-card.is-guest:hover,\n    .suggestion:hover {\n      transform: translateY(-1px);\n    }\n\n    .button:disabled,\n    .secondary-button:disabled {\n      cursor: not-allowed;\n      opacity: 0.45;\n      transform: none;\n    }\n\n    .help-panel {\n      max-height: 0;\n      overflow: hidden;\n      padding-bottom: 0;\n      border-bottom: 1px solid transparent;\n      transition: max-height 240ms ease, margin 240ms ease, padding-bottom 240ms ease, border-color 240ms ease;\n      margin: 0;\n    }\n\n    .help-panel.is-open {\n      max-height: 1200px;\n      padding-bottom: 12px;\n      border-bottom-color: var(--line);\n      margin: 0 0 12px;\n    }\n\n    .help-panel-mobile-slot {\n      display: none;\n    }\n\n    .help-grid {\n      display: grid;\n      grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n      gap: 10px;\n    }\n\n    .help-card {\n      min-height: 100%;\n      padding: 12px 13px;\n      border: 1px solid var(--line);\n      border-radius: 12px;\n      background: rgba(255, 255, 255, 0.03);\n    }\n\n    .help-card strong {\n      display: block;\n      margin-bottom: 8px;\n      font-size: 13px;\n    }\n\n    .help-card span {\n      display: block;\n      color: var(--copy-soft);\n      font-size: 12px;\n      line-height: 1.45;\n    }\n\n    .feat-panel,\n    .feat-ranked-panel {\n      display: grid;\n      gap: 12px;\n    }\n\n    .feat-meta-grid {\n      display: grid;\n      grid-template-columns: repeat(2, minmax(0, 1fr));\n      gap: 10px;\n      margin-bottom: 0;\n    }\n\n    .feat-meta-card {\n      min-height: 74px;\n      padding: 12px 14px;\n      border: 1px solid var(--line);\n      border-radius: 16px;\n      background: rgba(255, 255, 255, 0.03);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      gap: 8px;\n      text-align: left;\n    }\n\n    .feat-meta-card.is-accent {\n      border-color: rgba(149, 40, 0, 0.24);\n      background: rgba(149, 40, 0, 0.08);\n    }\n\n    .feat-meta-label {\n      display: block;\n      color: var(--copy-soft);\n      font-size: 11px;\n      font-weight: 800;\n      letter-spacing: 0.12em;\n      text-transform: uppercase;\n    }\n\n    .feat-meta-value {\n      display: block;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(24px, 3.2vw, 30px);\n      line-height: 1;\n      letter-spacing: -0.05em;\n    }\n\n    .feat-board-shell {\n      width: 100%;\n      display: flex;\n      justify-content: center;\n      padding: 2px 0 4px;\n    }\n\n    .feat-board-shell.hidden {\n      display: none !important;\n    }\n\n    #rankedGamePanel #rankedBoardShell {\n      display: none;\n    }\n\n    #rankedGamePanel #rankedBoardShell.is-visible {\n      display: flex !important;\n    }\n\n    .feat-circle {\n      position: relative;\n      width: 320px;\n      height: 320px;\n    }\n\n    .feat-center-slot {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      transform: translate(-50%, -62%);\n      z-index: 10;\n    }\n\n    .feat-hint-slot {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      width: 76px;\n      height: 76px;\n      margin-left: -38px;\n      margin-top: -38px;\n      transition: transform 360ms cubic-bezier(.22,1,.36,1), opacity 220ms ease;\n    }\n\n    .feat-node {\n      width: 100%;\n      height: 100%;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      gap: 5px;\n      padding: 8px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      border-radius: 18px;\n      background: rgba(255, 255, 255, 0.04);\n      text-align: center;\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n    }\n\n    .feat-node.is-center {\n      width: 92px;\n      height: 92px;\n      padding: 10px;\n      border-radius: 24px;\n      background: rgba(255, 255, 255, 0.05);\n      border-color: rgba(255, 255, 255, 0.12);\n    }\n\n    .feat-node.is-center.is-won {\n      border-color: rgba(125, 197, 106, 0.42);\n    }\n\n    .feat-node.is-center.is-lost {\n      border-color: rgba(255, 126, 89, 0.42);\n    }\n\n    .feat-node.is-important {\n      border-color: rgba(241, 108, 29, 0.28);\n      background: rgba(241, 108, 29, 0.08);\n    }\n\n    .feat-avatar {\n      width: 34px;\n      height: 34px;\n      flex: 0 0 34px;\n      aspect-ratio: 1 \/ 1;\n      border-radius: 50%;\n      overflow: hidden;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background:\n        radial-gradient(circle at 32% 28%, rgba(241, 108, 29, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(241, 108, 29, 0.16), rgba(255, 255, 255, 0.03));\n      color: var(--white);\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: 14px;\n      font-weight: 700;\n      letter-spacing: -0.04em;\n      text-transform: uppercase;\n    }\n\n    .feat-avatar img {\n      width: 100%;\n      height: 100%;\n      object-fit: cover;\n      display: block;\n    }\n\n    .feat-avatar.is-mystery {\n      font-size: 18px;\n      background: rgba(255, 255, 255, 0.08);\n    }\n\n    .feat-node.is-center .feat-avatar {\n      width: 40px;\n      height: 40px;\n      flex-basis: 40px;\n      font-size: 16px;\n    }\n\n    .feat-label {\n      max-width: 100%;\n      color: var(--white);\n      font-size: 9px;\n      line-height: 1.15;\n      font-weight: 700;\n      text-align: center;\n      white-space: nowrap;\n      overflow: hidden;\n      text-overflow: ellipsis;\n    }\n\n    .feat-node.is-center .feat-label {\n      font-size: 10px;\n    }\n\n    .feat-node.is-center .feat-label,\n    .feat-node.is-center .feat-index {\n      white-space: normal;\n      overflow: visible;\n      text-overflow: clip;\n      max-width: 100%;\n      word-break: break-word;\n      overflow-wrap: anywhere;\n    }\n\n    .feat-index {\n      color: var(--copy-soft);\n      font-size: 8px;\n      line-height: 1;\n      font-weight: 700;\n    }\n\n    .input-grid {\n      display: grid;\n      grid-template-columns: 152px minmax(0, 1fr) 152px 152px;\n      gap: 10px;\n      align-items: stretch;\n      width: 100%;\n      margin: 0 auto;\n    }\n\n    .attempts-card {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      border: 1px solid #fff;\n      background: #fff;\n      color: #111;\n      text-align: center;\n      white-space: nowrap;\n    }\n\n    .action-slot {\n      width: 152px;\n      min-width: 152px;\n      align-self: stretch;\n    }\n\n    .input-shell {\n      position: relative;\n      z-index: 4;\n      min-width: 0;\n    }\n\n    .input-label {\n      display: none;\n    }\n\n    .search-field {\n      width: 100%;\n      min-height: 56px;\n      height: 56px;\n      padding: 0 16px;\n      border-radius: 12px;\n      border: 1px solid rgba(255, 255, 255, 0.1);\n      background: #101010;\n      color: var(--white);\n      font-size: 15px;\n      outline: none;\n      transition: border-color var(--ease), background var(--ease), opacity var(--ease);\n    }\n\n    .search-field:focus {\n      border-color: rgba(255, 255, 255, 0.18);\n      background: #111;\n    }\n\n    .search-field::placeholder {\n      color: var(--copy-faint);\n    }\n\n    .search-field:disabled {\n      opacity: 0.5;\n      cursor: not-allowed;\n    }\n\n    .streak-card {\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      gap: 5px;\n      text-align: center;\n    }\n\n    .streak-main {\n      font-size: 15px;\n      line-height: 1;\n      font-weight: 700;\n    }\n\n    .streak-sub {\n      color: rgba(17, 17, 17, 0.74);\n      font-size: 11px;\n      line-height: 1.1;\n      font-weight: 700;\n      text-transform: none;\n      letter-spacing: 0;\n    }\n\n    .streak-card:not(.is-guest) {\n      cursor: default;\n    }\n\n    .streak-card:not(.is-guest):hover {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #111;\n      transform: none;\n    }\n\n    .suggestions {\n      position: fixed;\n      top: 0;\n      left: 0;\n      width: 280px;\n      max-height: min(280px, calc(100dvh - 24px));\n      overflow-y: auto;\n      z-index: 2147483001;\n      display: none;\n      padding: 6px;\n      border: 1px solid var(--line);\n      border-radius: 14px;\n      background: rgba(9, 9, 9, 0.98);\n      box-shadow: 0 22px 50px rgba(0, 0, 0, 0.55);\n      backdrop-filter: blur(12px);\n      overscroll-behavior: contain;\n      -webkit-overflow-scrolling: touch;\n    }\n\n    .suggestion {\n      width: 100%;\n      display: flex;\n      justify-content: space-between;\n      gap: 8px;\n      padding: 11px 12px;\n      border: 0;\n      border-radius: 10px;\n      background: transparent;\n      color: var(--white);\n      text-align: left;\n      cursor: pointer;\n    }\n\n    .suggestion small {\n      color: var(--copy-faint);\n      font-size: 11px;\n    }\n\n    .message {\n      display: none;\n      width: 100%;\n      margin: 0;\n      padding: 10px 12px;\n      border-radius: 999px;\n      border: 1px solid var(--line);\n      background: rgba(255, 255, 255, 0.03);\n      color: var(--copy);\n      font-size: 13px;\n      line-height: 1.45;\n      text-align: center;\n    }\n\n    .message.is-visible {\n      display: block;\n    }\n\n    .message.is-success {\n      border-color: rgba(125, 197, 106, 0.36);\n      background: rgba(125, 197, 106, 0.1);\n      color: #daf2d3;\n    }\n\n    .message.is-error,\n    .message.is-error-final {\n      border-color: rgba(255, 126, 89, 0.32);\n      background: rgba(255, 126, 89, 0.1);\n      color: #ffd7c6;\n    }\n\n    .results-list {\n      display: grid;\n      gap: 12px;\n      margin-top: 0;\n      width: 100%;\n    }\n\n    .empty-state {\n      padding: 16px;\n      border: 1px dashed rgba(255, 255, 255, 0.15);\n      border-radius: 12px;\n      color: var(--copy-soft);\n      font-size: 13px;\n      line-height: 1.5;\n      text-align: center;\n    }\n\n    .answer-card {\n      padding: 18px;\n      border: 1px solid var(--line-faint);\n      border-radius: 22px;\n      background: linear-gradient(180deg, rgba(14, 14, 14, 0.96), rgba(10, 10, 10, 0.96));\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n      text-align: left;\n    }\n\n    .answer-card.is-correct {\n      border-color: rgba(125, 197, 106, 0.34);\n    }\n\n    .demo-app.is-ranked-mode .feat-node.is-important {\n      border-color: rgba(149, 40, 0, 0.32);\n      background: rgba(149, 40, 0, 0.09);\n    }\n\n    .demo-app.is-ranked-mode .feat-avatar {\n      background:\n        radial-gradient(circle at 32% 28%, rgba(149, 40, 0, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(149, 40, 0, 0.16), rgba(255, 255, 255, 0.03));\n    }\n\n    .demo-app.is-ranked-mode #rankedSubmitButton.button,\n    .demo-app.is-ranked-mode #rankedSideActionButton.secondary-button.is-primary {\n      background: #952800 !important;\n      border-color: #952800 !important;\n      color: #111 !important;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .button:hover,\n    .demo-app.is-ranked-mode .feat-ranked-form .secondary-button.is-primary:hover {\n      background: #fff;\n      border-color: #fff;\n      color: #111;\n    }\n\n    .demo-app.is-ranked-mode #rankedSubmitButton.button:hover,\n    .demo-app.is-ranked-mode #rankedSideActionButton.secondary-button.is-primary:hover {\n      background: #fff !important;\n      border-color: #fff !important;\n      color: #111 !important;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .input-shell {\n      border: 2px solid #080808;\n      border-radius: 0;\n      background: #101010;\n      overflow: hidden;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .action-slot,\n    .demo-app.is-ranked-mode .feat-ranked-form .button,\n    .demo-app.is-ranked-mode .feat-ranked-form .secondary-button {\n      position: relative;\n      z-index: 8;\n      pointer-events: auto;\n      touch-action: manipulation;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .search-field {\n      border: 0;\n      border-radius: 0;\n      background: transparent;\n      box-shadow: none;\n      transition: none;\n      appearance: none;\n      -webkit-appearance: none;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .search-field:focus {\n      background: transparent;\n      box-shadow: none;\n      border-color: transparent;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .search-field::placeholder {\n      color: rgba(247, 244, 239, 0.18);\n      opacity: 1;\n    }\n\n    .demo-app.is-ranked-mode .message.is-error,\n    .demo-app.is-ranked-mode .message.is-error-final {\n      border-color: rgba(149, 40, 0, 0.32);\n      background: rgba(149, 40, 0, 0.1);\n      color: #ffd7b5;\n    }\n\n    .ranked-summary-panel {\n      margin-top: 0;\n      padding: 16px;\n      border: 1px solid rgba(149, 40, 0, 0.28);\n      border-radius: 18px;\n      background: rgba(149, 40, 0, 0.08);\n    }\n\n    .ranked-summary-panel.hidden {\n      display: none;\n    }\n\n    .ranked-summary-panel.is-record {\n      border-color: rgba(125, 197, 106, 0.32);\n      background: rgba(125, 197, 106, 0.08);\n    }\n\n    .ranked-summary-title {\n      margin: 0 0 10px;\n      color: #fff;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(22px, 4vw, 28px);\n      line-height: 1;\n      letter-spacing: -0.04em;\n      font-weight: 800;\n    }\n\n    .ranked-summary-lines {\n      display: grid;\n      gap: 5px;\n    }\n\n    .ranked-summary-line {\n      color: var(--white);\n      font-size: 14px;\n      line-height: 1.5;\n      font-weight: 600;\n    }\n\n    .ranked-summary-line strong {\n      font-weight: 800;\n    }\n\n    .answer-card-head {\n      display: grid;\n      grid-template-columns: 92px minmax(0, 1fr);\n      gap: 16px;\n      align-items: center;\n      margin-bottom: 14px;\n    }\n\n    .answer-cover {\n      position: relative;\n      width: 92px;\n      height: 92px;\n      border: 1px solid rgba(255, 255, 255, 0.12);\n      border-radius: 50%;\n      background:\n        radial-gradient(circle at 32% 28%, rgba(241, 108, 29, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(241, 108, 29, 0.16), rgba(255, 255, 255, 0.03));\n      overflow: hidden;\n      box-shadow: 0 18px 34px rgba(0, 0, 0, 0.34);\n    }\n\n    .answer-cover img {\n      width: 100%;\n      height: 100%;\n      object-fit: cover;\n      display: block;\n    }\n\n    .answer-cover-fallback {\n      width: 100%;\n      height: 100%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      color: var(--white);\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: 28px;\n      font-weight: 700;\n      letter-spacing: -0.04em;\n      text-transform: uppercase;\n    }\n\n    .answer-copy {\n      min-width: 0;\n      display: flex;\n      flex-direction: column;\n      gap: 10px;\n      align-items: flex-start;\n    }\n\n    .answer-badge {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      min-height: 28px;\n      padding: 0 12px;\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      color: var(--copy-soft);\n      font-size: 11px;\n      font-weight: 700;\n    }\n\n    .answer-name {\n      margin: 0;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(28px, 4vw, 34px);\n      line-height: 1;\n      letter-spacing: -0.04em;\n    }\n\n    .answer-sub {\n      margin: -2px 0 0;\n      color: var(--copy-soft);\n      font-size: 12px;\n      line-height: 1.45;\n    }\n\n    .answer-stats {\n      display: grid;\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 8px;\n    }\n\n    .answer-stat {\n      min-height: 90px;\n      padding: 12px 10px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      border-radius: 14px;\n      background: rgba(255, 255, 255, 0.04);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      align-items: center;\n      text-align: center;\n    }\n\n    .answer-stat-label {\n      display: block;\n      color: var(--white);\n      opacity: 0.92;\n      font-size: 12px;\n      font-weight: 700;\n    }\n\n    .answer-stat-value {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      font-size: clamp(15px, 1.8vw, 18px);\n      line-height: 1.06;\n      font-weight: 800;\n      letter-spacing: -0.03em;\n      text-align: center;\n    }\n\n    .feat-embed-shell {\n      margin-top: 12px;\n      padding-top: 12px;\n      border-top: 1px solid var(--line);\n    }\n\n    .feat-embed-shell::after {\n      content: \"\";\n      display: block;\n      margin-top: 12px;\n      border-top: 1px solid var(--line);\n    }\n\n    .feat-embed-shell iframe {\n      width: 100%;\n      min-height: 152px;\n      border: 0;\n      border-radius: 16px;\n      background: #0b0b0b;\n    }\n\n    .feat-tip {\n      margin-top: 12px;\n      color: var(--white);\n      font-size: 15px;\n      line-height: 1.55;\n    }\n\n    .hidden {\n      display: none !important;\n    }\n\n    @media (max-width: 720px) {\n      .demo-app {\n        width: 100%;\n        max-width: 100%;\n        padding: max(6px, env(safe-area-inset-top, 0px)) 4px calc(10px + env(safe-area-inset-bottom, 0px));\n      }\n\n      .app-shell {\n        display: flex;\n        flex-direction: column;\n        padding: 8px 6px 10px;\n        border: 0;\n        border-radius: 0;\n        background: transparent;\n        box-shadow: none;\n      }\n\n      .app-shell::after {\n        display: none;\n      }\n\n      .controls-shell {\n        order: 1;\n        position: relative;\n        border-top: 0;\n        border-bottom: 1px solid var(--line);\n        padding-top: 10px;\n        padding-bottom: 20px;\n      }\n\n      .controls-shell::after {\n        content: \"Gioca\";\n        position: absolute;\n        left: 50%;\n        bottom: -11px;\n        transform: translateX(-50%) translateY(-2px);\n        padding: 0 14px;\n        background: var(--bg);\n        color: #9E9E9E;\n        font-size: 15px;\n        line-height: 1;\n      }\n\n      .topbar {\n        order: 2;\n        padding: 12px 4px 4px;\n      }\n\n      .top-logo {\n        width: min(260px, 66vw);\n      }\n\n      .shell {\n        order: 3;\n        border-top: 0;\n        padding-top: 14px;\n      }\n\n      .help-panel-mobile-slot {\n        display: block;\n      }\n\n      .controls-shell .help-panel.is-open {\n        margin: 10px 0 0;\n        padding-bottom: 0;\n        border-bottom-color: transparent;\n      }\n\n      .tab-ranked-mobile {\n        display: inline-flex;\n      }\n\n      .controls-inner .tab-ranked-mobile {\n        display: inline-flex !important;\n        width: 100%;\n      }\n\n      .input-grid {\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n        gap: 8px;\n      }\n\n      .input-shell {\n        grid-column: 1 \/ -1;\n        order: 3;\n      }\n\n      .attempts-card {\n        order: 1;\n      }\n\n      .action-slot {\n        order: 2;\n        width: auto;\n        min-width: 0;\n      }\n\n      .input-grid > .button {\n        order: 4;\n        grid-column: 1 \/ -1;\n      }\n\n      .action-slot,\n      .attempts-card,\n      .button,\n      .secondary-button,\n      .streak-card,\n      .search-field {\n        min-height: 48px;\n        height: 48px;\n      }\n\n      .search-field {\n        font-size: 16px;\n      }\n\n      .feat-circle {\n        width: 284px;\n        height: 284px;\n      }\n\n      .feat-hint-slot {\n        width: 68px;\n        height: 68px;\n        margin-left: -34px;\n        margin-top: -34px;\n      }\n\n      .feat-node.is-center {\n        width: 84px;\n        height: 84px;\n        padding: 8px 6px;\n        gap: 4px;\n      }\n\n      .feat-node.is-center .feat-label {\n        font-size: 9px;\n        line-height: 1.05;\n      }\n\n      .feat-node.is-center .feat-index {\n        font-size: 7px;\n      }\n\n      .answer-card {\n        padding: 12px;\n        border-radius: 16px;\n      }\n\n      .answer-card-head {\n        grid-template-columns: 72px minmax(0, 1fr);\n        gap: 12px;\n      }\n\n      .answer-cover {\n        width: 72px;\n        height: 72px;\n      }\n\n      .answer-name {\n        font-size: clamp(20px, 7vw, 26px);\n      }\n\n      .answer-stats {\n        grid-template-columns: 1fr;\n      }\n\n      .help-grid,\n      .feat-meta-grid,\n      .answer-stats {\n        grid-template-columns: 1fr;\n      }\n    }\n\n    @media (max-width: 520px) {\n      .demo-app {\n        padding-inline: 3px;\n      }\n\n      .controls-shell {\n        padding-top: 8px;\n      }\n\n      .top-logo {\n        width: min(232px, 64vw);\n      }\n\n      .controls-inner {\n        grid-template-columns: 1fr;\n      }\n\n      .controls-inner .tab-ranked-mobile {\n        display: inline-flex !important;\n        width: 100%;\n      }\n    }\n\n    @media (max-width: 400px) {\n      .demo-app {\n        padding-inline: 2px;\n      }\n\n      .top-logo {\n        width: min(214px, 62vw);\n      }\n\n      .attempts-card,\n      .button,\n      .secondary-button,\n      .streak-main {\n        font-size: 12px;\n      }\n\n      .streak-sub {\n        font-size: 8px;\n      }\n\n      .feat-circle {\n        width: 268px;\n        height: 268px;\n      }\n\n      .feat-node.is-center {\n        width: 82px;\n        height: 82px;\n      }\n    }\n\n    @media (hover: none), (pointer: coarse) {\n      .tab:hover,\n      .ghost-button:hover,\n      .button:hover,\n      .secondary-button:hover,\n      .streak-card.is-guest:hover,\n      .suggestion:hover {\n        transform: none;\n      }\n\n      .button:hover,\n      .secondary-button.is-primary:hover,\n      .streak-card.is-guest:hover {\n        background: var(--accent);\n        border-color: var(--accent);\n        color: #111;\n      }\n\n      .secondary-button.is-muted:hover {\n        background: rgba(255, 255, 255, 0.03);\n        border-color: var(--line);\n        color: var(--white);\n      }\n\n      .button:active,\n      .secondary-button:active,\n      .streak-card.is-guest:active,\n      .tab:active,\n      .ghost-button:active,\n      .suggestion:active {\n        transform: scale(0.99);\n      }\n    }\n\n    @media (max-width: 720px) {\n      .demo-app .top-logo {\n        margin-top: 14px !important;\n      }\n\n      .demo-app .controls-inner {\n        margin-bottom: 18px !important;\n      }\n    }\n  <\/style>\n<\/head>\n<body>\n  <div class=\"demo-app\">\n    <div class=\"app-shell\">\n      <header class=\"topbar\">\n        <img decoding=\"async\" class=\"top-logo\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1.png\" alt=\"BulldogFeat\">\n      <\/header>\n\n      <section class=\"controls-shell\" aria-label=\"Controlli BulldogFeat\">\n        <div class=\"controls-inner\">\n          <button class=\"tab is-active\" data-mode=\"classic\" type=\"button\">Daily<\/button>\n          <button class=\"tab\" data-mode=\"practice\" type=\"button\">Allenamento<\/button>\n          <button id=\"rankedModeButton\" class=\"tab tab-ranked-mobile\" type=\"button\">Classificata<\/button>\n          <button id=\"helpToggle\" class=\"ghost-button\" type=\"button\">Come si gioca<\/button>\n        <\/div>\n        <div id=\"helpPanelMobileSlot\" class=\"help-panel-mobile-slot\"><\/div>\n      <\/section>\n\n      <main class=\"shell\">\n        <section class=\"game-shell\">\n          <section id=\"helpPanel\" class=\"help-panel\" aria-hidden=\"true\">\n            <div class=\"help-grid\">\n              <div class=\"help-card\">\n                <strong>Obiettivo<\/strong>\n                <span>Trova il rapper segreto partendo dalle sue collaborazioni.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Centro<\/strong>\n                <span>Al centro vedi il tipo dell'artista corretto: Rapper, Producer, Gruppo o Duo.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Feat<\/strong>\n                <span>Ogni errore svela un nuovo feat. Le ultime 2 carte evidenziate sono le collaborazioni piu forti.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Daily<\/strong>\n                <span>Hai 5 tentativi. La partita del giorno si salva in locale.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Allenamento<\/strong>\n                <span>Puoi cambiare artista quando vuoi con NUOVO e continuare a fare pratica.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Progressione<\/strong>\n                <span>Parti da 1 feat visibile. Ogni errore ne sblocca un altro.<\/span>\n              <\/div>\n            <\/div>\n          <\/section>\n\n          <section id=\"rankedHelpPanel\" class=\"help-panel hidden\" aria-hidden=\"true\">\n            <div class=\"help-grid\">\n              <div class=\"help-card\">\n                <strong>Timer<\/strong>\n                <span>Hai 2 minuti per fare il punteggio piu alto possibile.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Punti<\/strong>\n                <span>Ogni rapper corretto vale 1 punto e aggiunge 15 secondi.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Skip<\/strong>\n                <span>Puoi saltare il round corrente, ma perdi 15 secondi.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Tentativi<\/strong>\n                <span>Hai 5 tentativi per round. Se li finisci, passi al successivo.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Reveal<\/strong>\n                <span>L'artista corretto del round chiuso resta come indizio iniziale del round dopo.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Record<\/strong>\n                <span>Il punteggio migliore viene salvato nella classifica mensile della classificata.<\/span>\n              <\/div>\n            <\/div>\n          <\/section>\n\n          <section id=\"standardGamePanel\" class=\"feat-panel\">\n            <div id=\"gameMsg\" class=\"message\" aria-live=\"polite\"><\/div>\n\n            <div id=\"resultsList\" class=\"results-list\">\n            <\/div>\n\n            <div class=\"feat-board-shell\">\n              <div class=\"feat-circle\">\n                <div id=\"centerArtist\" class=\"feat-center-slot\"><\/div>\n                <div id=\"hint-0\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-1\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-2\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-3\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-4\" class=\"feat-hint-slot\"><\/div>\n              <\/div>\n            <\/div>\n\n            <form id=\"guessForm\" class=\"input-grid\" autocomplete=\"off\">\n              <div id=\"attemptsCard\" class=\"attempts-card\" aria-live=\"polite\">5 TENTATIVI<\/div>\n\n              <div class=\"input-shell\">\n                <label id=\"inputLabel\" class=\"input-label\" for=\"artistInput\">inserisci un artista<\/label>\n                <input id=\"artistInput\" class=\"search-field\" type=\"text\" placeholder=\"inserisci un artista\" aria-describedby=\"gameMsg\">\n                <div id=\"suggestions\" class=\"suggestions\" role=\"listbox\" aria-label=\"Suggerimenti artisti\"><\/div>\n              <\/div>\n\n              <button id=\"submitButton\" class=\"button\" type=\"submit\">PROVA<\/button>\n\n              <div class=\"action-slot\">\n                <button id=\"modeActionButton\" class=\"secondary-button is-primary hidden\" type=\"button\">NUOVO<\/button>\n                <a id=\"dailyStreakCard\" class=\"streak-card hidden is-guest\" href=\"https:\/\/bulldogmusik.it\/account-login\/\" aria-label=\"Accedi per salvare la streak\">\n                  <span id=\"dailyStreakMain\" class=\"streak-main\">STREAK<\/span>\n                  <span id=\"dailyStreakSub\" class=\"streak-sub\">Accedi per salvarla<\/span>\n                <\/a>\n              <\/div>\n            <\/form>\n          <\/section>\n\n          <section id=\"rankedGamePanel\" class=\"feat-ranked-panel hidden\">\n            <section class=\"feat-meta-grid\" aria-label=\"Statistiche Classificata\">\n              <article class=\"feat-meta-card is-accent\">\n                <span class=\"feat-meta-label\">Tempo<\/span>\n                <strong id=\"rankedTimerValue\" class=\"feat-meta-value\">2:00<\/strong>\n              <\/article>\n              <article class=\"feat-meta-card\">\n                <span class=\"feat-meta-label\">Punti<\/span>\n                <strong id=\"rankedScoreValue\" class=\"feat-meta-value\">0<\/strong>\n              <\/article>\n            <\/section>\n\n            <section id=\"rankedSummaryPanel\" class=\"ranked-summary-panel hidden\" aria-live=\"polite\">\n              <h3 id=\"rankedSummaryTitle\" class=\"ranked-summary-title\">Partita conclusa<\/h3>\n              <div id=\"rankedSummaryLines\" class=\"ranked-summary-lines\"><\/div>\n            <\/section>\n\n            <div id=\"rankedGameMsg\" class=\"message\" aria-live=\"polite\"><\/div>\n\n            <div id=\"rankedResultsList\" class=\"results-list\">\n            <\/div>\n\n            <div id=\"rankedBoardShell\" class=\"feat-board-shell hidden\">\n              <div class=\"feat-circle\">\n                <div id=\"rankedCenterArtist\" class=\"feat-center-slot\"><\/div>\n                <div id=\"ranked-hint-0\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-1\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-2\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-3\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-4\" class=\"feat-hint-slot\"><\/div>\n              <\/div>\n            <\/div>\n\n            <form id=\"rankedGuessForm\" class=\"input-grid feat-ranked-form\" autocomplete=\"off\">\n              <div id=\"rankedAttemptsCard\" class=\"attempts-card\" aria-live=\"polite\">5 TENTATIVI<\/div>\n\n              <div class=\"input-shell\">\n                <input id=\"rankedArtistInput\" class=\"search-field\" type=\"text\" placeholder=\"inserisci un artista\" aria-describedby=\"rankedGameMsg\">\n                <div id=\"rankedSuggestions\" class=\"suggestions\" role=\"listbox\" aria-label=\"Suggerimenti artisti classificata\"><\/div>\n              <\/div>\n\n              <button id=\"rankedSubmitButton\" class=\"button\" type=\"submit\">PROVA<\/button>\n\n              <div class=\"action-slot\">\n                <button id=\"rankedSideActionButton\" class=\"secondary-button is-primary\" type=\"button\" data-action=\"start\">INIZIA<\/button>\n              <\/div>\n            <\/form>\n          <\/section>\n        <\/section>\n      <\/main>\n    <\/div>\n  <\/div>\n\n  <script>\n    (async function () {\n      const bootstrapScript = document.currentScript;\n\n      async function loadScriptSource(src) {\n        return new Promise((resolve) => {\n          const existing = Array.from(document.querySelectorAll(\"script[src]\")).find((node) => node.src === src);\n          if (existing && Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n            resolve(true);\n            return;\n          }\n\n          const script = document.createElement(\"script\");\n          script.src = src;\n          script.async = false;\n          script.onload = () => resolve(true);\n          script.onerror = () => resolve(false);\n          document.head.appendChild(script);\n        });\n      }\n\n      async function ensureArtistsLoaded() {\n        if (Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n          return window.bulldogleArtists;\n        }\n\n        const sources = [\n          \".\/artists.js\",\n          \"artists.js\",\n          \"\/bulldogle\/artists.js?v=31\"\n        ];\n\n        if (window.location && \/^https?:\/i.test(window.location.protocol) && window.location.origin) {\n          sources.push(window.location.origin + \"\/bulldogle\/artists.js?v=31\");\n        }\n\n        sources.push(\"https:\/\/bulldogmusik.it\/bulldogle\/artists.js?v=31\");\n\n        for (const source of sources) {\n          const loaded = await loadScriptSource(source);\n          if (loaded && Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n            return window.bulldogleArtists;\n          }\n        }\n\n        return [];\n      }\n\n      const artistsSource = await ensureArtistsLoaded();\n      const featConfig = window.bulldogleFeatConfig || {};\n      const rankedConfig = window.bulldogleRankedConfig || {};\n      const guestLoginUrl = \"https:\/\/bulldogmusik.it\/account-login\/\";\n      const MAX_ATTEMPTS = 5;\n      const CLASSIC_LOGO_URL = \"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1.png\";\n      const RANKED_LOGO_URL = \"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato.png\";\n      const RANKED_ATTEMPTS = 5;\n      const RANKED_INITIAL_TIME = 120;\n      const RANKED_CORRECT_BONUS = 15;\n      const RANKED_SKIP_PENALTY = 15;\n      const RANKED_ROUND_TRANSITION_MS = 1000;\n      const RANKED_GAME_KEY = \"feat\";\n      const hasRankedBackend = Boolean(rankedConfig && rankedConfig.ajaxUrl && rankedConfig.nonce);\n      const spotifyThumbStorageKey = \"bulldogfeat-spotify-thumbs-v1\";\n\n      const demoRoots = Array.from(document.querySelectorAll(\".demo-app\"));\n      const appRoot = bootstrapScript &&\n        bootstrapScript.previousElementSibling &&\n        bootstrapScript.previousElementSibling.classList &&\n        bootstrapScript.previousElementSibling.classList.contains(\"demo-app\")\n          ? bootstrapScript.previousElementSibling\n          : demoRoots[demoRoots.length - 1];\n\n      if (!appRoot) return;\n\n      const elements = {\n        topLogo: appRoot.querySelector(\".top-logo\"),\n        tabs: Array.from(appRoot.querySelectorAll(\".tab[data-mode]\")),\n        rankedModeButton: appRoot.querySelector(\"#rankedModeButton\"),\n        helpToggle: appRoot.querySelector(\"#helpToggle\"),\n        helpPanel: appRoot.querySelector(\"#helpPanel\"),\n        rankedHelpPanel: appRoot.querySelector(\"#rankedHelpPanel\"),\n        helpPanelMobileSlot: appRoot.querySelector(\"#helpPanelMobileSlot\"),\n        standardGamePanel: appRoot.querySelector(\"#standardGamePanel\"),\n        rankedGamePanel: appRoot.querySelector(\"#rankedGamePanel\"),\n        attemptsCard: appRoot.querySelector(\"#attemptsCard\"),\n        guessForm: appRoot.querySelector(\"#guessForm\"),\n        input: appRoot.querySelector(\"#artistInput\"),\n        suggestions: appRoot.querySelector(\"#suggestions\"),\n        submitButton: appRoot.querySelector(\"#submitButton\"),\n        modeActionButton: appRoot.querySelector(\"#modeActionButton\"),\n        dailyStreakCard: appRoot.querySelector(\"#dailyStreakCard\"),\n        dailyStreakMain: appRoot.querySelector(\"#dailyStreakMain\"),\n        dailyStreakSub: appRoot.querySelector(\"#dailyStreakSub\"),\n        message: appRoot.querySelector(\"#gameMsg\"),\n        resultsList: appRoot.querySelector(\"#resultsList\"),\n        centerArtist: appRoot.querySelector(\"#centerArtist\"),\n        hints: Array.from({ length: 5 }, (_, index) => appRoot.querySelector(\"#hint-\" + index)),\n        rankedTimerValue: appRoot.querySelector(\"#rankedTimerValue\"),\n        rankedScoreValue: appRoot.querySelector(\"#rankedScoreValue\"),\n        rankedAttemptsCard: appRoot.querySelector(\"#rankedAttemptsCard\"),\n        rankedGuessForm: appRoot.querySelector(\"#rankedGuessForm\"),\n        rankedInput: appRoot.querySelector(\"#rankedArtistInput\"),\n        rankedSuggestions: appRoot.querySelector(\"#rankedSuggestions\"),\n        rankedSubmitButton: appRoot.querySelector(\"#rankedSubmitButton\"),\n        rankedSideActionButton: appRoot.querySelector(\"#rankedSideActionButton\"),\n        rankedSummaryPanel: appRoot.querySelector(\"#rankedSummaryPanel\"),\n        rankedSummaryTitle: appRoot.querySelector(\"#rankedSummaryTitle\"),\n        rankedSummaryLines: appRoot.querySelector(\"#rankedSummaryLines\"),\n        rankedMessage: appRoot.querySelector(\"#rankedGameMsg\"),\n        rankedResultsList: appRoot.querySelector(\"#rankedResultsList\"),\n        rankedBoardShell: appRoot.querySelector(\"#rankedBoardShell\"),\n        rankedCenterArtist: appRoot.querySelector(\"#rankedCenterArtist\"),\n        rankedHints: Array.from({ length: 5 }, (_, index) => appRoot.querySelector(\"#ranked-hint-\" + index))\n      };\n\n      if (!elements.guessForm || !elements.input || !elements.submitButton || !elements.suggestions) {\n        return;\n      }\n\n      const desktopHelpPanelParent = elements.helpPanel ? elements.helpPanel.parentElement : null;\n      const desktopHelpPanelNextSibling = elements.helpPanel ? elements.helpPanel.nextElementSibling : null;\n      const desktopRankedHelpPanelParent = elements.rankedHelpPanel ? elements.rankedHelpPanel.parentElement : null;\n      const desktopRankedHelpPanelNextSibling = elements.rankedHelpPanel ? elements.rankedHelpPanel.nextElementSibling : null;\n\n      if (elements.suggestions.parentElement !== document.body) {\n        document.body.appendChild(elements.suggestions);\n      }\n      if (elements.rankedSuggestions && elements.rankedSuggestions.parentElement !== document.body) {\n        document.body.appendChild(elements.rankedSuggestions);\n      }\n\n      const spotifyThumbCache = new Map();\n      const spotifyThumbRequests = new Map();\n      let messageTimeoutId = 0;\n      let streakLoading = false;\n      let rankedMessageTimeoutId = 0;\n\n      try {\n        const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n        Object.keys(storedThumbs).forEach((spotifyId) => {\n          if (storedThumbs[spotifyId]) {\n            spotifyThumbCache.set(spotifyId, String(storedThumbs[spotifyId]));\n          }\n        });\n      } catch (_) {}\n\n      const artists = artistsSource.map((artist) => ({\n        id: Number(artist.id),\n        name: String(artist.name || \"\").trim(),\n        city: String(artist.city || \"\").trim(),\n        region: String(artist.region || \"\").trim(),\n        debutYear: Number(artist.debutYear || 0),\n        members: String(artist.members || \"\").trim(),\n        popularity: String(artist.popularity || \"\").trim(),\n        spotifyId: String(artist.spotifyId || \"\").trim(),\n        collab: String(artist.collab || \"\").trim(),\n        collabmid: String(artist.collabmid || \"\").trim(),\n        tip: String(artist.tip || \"\").trim()\n      })).filter((artist) => artist.id && artist.name);\n\n      const validArtists = artists.filter((artist) => {\n        const midCount = splitList(artist.collabmid).length;\n        const collabCount = splitList(artist.collab).length;\n        return midCount >= 3 && (midCount + collabCount) >= 5;\n      });\n\n      if (!validArtists.length) {\n        setMessage(\"Nessun artista valido trovato per BulldogFeat.\", \"error-final\");\n        disableInput(true);\n        return;\n      }\n\n      const italyDateInfo = getItalyDateInfo();\n      const dailyStorageKey = \"bulldogle_feat_\" + italyDateInfo.dayKey;\n      const localRankedBestKey = \"bulldogle_feat_ranked_best\";\n\n      const app = {\n        mode: \"classic\",\n        modes: {\n          classic: createGameState(pickDailyTarget()),\n          practice: createGameState(pickRandomValidArtist())\n        },\n        ranked: {\n          active: false,\n          preparing: false,\n          submitting: false,\n          complete: false,\n          betweenRounds: false,\n          sessionToken: \"\",\n          currentArtist: null,\n          hints: [],\n          revealedHints: 1,\n          roundAttempts: 0,\n          roundGuessedIds: new Set(),\n          usedTargetIds: new Set(),\n          score: 0,\n          timeLeft: RANKED_INITIAL_TIME,\n          results: [],\n          timerId: 0,\n          roundTransitionId: 0,\n          summaryTitle: \"Partita conclusa\",\n          summaryLines: [],\n          isRecord: false,\n          lastRoundSolved: false\n        }\n      };\n\n      function createGameState(targetArtist) {\n        return {\n          target: targetArtist,\n          hints: buildHintSet(targetArtist),\n          attempts: 0,\n          revealedHints: 1,\n          guessedIds: new Set(),\n          complete: false,\n          status: \"playing\"\n        };\n      }\n\n      function normalize(value) {\n        return String(value || \"\").trim().toLowerCase();\n      }\n\n      function splitList(value) {\n        return String(value || \"\")\n          .split(\",\")\n          .map((entry) => entry.trim())\n          .filter(Boolean);\n      }\n\n      function hashString(value) {\n        let hash = 2166136261;\n        for (let index = 0; index < value.length; index++) {\n          hash ^= value.charCodeAt(index);\n          hash = Math.imul(hash, 16777619);\n        }\n        return hash >>> 0;\n      }\n\n      function createSeededRandom(seed) {\n        let randomState = seed >>> 0;\n        return function () {\n          randomState += 0x6D2B79F5;\n          let value = Math.imul(randomState ^ (randomState >>> 15), 1 | randomState);\n          value ^= value + Math.imul(value ^ (value >>> 7), 61 | value);\n          return ((value ^ (value >>> 14)) >>> 0) \/ 4294967296;\n        };\n      }\n\n      function shuffle(array, randomFn) {\n        const next = array.slice();\n        for (let index = next.length - 1; index > 0; index--) {\n          const swapIndex = Math.floor(randomFn() * (index + 1));\n          const temp = next[index];\n          next[index] = next[swapIndex];\n          next[swapIndex] = temp;\n        }\n        return next;\n      }\n\n      function getItalyDateInfo() {\n        const formatter = new Intl.DateTimeFormat(\"en-CA\", {\n          timeZone: \"Europe\/Rome\",\n          year: \"numeric\",\n          month: \"2-digit\",\n          day: \"2-digit\"\n        });\n\n        const parts = formatter.formatToParts(new Date());\n        const year = Number(parts.find((part) => part.type === \"year\").value);\n        const month = Number(parts.find((part) => part.type === \"month\").value);\n        const day = Number(parts.find((part) => part.type === \"day\").value);\n\n        return {\n          dayKey: year + \"-\" + String(month).padStart(2, \"0\") + \"-\" + String(day).padStart(2, \"0\")\n        };\n      }\n\n      function formatTime(totalSeconds) {\n        const safeTime = Math.max(0, Number(totalSeconds || 0));\n        const minutes = Math.floor(safeTime \/ 60);\n        const seconds = String(safeTime % 60).padStart(2, \"0\");\n        return minutes + \":\" + seconds;\n      }\n\n      function findArtistByName(name) {\n        const normalized = normalize(name);\n        return artists.find((artist) => normalize(artist.name) === normalized);\n      }\n\n      function findArtistById(id) {\n        return artists.find((artist) => artist.id === id);\n      }\n\n      function pickDailyTarget() {\n        const random = createSeededRandom(hashString(\"feat|\" + italyDateInfo.dayKey));\n        const index = Math.floor(random() * validArtists.length);\n        return validArtists[index] || validArtists[0];\n      }\n\n      function pickRandomValidArtist(excludedIds) {\n        const blocked = excludedIds || new Set();\n        let pool = validArtists.filter((artist) => !blocked.has(artist.id));\n        if (!pool.length) {\n          pool = validArtists.slice();\n        }\n        return pool[Math.floor(Math.random() * pool.length)];\n      }\n\n      function buildHintSet(targetArtist) {\n        const usedIds = new Set([targetArtist.id]);\n        const hints = [];\n\n        addHintsFromNames(splitList(targetArtist.collabmid), 3, \"collabmid\");\n        addHintsFromNames(splitList(targetArtist.collab), 2, \"collab\");\n\n        if (hints.length < 5) {\n          const fallback = shuffle(\n            artists.filter((artist) => !usedIds.has(artist.id)),\n            Math.random\n          );\n\n          for (const artist of fallback) {\n            if (hints.length >= 5) break;\n            hints.push({ artist: artist, source: \"fallback\" });\n            usedIds.add(artist.id);\n          }\n        }\n\n        return hints.slice(0, 5);\n\n        function addHintsFromNames(names, limit, source) {\n          const pool = shuffle(Array.from(new Set(names)), Math.random);\n          for (const name of pool) {\n            if (hints.filter((hint) => hint.source === source).length >= limit || hints.length >= 5) {\n              break;\n            }\n            const artist = findArtistByName(name);\n            if (!artist || usedIds.has(artist.id)) {\n              continue;\n            }\n            hints.push({ artist: artist, source: source });\n            usedIds.add(artist.id);\n          }\n        }\n      }\n\n      function serializeHints(hints) {\n        return hints.map((hint) => ({\n          id: hint.artist.id,\n          source: hint.source\n        }));\n      }\n\n      function restoreHints(savedHints) {\n        if (!Array.isArray(savedHints) || savedHints.length !== 5) {\n          return null;\n        }\n\n        const restored = [];\n        const usedIds = new Set();\n        for (const savedHint of savedHints) {\n          const artist = findArtistById(Number(savedHint.id));\n          if (!artist || usedIds.has(artist.id)) {\n            return null;\n          }\n          restored.push({ artist: artist, source: savedHint.source || \"fallback\" });\n          usedIds.add(artist.id);\n        }\n        return restored;\n      }\n\n      function getInitials(name) {\n        return String(name || \"\")\n          .split(\/\\s+\/)\n          .filter(Boolean)\n          .map((word) => word.charAt(0))\n          .join(\"\")\n          .slice(0, 2)\n          .toUpperCase() || \"BF\";\n      }\n\n      function persistSpotifyThumbnailUrl(spotifyId, thumbnailUrl) {\n        if (!spotifyId || !thumbnailUrl) return;\n        try {\n          const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n          storedThumbs[spotifyId] = thumbnailUrl;\n          window.localStorage.setItem(spotifyThumbStorageKey, JSON.stringify(storedThumbs));\n        } catch (_) {}\n      }\n\n      function clearSpotifyThumbnailUrl(spotifyId) {\n        if (!spotifyId) return;\n        spotifyThumbCache.delete(spotifyId);\n        spotifyThumbRequests.delete(spotifyId);\n        try {\n          const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n          delete storedThumbs[spotifyId];\n          window.localStorage.setItem(spotifyThumbStorageKey, JSON.stringify(storedThumbs));\n        } catch (_) {}\n      }\n\n      async function getSpotifyThumbnailUrl(spotifyId) {\n        if (!spotifyId) return \"\";\n        if (spotifyThumbCache.has(spotifyId)) {\n          return spotifyThumbCache.get(spotifyId);\n        }\n        if (spotifyThumbRequests.has(spotifyId)) {\n          return spotifyThumbRequests.get(spotifyId);\n        }\n\n        const request = (async function () {\n          const sources = [\n            \"https:\/\/open.spotify.com\/oembed?url=\" + encodeURIComponent(\"https:\/\/open.spotify.com\/artist\/\" + spotifyId),\n            \"https:\/\/open.spotify.com\/oembed?url=\" + encodeURIComponent(\"spotify:artist:\" + spotifyId)\n          ];\n\n          for (const source of sources) {\n            try {\n              const response = await fetch(source, { credentials: \"omit\" });\n              if (!response.ok) continue;\n              const payload = await response.json();\n              const thumbnailUrl = payload && payload.thumbnail_url ? String(payload.thumbnail_url) : \"\";\n              if (thumbnailUrl) {\n                spotifyThumbCache.set(spotifyId, thumbnailUrl);\n                persistSpotifyThumbnailUrl(spotifyId, thumbnailUrl);\n                return thumbnailUrl;\n              }\n            } catch (_) {}\n          }\n\n          return \"\";\n        })().finally(function () {\n          spotifyThumbRequests.delete(spotifyId);\n        });\n\n        spotifyThumbRequests.set(spotifyId, request);\n        return request;\n      }\n\n      function buildAvatar(artist, mystery, sizeClass) {\n        const avatar = document.createElement(\"div\");\n        avatar.className = \"feat-avatar\" + (mystery ? \" is-mystery\" : \"\");\n        avatar.textContent = mystery ? \"?\" : getInitials(artist.name);\n\n        if (!mystery && artist.spotifyId) {\n          getSpotifyThumbnailUrl(artist.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = artist.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              avatar.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(artist.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        return avatar;\n      }\n\n      function renderCenterCard(state) {\n        elements.centerArtist.innerHTML = \"\";\n        const node = document.createElement(\"div\");\n        node.className = \"feat-node is-center\";\n\n        if (state.complete) {\n          node.classList.add(state.status === \"won\" ? \"is-won\" : \"is-lost\");\n          node.appendChild(buildAvatar(state.target, false));\n          const name = document.createElement(\"div\");\n          name.className = \"feat-label\";\n          name.textContent = state.target.name;\n          const members = document.createElement(\"div\");\n          members.className = \"feat-index\";\n          members.textContent = state.target.members || \"Artista\";\n          node.appendChild(name);\n          node.appendChild(members);\n        } else {\n          node.appendChild(buildAvatar(state.target, true));\n          const members = document.createElement(\"div\");\n          members.className = \"feat-label\";\n          members.textContent = state.target.members || \"Artista\";\n          node.appendChild(members);\n        }\n\n        elements.centerArtist.appendChild(node);\n      }\n\n      function renderHints(state) {\n        const positions = [0, 72, 144, 216, 288];\n        const radius = 105;\n\n        state.hints.forEach((hint, index) => {\n          const angle = positions[index] * (Math.PI \/ 180);\n          const x = Math.sin(angle) * radius;\n          const y = -Math.cos(angle) * radius;\n          const slot = elements.hints[index];\n          if (!slot) return;\n\n          const isRevealed = index < state.revealedHints || state.complete;\n          slot.style.transform = \"translate(\" + x + \"px, \" + y + \"px)\";\n          slot.innerHTML = \"\";\n\n          const node = document.createElement(\"div\");\n          node.className = \"feat-node\" + (index >= 3 ? \" is-important\" : \"\") + (!isRevealed ? \" is-hidden\" : \"\");\n          node.appendChild(buildAvatar(hint.artist, !isRevealed));\n\n          const label = document.createElement(\"div\");\n          label.className = \"feat-label\";\n          label.textContent = isRevealed ? hint.artist.name : \"?\";\n          node.appendChild(label);\n\n          if (!isRevealed) {\n            const number = document.createElement(\"div\");\n            number.className = \"feat-index\";\n            number.textContent = String(index + 1);\n            node.appendChild(number);\n          }\n\n          slot.appendChild(node);\n        });\n      }\n\n      function renderBoard() {\n        const state = getCurrentState();\n        renderCenterCard(state);\n        renderHints(state);\n      }\n\n      function buildAnswerCard(state, solved) {\n        const article = document.createElement(\"article\");\n        article.className = \"answer-card\" + (solved ? \" is-correct\" : \"\");\n\n        const top = document.createElement(\"div\");\n        top.className = \"answer-card-head\";\n\n        const cover = document.createElement(\"div\");\n        cover.className = \"answer-cover\";\n        const coverFallback = document.createElement(\"div\");\n        coverFallback.className = \"answer-cover-fallback\";\n        coverFallback.textContent = getInitials(state.target.name);\n        cover.appendChild(coverFallback);\n\n        if (state.target.spotifyId) {\n          getSpotifyThumbnailUrl(state.target.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = state.target.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              cover.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(state.target.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        const copy = document.createElement(\"div\");\n        copy.className = \"answer-copy\";\n\n        const badge = document.createElement(\"span\");\n        badge.className = \"answer-badge\";\n        badge.textContent = solved ? \"Hai indovinato\" : \"Artista corretto\";\n\n        const name = document.createElement(\"h3\");\n        name.className = \"answer-name\";\n        name.textContent = state.target.name;\n\n        const sub = document.createElement(\"p\");\n        sub.className = \"answer-sub\";\n        sub.textContent = (state.target.members || \"Artista\") + \" \u2022 \" + state.revealedHints + \"\/5 feat visibili\";\n\n        copy.appendChild(badge);\n        copy.appendChild(name);\n        copy.appendChild(sub);\n        top.appendChild(cover);\n        top.appendChild(copy);\n        article.appendChild(top);\n\n        const strongFeatCount = splitList(state.target.collabmid).length;\n        const allFeatCount = strongFeatCount + splitList(state.target.collab).length;\n        const stats = [\n          { label: \"Tipo\", value: state.target.members || \"Artista\" },\n          { label: \"Feat stretti\", value: String(strongFeatCount) },\n          { label: \"Feat totali\", value: String(allFeatCount) }\n        ];\n\n        const statsGrid = document.createElement(\"div\");\n        statsGrid.className = \"answer-stats\";\n        stats.forEach((stat) => {\n          const item = document.createElement(\"div\");\n          item.className = \"answer-stat\";\n          const label = document.createElement(\"span\");\n          label.className = \"answer-stat-label\";\n          label.textContent = stat.label;\n          const value = document.createElement(\"span\");\n          value.className = \"answer-stat-value\";\n          value.textContent = stat.value;\n          item.appendChild(label);\n          item.appendChild(value);\n          statsGrid.appendChild(item);\n        });\n        article.appendChild(statsGrid);\n\n        if (state.target.spotifyId) {\n          const embedShell = document.createElement(\"div\");\n          embedShell.className = \"feat-embed-shell\";\n          const iframe = document.createElement(\"iframe\");\n          iframe.loading = \"lazy\";\n          iframe.allow = \"autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture\";\n          iframe.src = \"https:\/\/open.spotify.com\/embed\/artist\/\" + state.target.spotifyId + \"?utm_source=generator&theme=0\";\n          iframe.title = \"Spotify di \" + state.target.name;\n          embedShell.appendChild(iframe);\n          article.appendChild(embedShell);\n        }\n\n        if (state.target.tip) {\n          const tip = document.createElement(\"div\");\n          tip.className = \"feat-tip\";\n          tip.textContent = state.target.tip;\n          article.appendChild(tip);\n        }\n\n        return article;\n      }\n\n      function getCurrentState() {\n        return app.modes[app.mode];\n      }\n\n      function isRankedMode() {\n        return app.mode === \"ranked\";\n      }\n\n      function renderAttempts() {\n        const state = getCurrentState();\n        const attemptsLeft = Math.max(0, MAX_ATTEMPTS - state.attempts);\n        elements.attemptsCard.textContent = attemptsLeft + \" \" + (attemptsLeft === 1 ? \"TENTATIVO\" : \"TENTATIVI\");\n      }\n\n      function renderActionSlot() {\n        const practice = app.mode === \"practice\";\n        elements.modeActionButton.classList.toggle(\"hidden\", !practice);\n        elements.dailyStreakCard.classList.toggle(\"hidden\", practice);\n        elements.dailyStreakCard.classList.toggle(\"is-guest\", !practice && !featConfig.isLoggedIn);\n      }\n\n      function renderResults() {\n        elements.resultsList.innerHTML = \"\";\n        return;\n      }\n\n      function disableInput(disabled) {\n        elements.input.disabled = disabled;\n        elements.submitButton.disabled = disabled;\n      }\n\n      function renderInputState() {\n        const state = getCurrentState();\n        const disabled = state.complete;\n        disableInput(disabled);\n        if (state.complete && app.mode === \"classic\") {\n          elements.input.placeholder = \"Torna domani!\";\n        } else {\n          elements.input.placeholder = \"inserisci un artista\";\n        }\n      }\n\n      function renderTabs() {\n        elements.tabs.forEach((tab) => {\n          tab.classList.toggle(\"is-active\", tab.dataset.mode === app.mode);\n        });\n        if (elements.rankedModeButton) {\n          elements.rankedModeButton.classList.toggle(\"is-active\", isRankedMode());\n        }\n      }\n\n      function getCurrentHelpPanel() {\n        return isRankedMode() ? elements.rankedHelpPanel : elements.helpPanel;\n      }\n\n      function closeAllHelpPanels() {\n        [elements.helpPanel, elements.rankedHelpPanel].forEach((panel) => {\n          if (!panel) return;\n          panel.classList.remove(\"is-open\");\n          panel.setAttribute(\"aria-hidden\", \"true\");\n        });\n        elements.helpToggle.classList.remove(\"is-active\");\n      }\n\n      function syncHelpToggleState() {\n        const panel = getCurrentHelpPanel();\n        elements.helpToggle.classList.toggle(\"is-active\", !!panel && panel.classList.contains(\"is-open\"));\n      }\n\n      function restorePanelPlacement(panel, parent, nextSibling) {\n        if (!panel || !parent) return;\n        if (panel.parentElement === parent) return;\n\n        if (nextSibling && nextSibling.parentElement === parent) {\n          parent.insertBefore(panel, nextSibling);\n          return;\n        }\n\n        parent.appendChild(panel);\n      }\n\n      function syncHelpPanelPlacement() {\n        if (!elements.helpPanelMobileSlot) return;\n\n        const isMobileLayout = window.matchMedia(\"(max-width: 720px)\").matches;\n        const activePanel = getCurrentHelpPanel();\n\n        if (isMobileLayout) {\n          [elements.helpPanel, elements.rankedHelpPanel].forEach((panel) => {\n            if (!panel) return;\n\n            if (panel === activePanel) {\n              if (panel.parentElement !== elements.helpPanelMobileSlot) {\n                elements.helpPanelMobileSlot.appendChild(panel);\n              }\n              return;\n            }\n\n            if (panel === elements.helpPanel) {\n              restorePanelPlacement(panel, desktopHelpPanelParent, desktopHelpPanelNextSibling);\n              return;\n            }\n\n            restorePanelPlacement(panel, desktopRankedHelpPanelParent, desktopRankedHelpPanelNextSibling);\n          });\n          return;\n        }\n\n        restorePanelPlacement(elements.helpPanel, desktopHelpPanelParent, desktopHelpPanelNextSibling);\n        restorePanelPlacement(elements.rankedHelpPanel, desktopRankedHelpPanelParent, desktopRankedHelpPanelNextSibling);\n      }\n\n      function syncHelpPanelVisibility() {\n        const rankedActive = isRankedMode();\n        if (elements.helpPanel) {\n          elements.helpPanel.classList.toggle(\"hidden\", rankedActive);\n        }\n        if (elements.rankedHelpPanel) {\n          elements.rankedHelpPanel.classList.toggle(\"hidden\", !rankedActive);\n        }\n      }\n\n      function renderBranding() {\n        const rankedActive = isRankedMode();\n        elements.topLogo.src = rankedActive ? RANKED_LOGO_URL : CLASSIC_LOGO_URL;\n        elements.topLogo.alt = rankedActive ? \"BulldogFeat Classificata\" : \"BulldogFeat\";\n        appRoot.classList.toggle(\"is-ranked-mode\", rankedActive);\n        document.body.classList.toggle(\"bulldogfeat-ranked-mode-active\", rankedActive);\n        document.documentElement.classList.toggle(\"bulldogfeat-ranked-mode-active\", rankedActive);\n      }\n\n      function renderPanels() {\n        const rankedActive = isRankedMode();\n        elements.standardGamePanel.classList.toggle(\"hidden\", rankedActive);\n        elements.rankedGamePanel.classList.toggle(\"hidden\", !rankedActive);\n        syncHelpPanelVisibility();\n        syncHelpPanelPlacement();\n      }\n\n      function renderRankedCenterCard() {\n        elements.rankedCenterArtist.innerHTML = \"\";\n        const node = document.createElement(\"div\");\n        node.className = \"feat-node is-center\";\n\n        if (app.ranked.currentArtist && (app.ranked.complete || app.ranked.betweenRounds)) {\n          node.classList.add(app.ranked.lastRoundSolved ? \"is-won\" : \"is-lost\");\n          node.appendChild(buildAvatar(app.ranked.currentArtist, false));\n          const name = document.createElement(\"div\");\n          name.className = \"feat-label\";\n          name.textContent = app.ranked.currentArtist.name;\n          const members = document.createElement(\"div\");\n          members.className = \"feat-index\";\n          members.textContent = app.ranked.currentArtist.members || \"Artista\";\n          node.appendChild(name);\n          node.appendChild(members);\n        } else if (app.ranked.currentArtist) {\n          node.appendChild(buildAvatar(app.ranked.currentArtist, true));\n          const members = document.createElement(\"div\");\n          members.className = \"feat-label\";\n          members.textContent = app.ranked.currentArtist.members || \"Artista\";\n          node.appendChild(members);\n        }\n\n        elements.rankedCenterArtist.appendChild(node);\n      }\n\n      function renderRankedHints() {\n        const positions = [0, 72, 144, 216, 288];\n        const radius = 105;\n\n        app.ranked.hints.forEach((hint, index) => {\n          const angle = positions[index] * (Math.PI \/ 180);\n          const x = Math.sin(angle) * radius;\n          const y = -Math.cos(angle) * radius;\n          const slot = elements.rankedHints[index];\n          if (!slot) return;\n\n          const isRevealed = index < app.ranked.revealedHints || app.ranked.complete || app.ranked.betweenRounds;\n          slot.style.transform = \"translate(\" + x + \"px, \" + y + \"px)\";\n          slot.innerHTML = \"\";\n\n          const node = document.createElement(\"div\");\n          node.className = \"feat-node\" + (index >= 3 ? \" is-important\" : \"\");\n          node.appendChild(buildAvatar(hint.artist, !isRevealed));\n\n          const label = document.createElement(\"div\");\n          label.className = \"feat-label\";\n          label.textContent = isRevealed ? hint.artist.name : \"?\";\n          node.appendChild(label);\n\n          if (!isRevealed) {\n            const number = document.createElement(\"div\");\n            number.className = \"feat-index\";\n            number.textContent = String(index + 1);\n            node.appendChild(number);\n          }\n\n          slot.appendChild(node);\n        });\n      }\n\n      function buildRankedAnswerCard(result) {\n        const article = document.createElement(\"article\");\n        article.className = \"answer-card\" + (result.solved ? \" is-correct\" : \"\");\n\n        const top = document.createElement(\"div\");\n        top.className = \"answer-card-head\";\n\n        const cover = document.createElement(\"div\");\n        cover.className = \"answer-cover\";\n        const coverFallback = document.createElement(\"div\");\n        coverFallback.className = \"answer-cover-fallback\";\n        coverFallback.textContent = getInitials(result.artist.name);\n        cover.appendChild(coverFallback);\n\n        if (result.artist.spotifyId) {\n          getSpotifyThumbnailUrl(result.artist.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = result.artist.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              cover.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(result.artist.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        const copy = document.createElement(\"div\");\n        copy.className = \"answer-copy\";\n\n        const badge = document.createElement(\"span\");\n        badge.className = \"answer-badge\";\n        badge.textContent = result.label;\n\n        const name = document.createElement(\"h3\");\n        name.className = \"answer-name\";\n        name.textContent = result.artist.name;\n\n        const sub = document.createElement(\"p\");\n        sub.className = \"answer-sub\";\n        sub.textContent = (result.artist.members || \"Artista\") + \" \u2022 \" + result.revealedHints + \"\/5 feat visibili\";\n\n        copy.appendChild(badge);\n        copy.appendChild(name);\n        copy.appendChild(sub);\n        top.appendChild(cover);\n        top.appendChild(copy);\n        article.appendChild(top);\n\n        const strongFeatCount = splitList(result.artist.collabmid).length;\n        const allFeatCount = strongFeatCount + splitList(result.artist.collab).length;\n        const stats = [\n          { label: \"Tipo\", value: result.artist.members || \"Artista\" },\n          { label: \"Feat stretti\", value: String(strongFeatCount) },\n          { label: \"Feat totali\", value: String(allFeatCount) }\n        ];\n\n        const statsGrid = document.createElement(\"div\");\n        statsGrid.className = \"answer-stats\";\n        stats.forEach((stat) => {\n          const item = document.createElement(\"div\");\n          item.className = \"answer-stat\";\n          const label = document.createElement(\"span\");\n          label.className = \"answer-stat-label\";\n          label.textContent = stat.label;\n          const value = document.createElement(\"span\");\n          value.className = \"answer-stat-value\";\n          value.textContent = stat.value;\n          item.appendChild(label);\n          item.appendChild(value);\n          statsGrid.appendChild(item);\n        });\n        article.appendChild(statsGrid);\n\n        return article;\n      }\n\n      function renderRankedMeta() {\n        elements.rankedTimerValue.textContent = formatTime(app.ranked.timeLeft);\n        elements.rankedScoreValue.textContent = String(app.ranked.score);\n      }\n\n      function renderRankedAttempts() {\n        const attemptsLeft = Math.max(0, RANKED_ATTEMPTS - app.ranked.roundAttempts);\n        elements.rankedAttemptsCard.textContent = attemptsLeft + \" \" + (attemptsLeft === 1 ? \"TENTATIVO\" : \"TENTATIVI\");\n      }\n\n      function renderRankedInputState() {\n        const disabled = !app.ranked.active || app.ranked.betweenRounds || app.ranked.preparing || app.ranked.submitting;\n        elements.rankedInput.disabled = disabled;\n        elements.rankedSubmitButton.disabled = disabled;\n        elements.rankedInput.placeholder = app.ranked.active ? \"inserisci un artista\" : (app.ranked.complete ? \"Partita conclusa\" : \"inserisci un artista\");\n      }\n\n      function renderRankedActionButton() {\n        const button = elements.rankedSideActionButton;\n        button.className = \"secondary-button is-primary\";\n        button.disabled = false;\n\n        if (app.ranked.preparing || app.ranked.submitting) {\n          button.textContent = \"...\";\n          button.disabled = true;\n          button.dataset.action = \"wait\";\n          return;\n        }\n\n        if (app.ranked.active) {\n          if (app.ranked.betweenRounds) {\n            button.textContent = \"ATTENDI\";\n            button.disabled = true;\n            button.dataset.action = \"wait\";\n            return;\n          }\n          button.textContent = \"SKIP\";\n          button.dataset.action = \"skip\";\n          return;\n        }\n\n        if (app.ranked.complete) {\n          button.textContent = \"RIGIOCA\";\n          button.dataset.action = \"restart\";\n          return;\n        }\n\n        if (hasRankedBackend && !rankedConfig.isLoggedIn) {\n          button.textContent = \"ACCEDI\";\n          button.dataset.action = \"login\";\n          return;\n        }\n\n        button.textContent = \"INIZIA\";\n        button.dataset.action = \"start\";\n      }\n\n      function renderRankedSummary() {\n        elements.rankedSummaryPanel.classList.toggle(\"hidden\", !app.ranked.complete || !app.ranked.summaryLines.length);\n        elements.rankedSummaryPanel.classList.toggle(\"is-record\", app.ranked.isRecord);\n        elements.rankedSummaryTitle.textContent = app.ranked.summaryTitle || \"Partita conclusa\";\n        elements.rankedSummaryLines.innerHTML = \"\";\n\n        app.ranked.summaryLines.forEach((line) => {\n          const row = document.createElement(\"div\");\n          row.className = \"ranked-summary-line\";\n          row.innerHTML = line;\n          elements.rankedSummaryLines.appendChild(row);\n        });\n      }\n\n      function renderRankedResults() {\n        elements.rankedResultsList.innerHTML = \"\";\n        return;\n      }\n\n      function renderRankedBoard() {\n        const boardVisible = app.ranked.active || app.ranked.complete || app.ranked.betweenRounds;\n        elements.rankedBoardShell.classList.toggle(\"hidden\", !boardVisible);\n        elements.rankedBoardShell.classList.toggle(\"is-visible\", boardVisible);\n        renderRankedCenterCard();\n        renderRankedHints();\n      }\n\n      function renderRankedPanel() {\n        renderRankedMeta();\n        renderRankedAttempts();\n        renderRankedInputState();\n        renderRankedActionButton();\n        renderRankedSummary();\n        renderRankedBoard();\n        renderRankedResults();\n        hideRankedSuggestions();\n      }\n\n      function renderShell() {\n        renderBranding();\n        renderTabs();\n        renderPanels();\n\n        if (isRankedMode()) {\n          renderRankedPanel();\n          hideSuggestions();\n          syncHelpToggleState();\n          return;\n        }\n\n        renderAttempts();\n        renderActionSlot();\n        renderInputState();\n        renderBoard();\n        renderResults();\n        hideSuggestions();\n        hideRankedSuggestions();\n        syncHelpToggleState();\n      }\n\n      function setMessage(text, tone) {\n        if (messageTimeoutId) {\n          window.clearTimeout(messageTimeoutId);\n          messageTimeoutId = 0;\n        }\n\n        elements.message.className = \"message\";\n        if (text && tone) {\n          elements.message.textContent = text;\n          elements.message.classList.add(\"is-visible\", \"is-\" + tone);\n          if (tone !== \"success\" && tone !== \"error-final\") {\n            messageTimeoutId = window.setTimeout(function () {\n              elements.message.className = \"message\";\n              elements.message.textContent = \"\";\n              messageTimeoutId = 0;\n            }, 2500);\n          }\n          return;\n        }\n\n        elements.message.textContent = \"\";\n      }\n\n      function setRankedMessage(text, tone) {\n        if (rankedMessageTimeoutId) {\n          window.clearTimeout(rankedMessageTimeoutId);\n          rankedMessageTimeoutId = 0;\n        }\n\n        elements.rankedMessage.className = \"message\";\n        if (text && tone) {\n          elements.rankedMessage.textContent = text;\n          elements.rankedMessage.classList.add(\"is-visible\", \"is-\" + tone);\n          if (tone !== \"success\" && tone !== \"error-final\") {\n            rankedMessageTimeoutId = window.setTimeout(function () {\n              elements.rankedMessage.className = \"message\";\n              elements.rankedMessage.textContent = \"\";\n              rankedMessageTimeoutId = 0;\n            }, 2200);\n          }\n          return;\n        }\n\n        elements.rankedMessage.textContent = \"\";\n      }\n\n      function readLocalRankedBest() {\n        try {\n          return Number(window.localStorage.getItem(localRankedBestKey) || 0);\n        } catch (_) {\n          return 0;\n        }\n      }\n\n      function writeLocalRankedBest(score) {\n        const best = Math.max(readLocalRankedBest(), Number(score || 0));\n        try {\n          window.localStorage.setItem(localRankedBestKey, String(best));\n        } catch (_) {}\n        return best;\n      }\n\n      function saveDailyState() {\n        const state = app.modes.classic;\n        const payload = {\n          targetId: state.target.id,\n          attempts: state.attempts,\n          gameOver: state.complete,\n          revealedHints: state.revealedHints,\n          complete: state.complete,\n          status: state.status,\n          guessedIds: Array.from(state.guessedIds),\n          hints: serializeHints(state.hints)\n        };\n\n        try {\n          window.localStorage.setItem(dailyStorageKey, JSON.stringify(payload));\n        } catch (_) {}\n      }\n\n      function loadDailyState() {\n        try {\n          const raw = window.localStorage.getItem(dailyStorageKey);\n          if (!raw) return;\n          const saved = JSON.parse(raw);\n          const state = app.modes.classic;\n          if (!saved || Number(saved.targetId) !== state.target.id) {\n            try {\n              window.localStorage.removeItem(dailyStorageKey);\n            } catch (_) {}\n            return;\n          }\n\n          const restoredHints = restoreHints(saved.hints);\n          if (restoredHints) {\n            state.hints = restoredHints;\n          }\n          state.attempts = Number(saved.attempts || 0);\n          state.revealedHints = Math.max(1, Number(saved.revealedHints || 1));\n          state.complete = Boolean(saved.complete || saved.gameOver);\n          state.status = saved.status || \"playing\";\n          state.guessedIds = new Set((saved.guessedIds || []).map(Number));\n\n          if (state.status === \"won\") {\n            setMessage(\"Hai indovinato \" + state.target.name + \".\", \"success\");\n            syncStreakResult(\"won\");\n            return;\n          }\n\n          if (state.status === \"lost\") {\n            setMessage(\"Hai finito i tentativi. Era \" + state.target.name + \".\", \"error-final\");\n            syncStreakResult(\"lost\");\n            return;\n          }\n\n          setMessage(\"\", \"\");\n        } catch (_) {\n          try {\n            window.localStorage.removeItem(dailyStorageKey);\n          } catch (_) {}\n        }\n      }\n\n      function resetPracticeState() {\n        app.modes.practice = createGameState(pickRandomValidArtist());\n      }\n\n      function completeCurrentGame(status) {\n        const state = getCurrentState();\n        state.complete = true;\n        state.status = status;\n        state.revealedHints = 5;\n        renderShell();\n\n        if (app.mode === \"classic\") {\n          saveDailyState();\n          syncStreakResult(status === \"won\" ? \"won\" : \"lost\");\n        }\n      }\n\n      function makeGuess() {\n        const state = getCurrentState();\n        if (state.complete) return;\n\n        const guessArtist = findArtistByName(elements.input.value.trim());\n        if (!guessArtist) {\n          setMessage(\"Artista non trovato nella lista.\", \"error\");\n          return;\n        }\n\n        if (state.guessedIds.has(guessArtist.id)) {\n          setMessage(\"Hai gia provato questo artista.\", \"error\");\n          elements.input.value = \"\";\n          return;\n        }\n\n        state.guessedIds.add(guessArtist.id);\n        state.attempts += 1;\n        elements.input.value = \"\";\n        hideSuggestions();\n\n        if (guessArtist.id === state.target.id) {\n          setMessage(\"Hai indovinato \" + state.target.name + \".\", \"success\");\n          completeCurrentGame(\"won\");\n          return;\n        }\n\n        if (state.revealedHints < 5) {\n          state.revealedHints += 1;\n        }\n\n        if (state.attempts >= MAX_ATTEMPTS) {\n          setMessage(\"Hai finito i tentativi. Era \" + state.target.name + \".\", \"error-final\");\n          completeCurrentGame(\"lost\");\n          return;\n        }\n\n        renderShell();\n        if (app.mode === \"classic\") {\n          saveDailyState();\n        }\n      }\n\n      function showSuggestions() {\n        positionSuggestionsFor(elements.input, elements.suggestions);\n        elements.suggestions.style.display = \"block\";\n      }\n\n      function hideSuggestions() {\n        elements.suggestions.style.display = \"none\";\n      }\n\n      function showRankedSuggestions() {\n        positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n        elements.rankedSuggestions.style.display = \"block\";\n      }\n\n      function hideRankedSuggestions() {\n        elements.rankedSuggestions.style.display = \"none\";\n      }\n\n      function positionSuggestionsFor(inputElement, suggestionElement) {\n        const rect = inputElement.getBoundingClientRect();\n        const viewportPadding = 8;\n        const width = Math.max(240, rect.width);\n        const left = Math.min(\n          window.innerWidth - width - viewportPadding,\n          Math.max(viewportPadding, rect.left)\n        );\n        const viewportHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight;\n        const spaceBelow = viewportHeight - rect.bottom - viewportPadding;\n        const maxHeight = Math.max(140, Math.min(280, spaceBelow - 8));\n\n        suggestionElement.style.width = width + \"px\";\n        suggestionElement.style.left = left + \"px\";\n        suggestionElement.style.top = Math.max(viewportPadding, rect.bottom + 8) + \"px\";\n        suggestionElement.style.maxHeight = maxHeight + \"px\";\n      }\n\n      function updateSuggestions() {\n        const state = getCurrentState();\n        const value = normalize(elements.input.value);\n        elements.suggestions.innerHTML = \"\";\n\n        if (!value || state.complete) {\n          hideSuggestions();\n          return;\n        }\n\n        const matches = artists.filter((artist) => {\n          return normalize(artist.name).includes(value) && !state.guessedIds.has(artist.id);\n        }).slice(0, 8);\n\n        if (!matches.length) {\n          hideSuggestions();\n          return;\n        }\n\n        matches.forEach((artist) => {\n          const button = document.createElement(\"button\");\n          button.type = \"button\";\n          button.className = \"suggestion\";\n          const left = document.createElement(\"span\");\n          left.textContent = artist.name;\n          const right = document.createElement(\"small\");\n          right.textContent = artist.members || \"Artista\";\n          button.appendChild(left);\n          button.appendChild(right);\n          button.addEventListener(\"click\", function () {\n            elements.input.value = artist.name;\n            hideSuggestions();\n            elements.input.focus();\n          });\n          elements.suggestions.appendChild(button);\n        });\n\n        showSuggestions();\n      }\n\n      function updateRankedSuggestions() {\n        const value = normalize(elements.rankedInput.value);\n        elements.rankedSuggestions.innerHTML = \"\";\n\n        if (!value || !app.ranked.active || app.ranked.betweenRounds || !app.ranked.currentArtist) {\n          hideRankedSuggestions();\n          return;\n        }\n\n        const matches = artists.filter((artist) => {\n          return normalize(artist.name).includes(value) && !app.ranked.roundGuessedIds.has(artist.id);\n        }).slice(0, 8);\n\n        if (!matches.length) {\n          hideRankedSuggestions();\n          return;\n        }\n\n        matches.forEach((artist) => {\n          const button = document.createElement(\"button\");\n          button.type = \"button\";\n          button.className = \"suggestion\";\n          const left = document.createElement(\"span\");\n          left.textContent = artist.name;\n          const right = document.createElement(\"small\");\n          right.textContent = artist.members || \"Artista\";\n          button.appendChild(left);\n          button.appendChild(right);\n          button.addEventListener(\"click\", function () {\n            elements.rankedInput.value = artist.name;\n            hideRankedSuggestions();\n            elements.rankedInput.focus();\n          });\n          elements.rankedSuggestions.appendChild(button);\n        });\n\n        showRankedSuggestions();\n      }\n\n      async function postRankedAction(action, extraData) {\n        const body = new URLSearchParams({\n          action: action,\n          nonce: rankedConfig.nonce || \"\",\n          game_key: RANKED_GAME_KEY,\n          ...(extraData || {})\n        });\n\n        const response = await fetch(rankedConfig.ajaxUrl, {\n          method: \"POST\",\n          credentials: \"same-origin\",\n          headers: {\n            \"Content-Type\": \"application\/x-www-form-urlencoded; charset=UTF-8\"\n          },\n          body: body.toString()\n        });\n\n        if (!response.ok) {\n          throw new Error(\"Richiesta ranked non riuscita\");\n        }\n\n        return response.json();\n      }\n\n      function getRankedLoginUrl() {\n        return rankedConfig.loginUrl || guestLoginUrl;\n      }\n\n      function resetRankedState() {\n        const state = app.ranked;\n        state.active = false;\n        state.preparing = false;\n        state.submitting = false;\n        state.complete = false;\n        state.betweenRounds = false;\n        state.sessionToken = \"\";\n        state.currentArtist = null;\n        state.hints = [];\n        state.revealedHints = 1;\n        state.roundAttempts = 0;\n        state.roundGuessedIds = new Set();\n        state.usedTargetIds = new Set();\n        state.score = 0;\n        state.timeLeft = RANKED_INITIAL_TIME;\n        state.results = [];\n        state.summaryTitle = \"Partita conclusa\";\n        state.summaryLines = [];\n        state.isRecord = false;\n        state.lastRoundSolved = false;\n        window.clearInterval(state.timerId);\n        window.clearTimeout(state.roundTransitionId);\n        state.timerId = 0;\n        state.roundTransitionId = 0;\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n        setRankedMessage(\"\", \"\");\n      }\n\n      function startNextRankedArtist() {\n        if (!app.ranked.active) return;\n\n        window.clearTimeout(app.ranked.roundTransitionId);\n        app.ranked.betweenRounds = false;\n\n        if (app.ranked.usedTargetIds.size >= validArtists.length) {\n          app.ranked.usedTargetIds.clear();\n        }\n\n        app.ranked.currentArtist = pickRandomValidArtist(app.ranked.usedTargetIds);\n        app.ranked.usedTargetIds.add(app.ranked.currentArtist.id);\n        app.ranked.hints = buildHintSet(app.ranked.currentArtist);\n        app.ranked.revealedHints = 1;\n        app.ranked.roundAttempts = 0;\n        app.ranked.roundGuessedIds = new Set();\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n        setRankedMessage(\"\", \"\");\n        renderRankedPanel();\n        if (isRankedMode()) {\n          elements.rankedInput.focus();\n        }\n      }\n\n      function completeRankedRound(message, tone, label, solved) {\n        app.ranked.results.unshift({\n          artist: app.ranked.currentArtist,\n          label: label,\n          solved: solved,\n          revealedHints: app.ranked.revealedHints\n        });\n\n        app.ranked.lastRoundSolved = solved;\n        app.ranked.betweenRounds = true;\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n        renderRankedPanel();\n        setRankedMessage(message, tone);\n\n        app.ranked.roundTransitionId = window.setTimeout(function () {\n          if (!app.ranked.active || app.ranked.timeLeft <= 0) return;\n          startNextRankedArtist();\n        }, RANKED_ROUND_TRANSITION_MS);\n      }\n\n      function tickRanked() {\n        if (!app.ranked.active) return;\n        app.ranked.timeLeft -= 1;\n        renderRankedMeta();\n        if (app.ranked.timeLeft <= 0) {\n          finishRankedGame();\n        }\n      }\n\n      async function startRankedGame() {\n        if (app.ranked.active || app.ranked.preparing) return;\n\n        if (hasRankedBackend && !rankedConfig.isLoggedIn) {\n          window.location.href = getRankedLoginUrl();\n          return;\n        }\n\n        app.ranked.preparing = true;\n        app.ranked.complete = false;\n        app.ranked.summaryLines = [];\n        renderRankedActionButton();\n\n        try {\n          if (hasRankedBackend) {\n            const response = await postRankedAction(\"bulldogle_ranked_start\");\n            if (!response || !response.success || !response.data || !response.data.is_logged_in) {\n              window.location.href = getRankedLoginUrl();\n              return;\n            }\n            app.ranked.sessionToken = String(response.data.token || \"\");\n          } else {\n            app.ranked.sessionToken = \"demo-\" + String(Date.now());\n          }\n\n          window.clearInterval(app.ranked.timerId);\n          window.clearTimeout(app.ranked.roundTransitionId);\n          app.ranked.active = true;\n          app.ranked.complete = false;\n          app.ranked.betweenRounds = false;\n          app.ranked.submitting = false;\n          app.ranked.score = 0;\n          app.ranked.timeLeft = RANKED_INITIAL_TIME;\n          app.ranked.roundAttempts = 0;\n          app.ranked.roundGuessedIds = new Set();\n          app.ranked.usedTargetIds = new Set();\n          app.ranked.results = [];\n          app.ranked.summaryTitle = \"Partita conclusa\";\n          app.ranked.summaryLines = [];\n          app.ranked.isRecord = false;\n          app.ranked.lastRoundSolved = false;\n          setRankedMessage(\"\", \"\");\n          startNextRankedArtist();\n          app.ranked.timerId = window.setInterval(tickRanked, 1000);\n        } catch (_) {\n          app.ranked.active = false;\n          app.ranked.complete = false;\n          app.ranked.betweenRounds = false;\n          app.ranked.submitting = false;\n          app.ranked.currentArtist = null;\n          app.ranked.hints = [];\n          app.ranked.revealedHints = 1;\n          app.ranked.roundAttempts = 0;\n          app.ranked.roundGuessedIds = new Set();\n          app.ranked.usedTargetIds = new Set();\n          app.ranked.results = [];\n          window.clearInterval(app.ranked.timerId);\n          window.clearTimeout(app.ranked.roundTransitionId);\n          app.ranked.timerId = 0;\n          app.ranked.roundTransitionId = 0;\n          setRankedMessage(\"Non sono riuscito ad avviare la partita. Riprova tra poco.\", \"error\");\n        } finally {\n          app.ranked.preparing = false;\n          renderRankedPanel();\n        }\n      }\n\n      function submitRankedGuess() {\n        if (!app.ranked.active || app.ranked.betweenRounds || !app.ranked.currentArtist) return;\n\n        const guessArtist = findArtistByName(elements.rankedInput.value.trim());\n        if (!guessArtist) {\n          setRankedMessage(\"Artista non trovato nella lista.\", \"error\");\n          return;\n        }\n\n        if (app.ranked.roundGuessedIds.has(guessArtist.id)) {\n          setRankedMessage(\"Hai gia provato questo artista.\", \"error\");\n          elements.rankedInput.value = \"\";\n          return;\n        }\n\n        app.ranked.roundGuessedIds.add(guessArtist.id);\n        app.ranked.roundAttempts += 1;\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n\n        if (guessArtist.id === app.ranked.currentArtist.id) {\n          app.ranked.score += 1;\n          app.ranked.timeLeft += RANKED_CORRECT_BONUS;\n          renderRankedMeta();\n          setRankedMessage(\"Hai indovinato!\", \"success\");\n          completeRankedRound(\"Hai indovinato!\", \"success\", \"Hai indovinato\", true);\n          return;\n        }\n\n        if (app.ranked.revealedHints < 5) {\n          app.ranked.revealedHints += 1;\n        }\n\n        if (app.ranked.roundAttempts >= RANKED_ATTEMPTS) {\n          setRankedMessage(\"Hai finito i tentativi! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\");\n          completeRankedRound(\"Hai finito i tentativi! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\", \"Reveal del round\", false);\n          return;\n        }\n\n        renderRankedPanel();\n      }\n\n      function skipRankedArtist() {\n        if (!app.ranked.active || app.ranked.betweenRounds || !app.ranked.currentArtist) return;\n        app.ranked.timeLeft = Math.max(0, app.ranked.timeLeft - RANKED_SKIP_PENALTY);\n        renderRankedMeta();\n\n        if (app.ranked.timeLeft <= 0) {\n          finishRankedGame();\n          return;\n        }\n\n        setRankedMessage(\"Hai skippato! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\");\n        completeRankedRound(\"Hai skippato! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\", \"Skip\", false);\n      }\n\n      function escapeHtml(value) {\n        const div = document.createElement(\"div\");\n        div.textContent = value || \"\";\n        return div.innerHTML;\n      }\n\n      function buildRankedSummaryLines(data) {\n        const lines = [];\n        if (app.ranked.currentArtist && app.ranked.currentArtist.name) {\n          lines.push(\"L'ultimo artista era: <strong>\" + escapeHtml(app.ranked.currentArtist.name) + \"<\/strong>\");\n        }\n        lines.push(\"Punteggio finale: <strong>\" + String(app.ranked.score) + \"<\/strong>\");\n\n        if (data && typeof data.best_score !== \"undefined\") {\n          lines.push(\"Record mensile: <strong>\" + String(data.best_score) + \"<\/strong>\");\n          lines.push(\"Migliore posizione: <strong>\" + (data.best_rank ? \"#\" + data.best_rank : \"Fuori top 50\") + \"<\/strong>\");\n        } else {\n          const localBest = writeLocalRankedBest(app.ranked.score);\n          lines.push(\"Record demo: <strong>\" + String(localBest) + \"<\/strong>\");\n        }\n\n        return lines;\n      }\n\n      async function finishRankedGame() {\n        if (!app.ranked.active || app.ranked.submitting) return;\n\n        app.ranked.active = false;\n        app.ranked.complete = true;\n        app.ranked.betweenRounds = false;\n        app.ranked.submitting = true;\n        app.ranked.timeLeft = 0;\n        window.clearInterval(app.ranked.timerId);\n        window.clearTimeout(app.ranked.roundTransitionId);\n        app.ranked.timerId = 0;\n        app.ranked.roundTransitionId = 0;\n        hideRankedSuggestions();\n        setRankedMessage(\"\", \"\");\n        renderRankedMeta();\n        renderRankedInputState();\n        renderRankedActionButton();\n        app.ranked.summaryTitle = \"Partita conclusa\";\n        app.ranked.summaryLines = [\"Salvataggio record...\"];\n        app.ranked.isRecord = false;\n        renderRankedSummary();\n\n        try {\n          let data = null;\n          if (hasRankedBackend) {\n            const response = await postRankedAction(\"bulldogle_ranked_submit\", {\n              token: app.ranked.sessionToken,\n              score: String(app.ranked.score)\n            });\n            data = response && response.success ? response.data : null;\n          }\n\n          if (data) {\n            app.ranked.summaryTitle = data.is_record ? \"Nuovo record!\" : \"Partita conclusa\";\n            app.ranked.summaryLines = buildRankedSummaryLines(data);\n            app.ranked.isRecord = Boolean(data.is_record);\n          } else {\n            const previousBest = readLocalRankedBest();\n            const nextBest = Math.max(previousBest, app.ranked.score);\n            writeLocalRankedBest(nextBest);\n            app.ranked.summaryTitle = nextBest === app.ranked.score && app.ranked.score > previousBest ? \"Nuovo record!\" : \"Partita conclusa\";\n            app.ranked.summaryLines = buildRankedSummaryLines(null);\n            app.ranked.isRecord = app.ranked.score > previousBest;\n          }\n        } catch (_) {\n          const previousBest = readLocalRankedBest();\n          const nextBest = Math.max(previousBest, app.ranked.score);\n          writeLocalRankedBest(nextBest);\n          app.ranked.summaryTitle = \"Partita conclusa\";\n          app.ranked.summaryLines = buildRankedSummaryLines(null);\n          app.ranked.isRecord = app.ranked.score > previousBest;\n        } finally {\n          app.ranked.submitting = false;\n          renderRankedPanel();\n        }\n      }\n\n      function handleRankedSideAction() {\n        const action = elements.rankedSideActionButton.dataset.action;\n\n        if (action === \"login\") {\n          window.location.href = getRankedLoginUrl();\n          return;\n        }\n\n        if (action === \"start\" || action === \"restart\") {\n          startRankedGame();\n          return;\n        }\n\n        if (action === \"skip\") {\n          skipRankedArtist();\n        }\n      }\n\n      function bindTouchAction(node, handler) {\n        if (!node) return;\n\n        let touchHandled = false;\n\n        node.addEventListener(\"touchend\", function (event) {\n          if (node.disabled) return;\n          event.preventDefault();\n          touchHandled = true;\n          handler();\n          window.setTimeout(function () {\n            touchHandled = false;\n          }, 350);\n        }, { passive: false });\n\n        node.addEventListener(\"click\", function (event) {\n          if (node.disabled) return;\n          if (touchHandled) {\n            event.preventDefault();\n            return;\n          }\n          handler();\n        });\n      }\n\n      function renderStreakGuestState() {\n        elements.dailyStreakCard.classList.add(\"is-guest\");\n        elements.dailyStreakCard.href = guestLoginUrl;\n        elements.dailyStreakCard.setAttribute(\"aria-label\", \"Accedi per salvare la streak\");\n        elements.dailyStreakMain.textContent = \"STREAK\";\n        elements.dailyStreakSub.textContent = \"Accedi per salvarla\";\n      }\n\n      function renderStreakLoadingState() {\n        elements.dailyStreakCard.classList.remove(\"is-guest\");\n        elements.dailyStreakCard.removeAttribute(\"href\");\n        elements.dailyStreakMain.textContent = \"...\";\n        elements.dailyStreakSub.textContent = \"Caricamento streak\";\n      }\n\n      function renderStreakState(data) {\n        if (!data || !data.is_logged_in) {\n          renderStreakGuestState();\n          return;\n        }\n\n        elements.dailyStreakCard.classList.remove(\"is-guest\");\n        elements.dailyStreakCard.removeAttribute(\"href\");\n        const streakValue = Number(data.current_streak || 0);\n        elements.dailyStreakMain.textContent = streakValue + \" \" + (streakValue === 1 ? \"GIORNO\" : \"GIORNI\");\n\n        if (data.today_result === \"won\") {\n          elements.dailyStreakSub.textContent = \"Indovinata oggi \u2022 Record \" + (data.best_streak || data.current_streak || 0);\n        } else if (data.today_result === \"lost\") {\n          elements.dailyStreakSub.textContent = \"Interrotta oggi \u2022 Record \" + (data.best_streak || 0);\n        } else {\n          elements.dailyStreakSub.textContent = \"Record \" + (data.best_streak || data.current_streak || 0);\n        }\n      }\n\n      async function postStreakAction(action, extraData) {\n        const ajaxUrl = featConfig.ajaxUrl;\n        if (!ajaxUrl) {\n          throw new Error(\"Config streak WordPress non trovata\");\n        }\n\n        const body = new URLSearchParams({\n          action: action,\n          nonce: featConfig.nonce || \"\",\n          ...(extraData || {})\n        });\n\n        const response = await fetch(ajaxUrl, {\n          method: \"POST\",\n          credentials: \"same-origin\",\n          headers: {\n            \"Content-Type\": \"application\/x-www-form-urlencoded; charset=UTF-8\"\n          },\n          body: body.toString()\n        });\n\n        if (!response.ok) {\n          throw new Error(\"Richiesta streak non riuscita\");\n        }\n\n        return response.json();\n      }\n\n      async function loadStreakStatus() {\n        if (!featConfig.isLoggedIn) {\n          renderStreakGuestState();\n          return;\n        }\n\n        if (streakLoading) return;\n        streakLoading = true;\n        renderStreakLoadingState();\n\n        try {\n          const response = await postStreakAction(\"bulldogle_feat_streak_status\");\n          if (response && response.success) {\n            renderStreakState(response.data);\n          } else {\n            renderStreakGuestState();\n          }\n        } catch (_) {\n          renderStreakGuestState();\n        } finally {\n          streakLoading = false;\n        }\n      }\n\n      async function syncStreakResult(result) {\n        if (!featConfig.isLoggedIn) return;\n        try {\n          const response = await postStreakAction(\"bulldogle_feat_streak_update\", {\n            result: result,\n            day_key: italyDateInfo.dayKey\n          });\n\n          if (response && response.success) {\n            renderStreakState(response.data);\n          }\n        } catch (_) {}\n      }\n\n      function switchMode(nextMode) {\n        if (nextMode === app.mode) return;\n        if (app.mode === \"ranked\" && nextMode !== \"ranked\") {\n          resetRankedState();\n        }\n        app.mode = nextMode;\n        setMessage(\"\", \"\");\n        setRankedMessage(\"\", \"\");\n        hideSuggestions();\n        hideRankedSuggestions();\n        closeAllHelpPanels();\n        renderShell();\n        if (app.mode === \"classic\") {\n          loadStreakStatus();\n        }\n      }\n\n      elements.tabs.forEach((tab) => {\n        tab.addEventListener(\"click\", function () {\n          switchMode(tab.dataset.mode);\n        });\n      });\n\n      if (elements.rankedModeButton) {\n        elements.rankedModeButton.addEventListener(\"click\", function () {\n          switchMode(\"ranked\");\n        });\n      }\n\n      elements.helpToggle.addEventListener(\"click\", function () {\n        const panel = getCurrentHelpPanel();\n        if (!panel) return;\n\n        const shouldOpen = !panel.classList.contains(\"is-open\");\n        closeAllHelpPanels();\n\n        if (shouldOpen) {\n          panel.classList.add(\"is-open\");\n          panel.setAttribute(\"aria-hidden\", \"false\");\n        }\n\n        syncHelpToggleState();\n      });\n\n      elements.guessForm.addEventListener(\"submit\", function (event) {\n        event.preventDefault();\n        makeGuess();\n      });\n\n      elements.rankedGuessForm.addEventListener(\"submit\", function (event) {\n        event.preventDefault();\n        submitRankedGuess();\n        renderRankedPanel();\n      });\n\n      elements.modeActionButton.addEventListener(\"click\", function () {\n        if (app.mode !== \"practice\") return;\n        resetPracticeState();\n        setMessage(\"\", \"\");\n        hideSuggestions();\n        renderShell();\n      });\n\n      bindTouchAction(elements.rankedSideActionButton, handleRankedSideAction);\n\n      elements.input.addEventListener(\"input\", updateSuggestions);\n      elements.input.addEventListener(\"focus\", updateSuggestions);\n      elements.rankedInput.addEventListener(\"input\", updateRankedSuggestions);\n      elements.rankedInput.addEventListener(\"focus\", updateRankedSuggestions);\n\n      document.addEventListener(\"click\", function (event) {\n        if (!elements.suggestions.contains(event.target) && event.target !== elements.input) {\n          hideSuggestions();\n        }\n\n        if (!elements.rankedSuggestions.contains(event.target) && event.target !== elements.rankedInput) {\n          hideRankedSuggestions();\n        }\n      });\n\n      window.addEventListener(\"resize\", function () {\n        syncHelpPanelPlacement();\n        if (elements.suggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.input, elements.suggestions);\n        }\n        if (elements.rankedSuggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n        }\n      });\n\n      window.addEventListener(\"scroll\", function () {\n        if (elements.suggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.input, elements.suggestions);\n        }\n        if (elements.rankedSuggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n        }\n      }, true);\n\n      if (window.visualViewport) {\n        window.visualViewport.addEventListener(\"resize\", function () {\n          syncHelpPanelPlacement();\n          if (elements.suggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.input, elements.suggestions);\n          }\n          if (elements.rankedSuggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n          }\n        });\n\n        window.visualViewport.addEventListener(\"scroll\", function () {\n          if (elements.suggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.input, elements.suggestions);\n          }\n          if (elements.rankedSuggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n          }\n        });\n      }\n\n      loadDailyState();\n      syncHelpPanelPlacement();\n      renderShell();\n      loadStreakStatus();\n    })();\n  <\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5e400047 crew elementor-widget__width-initial e-transform elementor-widget elementor-widget-post-widget\" data-id=\"5e400047\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;posts_per_page&quot;:100,&quot;post_type&quot;:[&quot;page&quot;],&quot;nb_columns&quot;:&quot;1&quot;,&quot;_transform_translateX_effect&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:4,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_tablet&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_mobile&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:3,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_tablet&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_mobile&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_layout&quot;:&quot;grid&quot;,&quot;nb_columns_tablet&quot;:&quot;3&quot;,&quot;nb_columns_mobile&quot;:&quot;1&quot;,&quot;post_status&quot;:&quot;publish&quot;,&quot;pagination&quot;:&quot;none&quot;}\" data-widget_type=\"post-widget.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"post-container none classic\" data-total-post=\"2\" ><div class=\"post-container-inner\"><div class=\"elementor-grid\" ><article class=\"post-wrapper\"  data-post-id=\"8209\" ><div class=\"post-image\"><a href=\"https:\/\/bulldogmusik.it\/en\/bulldogmatch-ita\/\" ><img loading=\"lazy\" decoding=\"async\" width=\"1366\" height=\"768\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogMatch-New.png\" class=\"bpfwe-post-thumbnail\" alt=\"\" data-bpfwe-src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogMatch-New.png\" loading=\"lazy\" \/><\/a><\/div><div class=\"inner-content\"><div class=\"post-content elementor-repeater-item-aff2fa8\"><p>Indovina in rapper in meno di 20 tentativi, ogni tentativo scopri diverse affinit\u00e0....<\/p><\/div><\/div><\/article><article class=\"post-wrapper\"  data-post-id=\"7057\" ><div class=\"post-image\"><a href=\"https:\/\/bulldogmusik.it\/en\/bulldogle-rap-ita\/\" ><img loading=\"lazy\" decoding=\"async\" width=\"1366\" height=\"768\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Bulldogle-Classico-New.png\" class=\"bpfwe-post-thumbnail\" alt=\"\" data-bpfwe-src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Bulldogle-Classico-New.png\" loading=\"lazy\" \/><\/a><\/div><div class=\"inner-content\"><div class=\"post-content elementor-repeater-item-aff2fa8\"><p>Indovina il rapper in meno di 10 tentativi, ogni tentativo scopri nuove informazioni...<\/p><\/div><\/div><\/article><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div id=\"e-n-tab-content-16973812872\" role=\"tabpanel\" aria-labelledby=\"tab-speciale\" data-tab-index=\"2\" style=\"--n-tabs-title-order: 2;\" class=\" elementor-element elementor-element-24466b1e e-con-full e-flex wcf-starter-animations-none e-con e-child\" data-id=\"24466b1e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1346eb5d e-grid e-con-boxed wcf-starter-animations-none e-con e-child\" data-id=\"1346eb5d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ba31624 elementor-widget__width-initial e-transform elementor-widget elementor-widget-html\" data-id=\"4ba31624\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_translateX_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:-4,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"it\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>BulldogFeat Ranked Demo<\/title>\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Instrument+Sans:wght@400;500;600;700;800&family=Space+Grotesk:wght@500;700&display=swap\" rel=\"stylesheet\">\n  <style>\n    :root {\n      --bg: #000;\n      --panel: #070707;\n      --panel-2: #0b0b0b;\n      --line: rgba(255, 255, 255, 0.08);\n      --line-faint: rgba(255, 255, 255, 0.05);\n      --ranked-accent-rgb: 149, 40, 0;\n      --line-strong: rgba(var(--ranked-accent-rgb), 0.28);\n      --white: #f7f4ef;\n      --copy: rgba(247, 244, 239, 0.76);\n      --copy-soft: rgba(247, 244, 239, 0.56);\n      --copy-faint: rgba(247, 244, 239, 0.34);\n      --accent: #952800;\n      --success: #7dc56a;\n      --danger: #952800;\n      --ease: 220ms cubic-bezier(.2,.9,.2,1);\n    }\n\n    * { box-sizing: border-box; }\n\n    html,\n    body {\n      margin: 0;\n      min-height: 100%;\n      background: var(--bg);\n      color: var(--white);\n      font-family: \"Instrument Sans\", system-ui, sans-serif;\n      overflow-x: hidden;\n    }\n\n    button,\n    input,\n    iframe {\n      font: inherit;\n    }\n\n    .ranked-demo-app {\n      width: min(760px, calc(100vw - 20px));\n      margin: 0 auto;\n      padding: 18px 0 24px;\n    }\n\n    .app-shell {\n      position: relative;\n      isolation: isolate;\n      padding: 14px;\n      border: 1px solid var(--line);\n      border-radius: 22px;\n      background: linear-gradient(180deg, rgba(14, 14, 14, 0.98), rgba(7, 7, 7, 0.98));\n      overflow: visible;\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n    }\n\n    .app-shell::after {\n      content: \"\";\n      position: absolute;\n      inset: 0;\n      border-radius: inherit;\n      background-image: url(\"data:image\/svg+xml,%3Csvg%20xmlns='http:\/\/www.w3.org\/2000\/svg'%20viewBox='0%200%20180%20180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='.9'%20numOctaves='3'%20stitchTiles='stitch'\/%3E%3CfeColorMatrix%20type='saturate'%20values='0'\/%3E%3CfeComponentTransfer%3E%3CfeFuncA%20type='table'%20tableValues='0%20.58'\/%3E%3C\/feComponentTransfer%3E%3C\/filter%3E%3Crect%20width='180'%20height='180'%20filter='url(%23n)'%20opacity='1'\/%3E%3C\/svg%3E\");\n      background-size: 180px 180px;\n      mix-blend-mode: overlay;\n      opacity: 0.1;\n      pointer-events: none;\n    }\n\n    .app-shell > * {\n      position: relative;\n      z-index: 1;\n    }\n\n    .topbar {\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      gap: 0;\n      padding: 10px 8px 14px;\n    }\n\n    .top-logo {\n      display: block;\n      width: min(320px, 58vw);\n      height: auto;\n    }\n\n    .shell {\n      margin-top: 0;\n      padding-top: 14px;\n      border-top: 1px solid var(--line);\n    }\n\n    .game-shell {\n      position: relative;\n      padding: 2px 0 6px;\n      overflow: visible;\n    }\n\n    .meta-grid {\n      display: grid;\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 10px;\n      margin-bottom: 12px;\n    }\n\n    @media (min-width: 721px) {\n      .meta-grid {\n        padding-bottom: 14px;\n        border-bottom: 1px solid var(--line);\n      }\n\n      #helpPanel {\n        border-bottom-color: transparent;\n      }\n\n      #helpPanel.is-open {\n        border-bottom-color: var(--line);\n      }\n    }\n\n    .meta-card {\n      min-height: 74px;\n      padding: 12px 14px;\n      border: 1px solid var(--line);\n      border-radius: 16px;\n      background: rgba(255, 255, 255, 0.03);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      gap: 8px;\n      text-align: left;\n    }\n\n    .meta-card.is-accent {\n      border-color: rgba(var(--ranked-accent-rgb), 0.24);\n      background: rgba(var(--ranked-accent-rgb), 0.08);\n    }\n\n    .meta-button {\n      width: 100%;\n      min-height: 74px;\n      padding: 12px 14px;\n      border: 1px solid var(--line);\n      border-radius: 16px;\n      background: rgba(255, 255, 255, 0.03);\n      color: var(--white);\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      text-align: center;\n      font-size: 14px;\n      font-weight: 700;\n      cursor: pointer;\n      transition: transform var(--ease), border-color var(--ease), background var(--ease), color var(--ease);\n    }\n\n    .meta-button.is-active {\n      border-color: var(--line-strong);\n      background: rgba(var(--ranked-accent-rgb), 0.12);\n    }\n\n    .meta-button:hover {\n      transform: translateY(-1px);\n    }\n\n    .ranked-demo-app.is-ranked-mode .hide-when-ranked,\n    body.bulldogfeat-ranked-mode-active .hide-when-ranked,\n    html.bulldogfeat-ranked-mode-active .hide-when-ranked,\n    .ranked-demo-app.is-ranked-mode .hide.when.ranked,\n    body.bulldogfeat-ranked-mode-active .hide.when.ranked,\n    html.bulldogfeat-ranked-mode-active .hide.when.ranked {\n      display: none !important;\n    }\n\n    .show-when-ranked,\n    .show.when.ranked,\n    .show-when-ranked-flex,\n    .show.flex.when.ranked,\n    .show-when-ranked-grid,\n    .show.grid.when.ranked,\n    .show-when-ranked-inline {\n      display: none !important;\n    }\n\n    .ranked-demo-app.is-ranked-mode .show-when-ranked,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked,\n    .ranked-demo-app.is-ranked-mode .show.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.when.ranked {\n      display: block !important;\n    }\n\n    .ranked-demo-app.is-ranked-mode .show-when-ranked-flex,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-flex,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-flex,\n    .ranked-demo-app.is-ranked-mode .show.flex.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.flex.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.flex.when.ranked {\n      display: flex !important;\n    }\n\n    .ranked-demo-app.is-ranked-mode .show-when-ranked-grid,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-grid,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-grid,\n    .ranked-demo-app.is-ranked-mode .show.grid.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.grid.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.grid.when.ranked {\n      display: grid !important;\n    }\n\n    .ranked-demo-app.is-ranked-mode .show-when-ranked-inline,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-inline,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-inline {\n      display: inline-flex !important;\n    }\n\n    .meta-label {\n      display: block;\n      color: var(--copy-soft);\n      font-size: 11px;\n      font-weight: 800;\n      letter-spacing: 0.12em;\n      text-transform: uppercase;\n    }\n\n    .meta-value {\n      display: block;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(24px, 3.2vw, 30px);\n      line-height: 1;\n      letter-spacing: -0.05em;\n    }\n\n    .help-panel {\n      max-height: 0;\n      overflow: hidden;\n      padding-bottom: 0;\n      border-bottom: 1px solid var(--line);\n      transition: max-height 240ms ease, margin 240ms ease, padding-bottom 240ms ease, border-color 240ms ease;\n      margin: 0 0 12px;\n    }\n\n    .help-panel.is-open {\n      max-height: 1200px;\n      padding-bottom: 12px;\n      margin: 0 0 12px;\n    }\n\n    .help-grid {\n      display: grid;\n      grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n      gap: 10px;\n    }\n\n    .help-card {\n      min-height: 100%;\n      padding: 12px 13px;\n      border: 1px solid var(--line);\n      border-radius: 12px;\n      background: rgba(255, 255, 255, 0.03);\n    }\n\n    .help-card strong {\n      display: block;\n      margin-bottom: 8px;\n      font-size: 13px;\n    }\n\n    .help-card span {\n      display: block;\n      color: var(--copy-soft);\n      font-size: 12px;\n      line-height: 1.45;\n    }\n\n    .feat-board-shell {\n      width: 100%;\n      display: flex;\n      justify-content: center;\n      padding: 2px 0 4px;\n    }\n\n    .feat-board-shell.hidden {\n      display: none !important;\n    }\n\n    #rankedBoardShell {\n      display: none;\n    }\n\n    #rankedBoardShell.is-visible {\n      display: flex !important;\n    }\n\n    .feat-circle {\n      position: relative;\n      width: 320px;\n      height: 320px;\n    }\n\n    .feat-center-slot {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      transform: translate(-50%, -62%);\n      z-index: 10;\n    }\n\n    .feat-hint-slot {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      width: 76px;\n      height: 76px;\n      margin-left: -38px;\n      margin-top: -38px;\n      transition: transform 360ms cubic-bezier(.22,1,.36,1), opacity 220ms ease;\n    }\n\n    .feat-node {\n      width: 100%;\n      height: 100%;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      gap: 5px;\n      padding: 8px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      border-radius: 18px;\n      background: rgba(255, 255, 255, 0.04);\n      text-align: center;\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n    }\n\n    .feat-node.is-center {\n      width: 92px;\n      height: 92px;\n      padding: 10px;\n      border-radius: 24px;\n      background: rgba(255, 255, 255, 0.05);\n      border-color: rgba(255, 255, 255, 0.12);\n    }\n\n    .feat-node.is-center.is-won {\n      border-color: rgba(125, 197, 106, 0.42);\n    }\n\n    .feat-node.is-center.is-lost {\n      border-color: rgba(255, 155, 98, 0.42);\n    }\n\n    .feat-node.is-important {\n      border-color: rgba(149, 40, 0, 0.32);\n      background: rgba(149, 40, 0, 0.09);\n    }\n\n    .feat-avatar {\n      width: 34px;\n      height: 34px;\n      flex: 0 0 34px;\n      aspect-ratio: 1 \/ 1;\n      border-radius: 50%;\n      overflow: hidden;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background:\n        radial-gradient(circle at 32% 28%, rgba(149, 40, 0, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(149, 40, 0, 0.16), rgba(255, 255, 255, 0.03));\n      color: var(--white);\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: 14px;\n      font-weight: 700;\n      letter-spacing: -0.04em;\n      text-transform: uppercase;\n    }\n\n    .feat-avatar img {\n      width: 100%;\n      height: 100%;\n      object-fit: cover;\n      display: block;\n    }\n\n    .feat-avatar.is-mystery {\n      font-size: 18px;\n      background: rgba(255, 255, 255, 0.08);\n    }\n\n    .feat-node.is-center .feat-avatar {\n      width: 40px;\n      height: 40px;\n      flex-basis: 40px;\n      font-size: 16px;\n    }\n\n    .feat-label {\n      max-width: 100%;\n      color: var(--white);\n      font-size: 9px;\n      line-height: 1.15;\n      font-weight: 700;\n      text-align: center;\n      white-space: nowrap;\n      overflow: hidden;\n      text-overflow: ellipsis;\n    }\n\n    .feat-node.is-center .feat-label {\n      font-size: 10px;\n    }\n\n    .feat-node.is-center .feat-label,\n    .feat-node.is-center .feat-index {\n      white-space: normal;\n      overflow: visible;\n      text-overflow: clip;\n      max-width: 100%;\n      word-break: break-word;\n      overflow-wrap: anywhere;\n    }\n\n    .feat-index {\n      color: var(--copy-soft);\n      font-size: 8px;\n      line-height: 1;\n      font-weight: 700;\n    }\n\n    .input-grid {\n      display: grid;\n      grid-template-columns: 152px minmax(0, 1fr) 152px 152px;\n      gap: 10px;\n      align-items: stretch;\n      width: 100%;\n      margin: 0 auto;\n    }\n\n    .attempts-card,\n    .button,\n    .secondary-button {\n      min-width: 152px;\n      min-height: 56px;\n      height: 56px;\n      padding: 0 22px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1;\n      font-weight: 700;\n      letter-spacing: 0;\n      text-transform: uppercase;\n    }\n\n    .attempts-card {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      border: 1px solid #fff;\n      background: #fff;\n      color: #111;\n      text-align: center;\n      white-space: nowrap;\n    }\n\n    .action-slot {\n      width: 152px;\n      min-width: 152px;\n      align-self: stretch;\n    }\n\n    .button,\n    .secondary-button {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      border: 1px solid var(--line);\n      cursor: pointer;\n      transition: transform var(--ease), border-color var(--ease), background var(--ease), color var(--ease), opacity var(--ease);\n    }\n\n    .button,\n    .secondary-button.is-primary {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #111;\n    }\n\n    #submitButton.button,\n    #sideActionButton.secondary-button.is-primary {\n      background: #952800 !important;\n      border-color: #952800 !important;\n      color: #111 !important;\n    }\n\n    .secondary-button.is-muted {\n      background: rgba(255, 255, 255, 0.03);\n      border-color: var(--line);\n      color: var(--white);\n    }\n\n    .button:hover,\n    .secondary-button:hover {\n      transform: translateY(-1px);\n      background: #fff;\n      border-color: #fff;\n      color: #111;\n    }\n\n    #submitButton.button:hover,\n    #sideActionButton.secondary-button.is-primary:hover {\n      background: #fff !important;\n      border-color: #fff !important;\n      color: #111 !important;\n    }\n\n    .input-grid .action-slot,\n    .input-grid .button,\n    .input-grid .secondary-button {\n      position: relative;\n      z-index: 8;\n      pointer-events: auto;\n      touch-action: manipulation;\n    }\n\n    .button:disabled,\n    .secondary-button:disabled {\n      cursor: not-allowed;\n      opacity: 0.45;\n      transform: none;\n    }\n\n    .input-shell {\n      position: relative;\n      z-index: 5;\n      min-width: 0;\n      border: 2px solid #080808;\n      border-radius: 0;\n      background: #101010;\n      overflow: hidden;\n    }\n\n    .search-field {\n      width: 100%;\n      min-height: 56px;\n      height: 56px;\n      padding: 0 18px;\n      border: 0;\n      border-radius: 0;\n      background: transparent;\n      color: var(--white);\n      font-size: 15px;\n      outline: none;\n      box-shadow: none;\n      transition: none;\n      appearance: none;\n      -webkit-appearance: none;\n    }\n\n    .search-field:focus {\n      background: transparent;\n      box-shadow: none;\n    }\n\n    .search-field::placeholder {\n      color: rgba(247, 244, 239, 0.18);\n      opacity: 1;\n    }\n\n    .search-field:disabled {\n      opacity: 1;\n      cursor: not-allowed;\n      color: rgba(247, 244, 239, 0.26);\n    }\n\n    .suggestions {\n      position: fixed;\n      top: 0;\n      left: 0;\n      width: 280px;\n      max-height: min(280px, calc(100dvh - 24px));\n      overflow-y: auto;\n      z-index: 2147483001;\n      display: none;\n      padding: 6px;\n      border: 1px solid var(--line);\n      border-radius: 14px;\n      background: rgba(9, 9, 9, 0.98);\n      box-shadow: 0 22px 50px rgba(0, 0, 0, 0.55);\n      backdrop-filter: blur(12px);\n    }\n\n    .suggestion {\n      width: 100%;\n      display: flex;\n      justify-content: space-between;\n      gap: 8px;\n      padding: 11px 12px;\n      border: 0;\n      border-radius: 10px;\n      background: transparent;\n      color: var(--white);\n      text-align: left;\n      cursor: pointer;\n      transition: transform var(--ease), background var(--ease);\n    }\n\n    .suggestion small {\n      color: var(--copy-faint);\n      font-size: 11px;\n    }\n\n    .suggestion:hover {\n      transform: translateY(-1px);\n    }\n\n    .message {\n      display: none;\n      width: 100%;\n      margin: 0;\n      padding: 10px 12px;\n      border-radius: 999px;\n      border: 1px solid var(--line);\n      background: rgba(255, 255, 255, 0.03);\n      color: var(--copy);\n      font-size: 13px;\n      line-height: 1.45;\n      text-align: center;\n    }\n\n    .message.is-visible {\n      display: block;\n    }\n\n    .message.is-success {\n      border-color: rgba(125, 197, 106, 0.36);\n      background: rgba(125, 197, 106, 0.1);\n      color: #daf2d3;\n    }\n\n    .message.is-error,\n    .message.is-error-final {\n      border-color: rgba(149, 40, 0, 0.32);\n      background: rgba(149, 40, 0, 0.1);\n      color: #ffd7b5;\n    }\n\n    .summary-panel {\n      margin-top: 0;\n      padding: 16px;\n      border: 1px solid rgba(149, 40, 0, 0.28);\n      border-radius: 18px;\n      background: rgba(149, 40, 0, 0.08);\n    }\n\n    .summary-panel.hidden {\n      display: none;\n    }\n\n    .summary-panel.is-record {\n      border-color: rgba(125, 197, 106, 0.32);\n      background: rgba(125, 197, 106, 0.08);\n    }\n\n    .summary-title {\n      margin: 0 0 10px;\n      color: #fff;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(22px, 4vw, 28px);\n      line-height: 1;\n      letter-spacing: -0.04em;\n      font-weight: 800;\n    }\n\n    .summary-lines {\n      display: grid;\n      gap: 5px;\n    }\n\n    .summary-line {\n      color: var(--white);\n      font-size: 14px;\n      line-height: 1.5;\n      font-weight: 600;\n    }\n\n    .summary-line strong {\n      font-weight: 800;\n    }\n\n    .results-list {\n      display: grid;\n      gap: 12px;\n      margin-top: 0;\n      width: 100%;\n    }\n\n    .empty-state {\n      padding: 16px;\n      border: 1px dashed rgba(255, 255, 255, 0.15);\n      border-radius: 12px;\n      color: var(--copy-soft);\n      font-size: 13px;\n      line-height: 1.5;\n      text-align: center;\n    }\n\n    .answer-card {\n      padding: 18px;\n      border: 1px solid var(--line-faint);\n      border-radius: 22px;\n      background: linear-gradient(180deg, rgba(14, 14, 14, 0.96), rgba(10, 10, 10, 0.96));\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n      text-align: left;\n    }\n\n    .answer-card.is-correct {\n      border-color: rgba(125, 197, 106, 0.34);\n    }\n\n    .answer-card-head {\n      display: grid;\n      grid-template-columns: 92px minmax(0, 1fr);\n      gap: 16px;\n      align-items: center;\n      margin-bottom: 14px;\n    }\n\n    .answer-cover {\n      position: relative;\n      width: 92px;\n      height: 92px;\n      border: 1px solid rgba(255, 255, 255, 0.12);\n      border-radius: 50%;\n      background:\n        radial-gradient(circle at 32% 28%, rgba(149, 40, 0, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(149, 40, 0, 0.16), rgba(255, 255, 255, 0.03));\n      overflow: hidden;\n      box-shadow: 0 18px 34px rgba(0, 0, 0, 0.34);\n    }\n\n    .answer-cover img {\n      width: 100%;\n      height: 100%;\n      object-fit: cover;\n      display: block;\n    }\n\n    .answer-cover-fallback {\n      width: 100%;\n      height: 100%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      color: var(--white);\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: 28px;\n      font-weight: 700;\n      letter-spacing: -0.04em;\n      text-transform: uppercase;\n    }\n\n    .answer-copy {\n      min-width: 0;\n      display: flex;\n      flex-direction: column;\n      gap: 10px;\n      align-items: flex-start;\n    }\n\n    .answer-badge {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      min-height: 28px;\n      padding: 0 12px;\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      color: var(--copy-soft);\n      font-size: 11px;\n      font-weight: 700;\n    }\n\n    .answer-name {\n      margin: 0;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(28px, 4vw, 34px);\n      line-height: 1;\n      letter-spacing: -0.04em;\n    }\n\n    .answer-sub {\n      margin: -2px 0 0;\n      color: var(--copy-soft);\n      font-size: 12px;\n      line-height: 1.45;\n    }\n\n    .answer-stats {\n      display: grid;\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 8px;\n    }\n\n    .answer-stat {\n      min-height: 90px;\n      padding: 12px 10px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      border-radius: 14px;\n      background: rgba(255, 255, 255, 0.04);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      align-items: center;\n      text-align: center;\n    }\n\n    .answer-stat-label {\n      display: block;\n      color: var(--white);\n      opacity: 0.92;\n      font-size: 12px;\n      font-weight: 700;\n    }\n\n    .answer-stat-value {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      font-size: clamp(15px, 1.8vw, 18px);\n      line-height: 1.06;\n      font-weight: 800;\n      letter-spacing: -0.03em;\n      text-align: center;\n    }\n\n    .hidden {\n      display: none !important;\n    }\n\n    @media (max-width: 720px) {\n      .ranked-demo-app {\n        width: 100%;\n        max-width: 100%;\n        padding: max(6px, env(safe-area-inset-top, 0px)) 4px calc(10px + env(safe-area-inset-bottom, 0px));\n      }\n\n      .app-shell {\n        padding: 8px 6px 10px;\n        border: 0;\n        border-radius: 0;\n        background: transparent;\n        box-shadow: none;\n      }\n\n      .app-shell::after {\n        display: none;\n      }\n\n      .topbar {\n        padding: 12px 4px 10px;\n      }\n\n      .top-logo {\n        width: min(260px, 66vw);\n      }\n\n      .shell {\n        padding-top: 8px;\n      }\n\n      .meta-grid {\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n      }\n\n      .meta-grid > :last-child {\n        grid-column: 1 \/ -1;\n      }\n\n      .input-grid {\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n        gap: 8px;\n      }\n\n      .input-shell {\n        grid-column: 1 \/ -1;\n        order: 3;\n      }\n\n      .attempts-card {\n        order: 1;\n      }\n\n      .action-slot {\n        order: 2;\n        width: auto;\n        min-width: 0;\n      }\n\n      .input-grid > .button {\n        order: 4;\n        grid-column: 1 \/ -1;\n      }\n\n      .action-slot,\n      .attempts-card,\n      .button,\n      .secondary-button,\n      .search-field {\n        min-height: 48px;\n        height: 48px;\n      }\n\n      .search-field {\n        font-size: 16px;\n      }\n\n      .feat-circle {\n        width: 284px;\n        height: 284px;\n      }\n\n      .feat-hint-slot {\n        width: 68px;\n        height: 68px;\n        margin-left: -34px;\n        margin-top: -34px;\n      }\n\n      .feat-node.is-center {\n        width: 84px;\n        height: 84px;\n        padding: 8px 6px;\n        gap: 4px;\n      }\n\n      .feat-node.is-center .feat-label {\n        font-size: 9px;\n        line-height: 1.05;\n      }\n\n      .feat-node.is-center .feat-index {\n        font-size: 7px;\n      }\n\n      .answer-card {\n        padding: 12px;\n        border-radius: 16px;\n      }\n\n      .answer-card-head {\n        grid-template-columns: 72px minmax(0, 1fr);\n        gap: 12px;\n      }\n\n      .answer-cover {\n        width: 72px;\n        height: 72px;\n      }\n\n      .answer-name {\n        font-size: clamp(20px, 7vw, 26px);\n      }\n\n      .answer-stats,\n      .help-grid {\n        grid-template-columns: 1fr;\n      }\n    }\n\n    @media (max-width: 520px) {\n      .ranked-demo-app {\n        padding-inline: 3px;\n      }\n\n      .top-logo {\n        width: min(232px, 64vw);\n      }\n    }\n\n    @media (max-width: 400px) {\n      .ranked-demo-app {\n        padding-inline: 2px;\n      }\n\n      .top-logo {\n        width: min(214px, 62vw);\n      }\n\n      .attempts-card,\n      .button,\n      .secondary-button {\n        font-size: 12px;\n      }\n\n      .feat-circle {\n        width: 268px;\n        height: 268px;\n      }\n\n      .feat-node.is-center {\n        width: 82px;\n        height: 82px;\n      }\n    }\n\n    @media (hover: none), (pointer: coarse) {\n      .meta-button:hover,\n      .button:hover,\n      .secondary-button:hover,\n      .suggestion:hover {\n        transform: none;\n      }\n\n      .button:hover,\n      .secondary-button.is-primary:hover,\n      .meta-button.is-active:hover {\n        background: var(--accent);\n        border-color: var(--accent);\n        color: #111;\n      }\n\n      .secondary-button.is-muted:hover {\n        background: rgba(255, 255, 255, 0.03);\n        border-color: var(--line);\n        color: var(--white);\n      }\n    }\n\n    @media (max-width: 720px) {\n      .ranked-demo-app .top-logo {\n        margin-top: 14px !important;\n      }\n    }\n  <\/style>\n<\/head>\n<body>\n  <div class=\"ranked-demo-app\">\n    <div class=\"app-shell\">\n      <header class=\"topbar\">\n        <img decoding=\"async\" class=\"top-logo\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato.png\" alt=\"BulldogFeat Classificato\">\n      <\/header>\n\n      <main class=\"shell\">\n        <section class=\"game-shell\">\n          <section class=\"meta-grid\" aria-label=\"Statistiche Classificata\">\n            <article class=\"meta-card is-accent\">\n              <span class=\"meta-label\">Tempo<\/span>\n              <strong id=\"timerValue\" class=\"meta-value\">2:00<\/strong>\n            <\/article>\n            <article class=\"meta-card\">\n              <span class=\"meta-label\">Punti<\/span>\n              <strong id=\"scoreValue\" class=\"meta-value\">0<\/strong>\n            <\/article>\n            <button id=\"helpToggle\" class=\"meta-button\" type=\"button\">Come si gioca<\/button>\n          <\/section>\n\n          <section id=\"helpPanel\" class=\"help-panel\" aria-hidden=\"true\">\n            <div class=\"help-grid\">\n              <div class=\"help-card\">\n                <strong>Timer<\/strong>\n                <span>Hai 2 minuti per fare il punteggio piu alto possibile.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Punti<\/strong>\n                <span>Ogni artista corretto vale 1 punto e aggiunge 15 secondi.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Skip<\/strong>\n                <span>Puoi skippare l'artista corrente, ma perdi 15 secondi.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Tentativi<\/strong>\n                <span>Hai 5 tentativi per artista. Ogni errore svela un nuovo feat.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Centro<\/strong>\n                <span>Al centro vedi il tipo dell'artista. I feat attorno si aprono uno alla volta mentre sbagli.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Record<\/strong>\n                <span>Quando il backend ranked e presente, il miglior punteggio viene salvato come nell'originale.<\/span>\n              <\/div>\n            <\/div>\n          <\/section>\n\n          <section id=\"summaryPanel\" class=\"summary-panel hidden\" aria-live=\"polite\">\n            <h3 id=\"summaryTitle\" class=\"summary-title\">Partita conclusa<\/h3>\n            <div id=\"summaryLines\" class=\"summary-lines\"><\/div>\n          <\/section>\n\n          <div id=\"gameMsg\" class=\"message\" aria-live=\"polite\"><\/div>\n\n          <div id=\"resultsList\" class=\"results-list\">\n          <\/div>\n\n          <div id=\"rankedBoardShell\" class=\"feat-board-shell hidden\">\n            <div class=\"feat-circle\">\n              <div id=\"centerArtist\" class=\"feat-center-slot\"><\/div>\n              <div id=\"hint-0\" class=\"feat-hint-slot\"><\/div>\n              <div id=\"hint-1\" class=\"feat-hint-slot\"><\/div>\n              <div id=\"hint-2\" class=\"feat-hint-slot\"><\/div>\n              <div id=\"hint-3\" class=\"feat-hint-slot\"><\/div>\n              <div id=\"hint-4\" class=\"feat-hint-slot\"><\/div>\n            <\/div>\n          <\/div>\n\n          <form id=\"guessForm\" class=\"input-grid\" autocomplete=\"off\">\n            <div id=\"attemptsCard\" class=\"attempts-card\" aria-live=\"polite\">5 TENTATIVI<\/div>\n\n            <div class=\"input-shell\">\n              <input id=\"artistInput\" class=\"search-field\" type=\"text\" placeholder=\"inserisci un artista\" aria-describedby=\"gameMsg\">\n              <div id=\"suggestions\" class=\"suggestions\" role=\"listbox\" aria-label=\"Suggerimenti artisti classificata\"><\/div>\n            <\/div>\n\n              <button id=\"submitButton\" class=\"button\" type=\"submit\">PROVA<\/button>\n\n              <div class=\"action-slot\">\n                <button id=\"sideActionButton\" class=\"secondary-button is-primary\" type=\"button\" data-action=\"start\">INIZIA<\/button>\n              <\/div>\n            <\/form>\n        <\/section>\n      <\/main>\n    <\/div>\n  <\/div>\n\n  <script>\n    (async function () {\n      const bootstrapScript = document.currentScript;\n\n      async function loadScriptSource(src) {\n        return new Promise((resolve) => {\n          const existing = Array.from(document.querySelectorAll(\"script[src]\")).find((node) => node.src === src);\n          if (existing && Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n            resolve(true);\n            return;\n          }\n\n          const script = document.createElement(\"script\");\n          script.src = src;\n          script.async = false;\n          script.onload = () => resolve(true);\n          script.onerror = () => resolve(false);\n          document.head.appendChild(script);\n        });\n      }\n\n      async function ensureArtistsLoaded() {\n        if (Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n          return window.bulldogleArtists;\n        }\n\n        const sources = [\n          \".\/artists.js\",\n          \"artists.js\",\n          \"\/bulldogle\/artists.js?v=31\"\n        ];\n\n        if (window.location && \/^https?:\/i.test(window.location.protocol) && window.location.origin) {\n          sources.push(window.location.origin + \"\/bulldogle\/artists.js?v=31\");\n        }\n\n        sources.push(\"https:\/\/bulldogmusik.it\/bulldogle\/artists.js?v=31\");\n\n        for (const source of sources) {\n          const loaded = await loadScriptSource(source);\n          if (loaded && Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n            return window.bulldogleArtists;\n          }\n        }\n\n        return [];\n      }\n\n      const artistsSource = await ensureArtistsLoaded();\n      const rankedConfig = window.bulldogleRankedConfig || {};\n      const guestLoginUrl = \"https:\/\/bulldogmusik.it\/account-login\/\";\n      const MAX_ATTEMPTS = 5;\n      const INITIAL_TIME = 120;\n      const CORRECT_BONUS = 15;\n      const SKIP_PENALTY = 15;\n      const ROUND_TRANSITION_MS = 1000;\n      const GAME_KEY = \"feat\";\n      const spotifyThumbStorageKey = \"bulldogfeat-ranked-spotify-thumbs-v1\";\n      const localBestKey = \"bulldogfeat_ranked_demo_best\";\n      const hasBackend = Boolean(rankedConfig && rankedConfig.ajaxUrl && rankedConfig.nonce);\n\n      const demoRoots = Array.from(document.querySelectorAll(\".ranked-demo-app\"));\n      const appRoot = bootstrapScript &&\n        bootstrapScript.previousElementSibling &&\n        bootstrapScript.previousElementSibling.classList &&\n        bootstrapScript.previousElementSibling.classList.contains(\"ranked-demo-app\")\n          ? bootstrapScript.previousElementSibling\n          : demoRoots[demoRoots.length - 1];\n\n      if (!appRoot) return;\n\n      appRoot.classList.add(\"is-ranked-mode\");\n      document.body.classList.add(\"bulldogfeat-ranked-mode-active\");\n      document.documentElement.classList.add(\"bulldogfeat-ranked-mode-active\");\n\n      const elements = {\n        timerValue: appRoot.querySelector(\"#timerValue\"),\n        scoreValue: appRoot.querySelector(\"#scoreValue\"),\n        helpToggle: appRoot.querySelector(\"#helpToggle\"),\n        helpPanel: appRoot.querySelector(\"#helpPanel\"),\n        rankedBoardShell: appRoot.querySelector(\"#rankedBoardShell\"),\n        centerArtist: appRoot.querySelector(\"#centerArtist\"),\n        hints: Array.from({ length: 5 }, (_, index) => appRoot.querySelector(\"#hint-\" + index)),\n        attemptsCard: appRoot.querySelector(\"#attemptsCard\"),\n        guessForm: appRoot.querySelector(\"#guessForm\"),\n        input: appRoot.querySelector(\"#artistInput\"),\n        suggestions: appRoot.querySelector(\"#suggestions\"),\n        submitButton: appRoot.querySelector(\"#submitButton\"),\n        sideActionButton: appRoot.querySelector(\"#sideActionButton\"),\n        summaryPanel: appRoot.querySelector(\"#summaryPanel\"),\n        summaryTitle: appRoot.querySelector(\"#summaryTitle\"),\n        summaryLines: appRoot.querySelector(\"#summaryLines\"),\n        message: appRoot.querySelector(\"#gameMsg\"),\n        resultsList: appRoot.querySelector(\"#resultsList\")\n      };\n\n      if (!elements.guessForm || !elements.input || !elements.submitButton || !elements.sideActionButton) {\n        return;\n      }\n\n      if (elements.suggestions.parentElement !== document.body) {\n        document.body.appendChild(elements.suggestions);\n      }\n\n      const spotifyThumbCache = new Map();\n      const spotifyThumbRequests = new Map();\n      let messageTimeoutId = 0;\n      let helpOpen = false;\n\n      try {\n        const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n        Object.keys(storedThumbs).forEach((spotifyId) => {\n          if (storedThumbs[spotifyId]) {\n            spotifyThumbCache.set(spotifyId, String(storedThumbs[spotifyId]));\n          }\n        });\n      } catch (_) {}\n\n      const artists = artistsSource.map((artist) => ({\n        id: Number(artist.id),\n        name: String(artist.name || \"\").trim(),\n        members: String(artist.members || \"\").trim(),\n        spotifyId: String(artist.spotifyId || \"\").trim(),\n        collab: String(artist.collab || \"\").trim(),\n        collabmid: String(artist.collabmid || \"\").trim()\n      })).filter((artist) => artist.id && artist.name);\n\n      const validArtists = artists.filter((artist) => {\n        const midCount = splitList(artist.collabmid).length;\n        const collabCount = splitList(artist.collab).length;\n        return midCount >= 3 && (midCount + collabCount) >= 5;\n      });\n\n      const state = {\n        active: false,\n        preparing: false,\n        submitting: false,\n        complete: false,\n        betweenRounds: false,\n        sessionToken: \"\",\n        currentArtist: null,\n        hints: [],\n        revealedHints: 1,\n        roundAttempts: 0,\n        roundGuessedIds: new Set(),\n        usedTargetIds: new Set(),\n        score: 0,\n        timeLeft: INITIAL_TIME,\n        results: [],\n        timerId: 0,\n        roundTransitionId: 0,\n        summaryTitle: \"Partita conclusa\",\n        summaryLines: [],\n        isRecord: false\n      };\n\n      if (!validArtists.length) {\n        setMessage(\"Nessun artista valido trovato per BulldogFeat Ranked.\", \"error-final\");\n        disableInput(true);\n        return;\n      }\n\n      function splitList(value) {\n        return String(value || \"\")\n          .split(\",\")\n          .map((entry) => entry.trim())\n          .filter(Boolean);\n      }\n\n      function normalize(value) {\n        return String(value || \"\").trim().toLowerCase();\n      }\n\n      function shuffle(array) {\n        const next = array.slice();\n        for (let index = next.length - 1; index > 0; index--) {\n          const swapIndex = Math.floor(Math.random() * (index + 1));\n          const temp = next[index];\n          next[index] = next[swapIndex];\n          next[swapIndex] = temp;\n        }\n        return next;\n      }\n\n      function findArtistByName(name) {\n        const normalized = normalize(name);\n        return artists.find((artist) => normalize(artist.name) === normalized);\n      }\n\n      function pickRandomValidArtist(excludedIds) {\n        const blocked = excludedIds || new Set();\n        let pool = validArtists.filter((artist) => !blocked.has(artist.id));\n        if (!pool.length) {\n          pool = validArtists.slice();\n        }\n        return pool[Math.floor(Math.random() * pool.length)];\n      }\n\n      function buildHintSet(targetArtist) {\n        const usedIds = new Set([targetArtist.id]);\n        const hints = [];\n\n        addHintsFromNames(splitList(targetArtist.collabmid), 3, \"collabmid\");\n        addHintsFromNames(splitList(targetArtist.collab), 2, \"collab\");\n\n        if (hints.length < 5) {\n          const fallback = shuffle(\n            artists.filter((artist) => !usedIds.has(artist.id))\n          );\n\n          for (const artist of fallback) {\n            if (hints.length >= 5) break;\n            hints.push({ artist: artist, source: \"fallback\" });\n            usedIds.add(artist.id);\n          }\n        }\n\n        return hints.slice(0, 5);\n\n        function addHintsFromNames(names, limit, source) {\n          const pool = shuffle(Array.from(new Set(names)));\n          for (const name of pool) {\n            if (hints.filter((hint) => hint.source === source).length >= limit || hints.length >= 5) {\n              break;\n            }\n            const artist = findArtistByName(name);\n            if (!artist || usedIds.has(artist.id)) {\n              continue;\n            }\n            hints.push({ artist: artist, source: source });\n            usedIds.add(artist.id);\n          }\n        }\n      }\n\n      function getInitials(name) {\n        return String(name || \"\")\n          .split(\/\\s+\/)\n          .filter(Boolean)\n          .map((word) => word.charAt(0))\n          .join(\"\")\n          .slice(0, 2)\n          .toUpperCase() || \"BF\";\n      }\n\n      function persistSpotifyThumbnailUrl(spotifyId, thumbnailUrl) {\n        if (!spotifyId || !thumbnailUrl) return;\n        try {\n          const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n          storedThumbs[spotifyId] = thumbnailUrl;\n          window.localStorage.setItem(spotifyThumbStorageKey, JSON.stringify(storedThumbs));\n        } catch (_) {}\n      }\n\n      function clearSpotifyThumbnailUrl(spotifyId) {\n        if (!spotifyId) return;\n        spotifyThumbCache.delete(spotifyId);\n        spotifyThumbRequests.delete(spotifyId);\n        try {\n          const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n          delete storedThumbs[spotifyId];\n          window.localStorage.setItem(spotifyThumbStorageKey, JSON.stringify(storedThumbs));\n        } catch (_) {}\n      }\n\n      async function getSpotifyThumbnailUrl(spotifyId) {\n        if (!spotifyId) return \"\";\n        if (spotifyThumbCache.has(spotifyId)) {\n          return spotifyThumbCache.get(spotifyId);\n        }\n        if (spotifyThumbRequests.has(spotifyId)) {\n          return spotifyThumbRequests.get(spotifyId);\n        }\n\n        const request = (async function () {\n          const sources = [\n            \"https:\/\/open.spotify.com\/oembed?url=\" + encodeURIComponent(\"https:\/\/open.spotify.com\/artist\/\" + spotifyId),\n            \"https:\/\/open.spotify.com\/oembed?url=\" + encodeURIComponent(\"spotify:artist:\" + spotifyId)\n          ];\n\n          for (const source of sources) {\n            try {\n              const response = await fetch(source, { credentials: \"omit\" });\n              if (!response.ok) continue;\n              const payload = await response.json();\n              const thumbnailUrl = payload && payload.thumbnail_url ? String(payload.thumbnail_url) : \"\";\n              if (thumbnailUrl) {\n                spotifyThumbCache.set(spotifyId, thumbnailUrl);\n                persistSpotifyThumbnailUrl(spotifyId, thumbnailUrl);\n                return thumbnailUrl;\n              }\n            } catch (_) {}\n          }\n\n          return \"\";\n        })().finally(function () {\n          spotifyThumbRequests.delete(spotifyId);\n        });\n\n        spotifyThumbRequests.set(spotifyId, request);\n        return request;\n      }\n\n      function buildAvatar(artist, mystery) {\n        const avatar = document.createElement(\"div\");\n        avatar.className = \"feat-avatar\" + (mystery ? \" is-mystery\" : \"\");\n        avatar.textContent = mystery ? \"?\" : getInitials(artist.name);\n\n        if (!mystery && artist.spotifyId) {\n          getSpotifyThumbnailUrl(artist.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = artist.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              avatar.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(artist.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        return avatar;\n      }\n\n      function renderCenterCard() {\n        elements.centerArtist.innerHTML = \"\";\n        const node = document.createElement(\"div\");\n        node.className = \"feat-node is-center\";\n\n        if (state.currentArtist && (state.complete || state.betweenRounds)) {\n          node.classList.add(state.lastRoundSolved ? \"is-won\" : \"is-lost\");\n          node.appendChild(buildAvatar(state.currentArtist, false));\n          const name = document.createElement(\"div\");\n          name.className = \"feat-label\";\n          name.textContent = state.currentArtist.name;\n          const members = document.createElement(\"div\");\n          members.className = \"feat-index\";\n          members.textContent = state.currentArtist.members || \"Artista\";\n          node.appendChild(name);\n          node.appendChild(members);\n        } else if (state.currentArtist) {\n          node.appendChild(buildAvatar(state.currentArtist, true));\n          const members = document.createElement(\"div\");\n          members.className = \"feat-label\";\n          members.textContent = state.currentArtist.members || \"Artista\";\n          node.appendChild(members);\n        }\n\n        elements.centerArtist.appendChild(node);\n      }\n\n      function renderHints() {\n        const positions = [0, 72, 144, 216, 288];\n        const radius = 105;\n\n        state.hints.forEach((hint, index) => {\n          const angle = positions[index] * (Math.PI \/ 180);\n          const x = Math.sin(angle) * radius;\n          const y = -Math.cos(angle) * radius;\n          const slot = elements.hints[index];\n          if (!slot) return;\n\n          const isRevealed = index < state.revealedHints || state.complete || state.betweenRounds;\n          slot.style.transform = \"translate(\" + x + \"px, \" + y + \"px)\";\n          slot.innerHTML = \"\";\n\n          const node = document.createElement(\"div\");\n          node.className = \"feat-node\" + (index >= 3 ? \" is-important\" : \"\");\n          node.appendChild(buildAvatar(hint.artist, !isRevealed));\n\n          const label = document.createElement(\"div\");\n          label.className = \"feat-label\";\n          label.textContent = isRevealed ? hint.artist.name : \"?\";\n          node.appendChild(label);\n\n          if (!isRevealed) {\n            const number = document.createElement(\"div\");\n            number.className = \"feat-index\";\n            number.textContent = String(index + 1);\n            node.appendChild(number);\n          }\n\n          slot.appendChild(node);\n        });\n      }\n\n      function buildAnswerCard(result) {\n        const article = document.createElement(\"article\");\n        article.className = \"answer-card\" + (result.solved ? \" is-correct\" : \"\");\n\n        const top = document.createElement(\"div\");\n        top.className = \"answer-card-head\";\n\n        const cover = document.createElement(\"div\");\n        cover.className = \"answer-cover\";\n        const coverFallback = document.createElement(\"div\");\n        coverFallback.className = \"answer-cover-fallback\";\n        coverFallback.textContent = getInitials(result.artist.name);\n        cover.appendChild(coverFallback);\n\n        if (result.artist.spotifyId) {\n          getSpotifyThumbnailUrl(result.artist.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = result.artist.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              cover.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(result.artist.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        const copy = document.createElement(\"div\");\n        copy.className = \"answer-copy\";\n\n        const badge = document.createElement(\"span\");\n        badge.className = \"answer-badge\";\n        badge.textContent = result.label;\n\n        const name = document.createElement(\"h3\");\n        name.className = \"answer-name\";\n        name.textContent = result.artist.name;\n\n        const sub = document.createElement(\"p\");\n        sub.className = \"answer-sub\";\n        sub.textContent = (result.artist.members || \"Artista\") + \" \u2022 \" + result.revealedHints + \"\/5 feat visibili\";\n\n        copy.appendChild(badge);\n        copy.appendChild(name);\n        copy.appendChild(sub);\n        top.appendChild(cover);\n        top.appendChild(copy);\n        article.appendChild(top);\n\n        const strongFeatCount = splitList(result.artist.collabmid).length;\n        const allFeatCount = strongFeatCount + splitList(result.artist.collab).length;\n        const stats = [\n          { label: \"Tipo\", value: result.artist.members || \"Artista\" },\n          { label: \"Feat stretti\", value: String(strongFeatCount) },\n          { label: \"Feat totali\", value: String(allFeatCount) }\n        ];\n\n        const statsGrid = document.createElement(\"div\");\n        statsGrid.className = \"answer-stats\";\n        stats.forEach((stat) => {\n          const item = document.createElement(\"div\");\n          item.className = \"answer-stat\";\n          const label = document.createElement(\"span\");\n          label.className = \"answer-stat-label\";\n          label.textContent = stat.label;\n          const value = document.createElement(\"span\");\n          value.className = \"answer-stat-value\";\n          value.textContent = stat.value;\n          item.appendChild(label);\n          item.appendChild(value);\n          statsGrid.appendChild(item);\n        });\n        article.appendChild(statsGrid);\n\n        return article;\n      }\n\n      function renderMeta() {\n        elements.timerValue.textContent = formatTime(state.timeLeft);\n        elements.scoreValue.textContent = String(state.score);\n        elements.helpToggle.classList.toggle(\"is-active\", helpOpen);\n      }\n\n      function renderHelp() {\n        elements.helpPanel.classList.toggle(\"is-open\", helpOpen);\n        elements.helpPanel.setAttribute(\"aria-hidden\", helpOpen ? \"false\" : \"true\");\n        elements.helpToggle.classList.toggle(\"is-active\", helpOpen);\n      }\n\n      function renderAttempts() {\n        const attemptsLeft = Math.max(0, MAX_ATTEMPTS - state.roundAttempts);\n        elements.attemptsCard.textContent = attemptsLeft + \" \" + (attemptsLeft === 1 ? \"TENTATIVO\" : \"TENTATIVI\");\n      }\n\n      function renderActionButton() {\n        const button = elements.sideActionButton;\n        button.className = \"secondary-button\";\n        button.disabled = false;\n\n        if (state.preparing || state.submitting) {\n          button.textContent = \"...\";\n          button.classList.add(\"is-muted\");\n          button.disabled = true;\n          button.dataset.action = \"wait\";\n          return;\n        }\n\n        if (state.active) {\n          if (state.betweenRounds) {\n            button.textContent = \"ATTENDI\";\n            button.classList.add(\"is-muted\");\n            button.disabled = true;\n            button.dataset.action = \"wait\";\n            return;\n          }\n          button.textContent = \"SKIP\";\n          button.classList.add(\"is-muted\");\n          button.dataset.action = \"skip\";\n          return;\n        }\n\n        if (state.complete) {\n          button.textContent = \"RIGIOCA\";\n          button.classList.add(\"is-primary\");\n          button.dataset.action = \"restart\";\n          return;\n        }\n\n        if (hasBackend && !rankedConfig.isLoggedIn) {\n          button.textContent = \"ACCEDI\";\n          button.classList.add(\"is-primary\");\n          button.dataset.action = \"login\";\n          return;\n        }\n\n        button.textContent = \"INIZIA\";\n        button.classList.add(\"is-primary\");\n        button.dataset.action = \"start\";\n      }\n\n      function renderInput() {\n        const disabled = !state.active || state.betweenRounds || state.preparing || state.submitting;\n        elements.input.disabled = disabled;\n        elements.submitButton.disabled = disabled;\n      }\n\n      function renderSummary() {\n        elements.summaryPanel.classList.toggle(\"hidden\", !state.complete || !state.summaryLines.length);\n        elements.summaryPanel.classList.toggle(\"is-record\", state.isRecord);\n        elements.summaryTitle.textContent = state.summaryTitle || \"Partita conclusa\";\n        elements.summaryLines.innerHTML = \"\";\n        state.summaryLines.forEach((line) => {\n          const row = document.createElement(\"div\");\n          row.className = \"summary-line\";\n          row.innerHTML = line;\n          elements.summaryLines.appendChild(row);\n        });\n      }\n\n      function renderResults() {\n        elements.resultsList.innerHTML = \"\";\n        return;\n      }\n\n      function renderBoard() {\n        const boardVisible = state.active || state.complete || state.betweenRounds;\n        elements.rankedBoardShell.classList.toggle(\"hidden\", !boardVisible);\n        elements.rankedBoardShell.classList.toggle(\"is-visible\", boardVisible);\n        renderCenterCard();\n        renderHints();\n      }\n\n      function renderApp() {\n        renderMeta();\n        renderHelp();\n        renderAttempts();\n        renderActionButton();\n        renderInput();\n        renderSummary();\n        renderBoard();\n        renderResults();\n      }\n\n      function disableInput(disabled) {\n        elements.input.disabled = disabled;\n        elements.submitButton.disabled = disabled;\n      }\n\n      function setMessage(text, tone) {\n        if (messageTimeoutId) {\n          window.clearTimeout(messageTimeoutId);\n          messageTimeoutId = 0;\n        }\n\n        elements.message.className = \"message\";\n        if (text && tone) {\n          elements.message.textContent = text;\n          elements.message.classList.add(\"is-visible\", \"is-\" + tone);\n          if (tone !== \"success\" && tone !== \"error-final\") {\n            messageTimeoutId = window.setTimeout(function () {\n              elements.message.className = \"message\";\n              elements.message.textContent = \"\";\n              messageTimeoutId = 0;\n            }, 2200);\n          }\n          return;\n        }\n\n        elements.message.textContent = \"\";\n      }\n\n      function formatTime(totalSeconds) {\n        const safeTime = Math.max(0, totalSeconds);\n        const minutes = Math.floor(safeTime \/ 60);\n        const seconds = String(safeTime % 60).padStart(2, \"0\");\n        return minutes + \":\" + seconds;\n      }\n\n      function readLocalBest() {\n        try {\n          return Number(window.localStorage.getItem(localBestKey) || 0);\n        } catch (_) {\n          return 0;\n        }\n      }\n\n      function writeLocalBest(score) {\n        const best = Math.max(readLocalBest(), Number(score || 0));\n        try {\n          window.localStorage.setItem(localBestKey, String(best));\n        } catch (_) {}\n        return best;\n      }\n\n      async function postRankedAction(action, extraData) {\n        const body = new URLSearchParams({\n          action: action,\n          nonce: rankedConfig.nonce || \"\",\n          game_key: GAME_KEY,\n          ...(extraData || {})\n        });\n\n        const response = await fetch(rankedConfig.ajaxUrl, {\n          method: \"POST\",\n          credentials: \"same-origin\",\n          headers: {\n            \"Content-Type\": \"application\/x-www-form-urlencoded; charset=UTF-8\"\n          },\n          body: body.toString()\n        });\n\n        if (!response.ok) {\n          throw new Error(\"Richiesta ranked non riuscita\");\n        }\n\n        return response.json();\n      }\n\n      function startNextArtist() {\n        window.clearTimeout(state.roundTransitionId);\n        state.betweenRounds = false;\n\n        if (state.usedTargetIds.size >= validArtists.length) {\n          state.usedTargetIds.clear();\n        }\n\n        state.currentArtist = pickRandomValidArtist(state.usedTargetIds);\n        state.usedTargetIds.add(state.currentArtist.id);\n        state.hints = buildHintSet(state.currentArtist);\n        state.revealedHints = 1;\n        state.roundAttempts = 0;\n        state.roundGuessedIds = new Set();\n        elements.input.value = \"\";\n        hideSuggestions();\n        setMessage(\"\", \"\");\n        renderApp();\n        elements.input.focus();\n      }\n\n      async function startGame() {\n        if (state.active || state.preparing) return;\n\n        if (hasBackend && !rankedConfig.isLoggedIn) {\n          window.location.href = rankedConfig.loginUrl || guestLoginUrl;\n          return;\n        }\n\n        state.preparing = true;\n        renderActionButton();\n\n        try {\n          if (hasBackend) {\n            const response = await postRankedAction(\"bulldogle_ranked_start\");\n            if (!response || !response.success || !response.data || !response.data.is_logged_in) {\n              window.location.href = rankedConfig.loginUrl || guestLoginUrl;\n              return;\n            }\n            state.sessionToken = String(response.data.token || \"\");\n          } else {\n            state.sessionToken = \"demo-\" + String(Date.now());\n          }\n\n          window.clearInterval(state.timerId);\n          window.clearTimeout(state.roundTransitionId);\n          state.active = true;\n          state.complete = false;\n          state.submitting = false;\n          state.betweenRounds = false;\n          state.score = 0;\n          state.timeLeft = INITIAL_TIME;\n          state.results = [];\n          state.summaryTitle = \"Partita conclusa\";\n          state.summaryLines = [];\n          state.isRecord = false;\n          startNextArtist();\n          state.timerId = window.setInterval(tick, 1000);\n        } catch (_) {\n          state.active = false;\n          state.complete = false;\n          state.betweenRounds = false;\n          state.submitting = false;\n          state.currentArtist = null;\n          state.hints = [];\n          state.revealedHints = 1;\n          state.roundAttempts = 0;\n          state.roundGuessedIds = new Set();\n          state.usedTargetIds = new Set();\n          state.results = [];\n          window.clearInterval(state.timerId);\n          window.clearTimeout(state.roundTransitionId);\n          state.timerId = 0;\n          state.roundTransitionId = 0;\n          setMessage(\"Non sono riuscito ad avviare la partita. Riprova tra poco.\", \"error\");\n        } finally {\n          state.preparing = false;\n          renderApp();\n        }\n      }\n\n      function tick() {\n        if (!state.active) return;\n        state.timeLeft -= 1;\n        renderMeta();\n        if (state.timeLeft <= 0) {\n          finishGame();\n        }\n      }\n\n      function completeRound(label, solved) {\n        state.results.unshift({\n          artist: state.currentArtist,\n          label: label,\n          solved: solved,\n          revealedHints: state.revealedHints\n        });\n\n        state.lastRoundSolved = solved;\n        state.betweenRounds = true;\n        elements.input.value = \"\";\n        hideSuggestions();\n        renderApp();\n\n        state.roundTransitionId = window.setTimeout(function () {\n          if (!state.active || state.timeLeft <= 0) return;\n          startNextArtist();\n        }, ROUND_TRANSITION_MS);\n      }\n\n      function makeGuess() {\n        if (!state.active || state.betweenRounds || !state.currentArtist) return;\n\n        const guessArtist = findArtistByName(elements.input.value.trim());\n        if (!guessArtist) {\n          setMessage(\"Artista non trovato nella lista.\", \"error\");\n          return;\n        }\n\n        if (state.roundGuessedIds.has(guessArtist.id)) {\n          setMessage(\"Hai gia provato questo artista.\", \"error\");\n          elements.input.value = \"\";\n          return;\n        }\n\n        state.roundGuessedIds.add(guessArtist.id);\n        state.roundAttempts += 1;\n        elements.input.value = \"\";\n        hideSuggestions();\n\n        if (guessArtist.id === state.currentArtist.id) {\n          state.score += 1;\n          state.timeLeft += CORRECT_BONUS;\n          setMessage(\"Hai indovinato!\", \"success\");\n          completeRound(\"Hai indovinato\", true);\n          return;\n        }\n\n        if (state.revealedHints < 5) {\n          state.revealedHints += 1;\n        }\n\n        if (state.roundAttempts >= MAX_ATTEMPTS) {\n          setMessage(\"Hai finito i tentativi! Era \" + state.currentArtist.name + \".\", \"error-final\");\n          completeRound(\"Reveal del round\", false);\n          return;\n        }\n\n        renderApp();\n      }\n\n      function skipArtist() {\n        if (!state.active || state.betweenRounds || !state.currentArtist) return;\n        state.timeLeft = Math.max(0, state.timeLeft - SKIP_PENALTY);\n        if (state.timeLeft <= 0) {\n          finishGame();\n          return;\n        }\n        setMessage(\"Hai skippato! Era \" + state.currentArtist.name + \".\", \"error-final\");\n        completeRound(\"Skip\", false);\n      }\n\n      function buildSummaryLines(data) {\n        const lines = [];\n        if (state.currentArtist && state.currentArtist.name) {\n          lines.push(\"L'ultimo artista era: <strong>\" + escapeHtml(state.currentArtist.name) + \"<\/strong>\");\n        }\n        lines.push(\"Punteggio finale: <strong>\" + String(state.score) + \"<\/strong>\");\n\n        if (data) {\n          if (typeof data.best_score !== \"undefined\") {\n            lines.push(\"Record mensile: <strong>\" + String(data.best_score) + \"<\/strong>\");\n          }\n          if (data.best_rank) {\n            lines.push(\"Migliore posizione: <strong>#\" + String(data.best_rank) + \"<\/strong>\");\n          } else {\n            lines.push(\"Migliore posizione: <strong>Fuori top 50<\/strong>\");\n          }\n        } else {\n          lines.push(\"Record non salvato, riprova piu tardi.\");\n        }\n\n        return lines;\n      }\n\n      async function finishGame() {\n        if (!state.active || state.submitting) return;\n\n        state.active = false;\n        state.complete = true;\n        state.betweenRounds = false;\n        state.submitting = true;\n        state.timeLeft = 0;\n        window.clearInterval(state.timerId);\n        window.clearTimeout(state.roundTransitionId);\n        state.timerId = 0;\n        state.roundTransitionId = 0;\n        hideSuggestions();\n        setMessage(\"\", \"\");\n        state.summaryTitle = \"Partita conclusa\";\n        state.summaryLines = [\"Salvataggio record...\"];\n        state.isRecord = false;\n        renderApp();\n\n        try {\n          let data = null;\n          if (hasBackend) {\n            const response = await postRankedAction(\"bulldogle_ranked_submit\", {\n              token: state.sessionToken,\n              score: String(state.score)\n            });\n            data = response && response.success ? response.data : null;\n          } else {\n            const previousBest = readLocalBest();\n            const nextBest = writeLocalBest(state.score);\n            data = {\n              best_score: nextBest,\n              best_rank: null,\n              is_record: state.score > previousBest\n            };\n          }\n\n          if (data) {\n            state.summaryTitle = data.is_record ? \"Nuovo record!\" : \"Partita conclusa\";\n            state.summaryLines = buildSummaryLines(data);\n            state.isRecord = Boolean(data.is_record);\n          } else {\n            state.summaryTitle = \"Partita conclusa\";\n            state.summaryLines = buildSummaryLines(null);\n            state.isRecord = false;\n          }\n        } catch (_) {\n          state.summaryTitle = \"Partita conclusa\";\n          state.summaryLines = buildSummaryLines(null);\n          state.isRecord = false;\n        } finally {\n          state.submitting = false;\n          renderApp();\n        }\n      }\n\n      function escapeHtml(value) {\n        const div = document.createElement(\"div\");\n        div.textContent = value || \"\";\n        return div.innerHTML;\n      }\n\n      function showSuggestions() {\n        positionSuggestions();\n        elements.suggestions.style.display = \"block\";\n      }\n\n      function hideSuggestions() {\n        elements.suggestions.style.display = \"none\";\n      }\n\n      function positionSuggestions() {\n        const rect = elements.input.getBoundingClientRect();\n        const viewportPadding = 8;\n        const width = Math.max(240, rect.width);\n        const left = Math.min(\n          window.innerWidth - width - viewportPadding,\n          Math.max(viewportPadding, rect.left)\n        );\n        const viewportHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight;\n        const spaceBelow = viewportHeight - rect.bottom - viewportPadding;\n        const maxHeight = Math.max(140, Math.min(280, spaceBelow - 8));\n\n        elements.suggestions.style.width = width + \"px\";\n        elements.suggestions.style.left = left + \"px\";\n        elements.suggestions.style.top = Math.max(viewportPadding, rect.bottom + 8) + \"px\";\n        elements.suggestions.style.maxHeight = maxHeight + \"px\";\n      }\n\n      function updateSuggestions() {\n        const value = normalize(elements.input.value);\n        elements.suggestions.innerHTML = \"\";\n\n        if (!value || !state.active || state.betweenRounds || !state.currentArtist) {\n          hideSuggestions();\n          return;\n        }\n\n        const matches = artists.filter((artist) => {\n          return normalize(artist.name).includes(value) && !state.roundGuessedIds.has(artist.id);\n        }).slice(0, 8);\n\n        if (!matches.length) {\n          hideSuggestions();\n          return;\n        }\n\n        matches.forEach((artist) => {\n          const button = document.createElement(\"button\");\n          button.type = \"button\";\n          button.className = \"suggestion\";\n          const left = document.createElement(\"span\");\n          left.textContent = artist.name;\n          const right = document.createElement(\"small\");\n          right.textContent = artist.members || \"Artista\";\n          button.appendChild(left);\n          button.appendChild(right);\n          button.addEventListener(\"click\", function () {\n            elements.input.value = artist.name;\n            hideSuggestions();\n            elements.input.focus();\n          });\n          elements.suggestions.appendChild(button);\n        });\n\n        showSuggestions();\n      }\n\n      function handleSideAction() {\n        const action = elements.sideActionButton.dataset.action;\n        if (action === \"login\") {\n          window.location.href = rankedConfig.loginUrl || guestLoginUrl;\n          return;\n        }\n        if (action === \"start\" || action === \"restart\") {\n          startGame();\n          return;\n        }\n        if (action === \"skip\") {\n          skipArtist();\n        }\n      }\n\n      function bindTouchAction(node, handler) {\n        if (!node) return;\n\n        let touchHandled = false;\n\n        node.addEventListener(\"touchend\", function (event) {\n          if (node.disabled) return;\n          event.preventDefault();\n          touchHandled = true;\n          handler();\n          window.setTimeout(function () {\n            touchHandled = false;\n          }, 350);\n        }, { passive: false });\n\n        node.addEventListener(\"click\", function (event) {\n          if (node.disabled) return;\n          if (touchHandled) {\n            event.preventDefault();\n            return;\n          }\n          handler();\n        });\n      }\n\n      elements.helpToggle.addEventListener(\"click\", function () {\n        helpOpen = !helpOpen;\n        renderHelp();\n      });\n\n      elements.guessForm.addEventListener(\"submit\", function (event) {\n        event.preventDefault();\n        makeGuess();\n      });\n\n      bindTouchAction(elements.sideActionButton, handleSideAction);\n      elements.input.addEventListener(\"input\", updateSuggestions);\n      elements.input.addEventListener(\"focus\", updateSuggestions);\n\n      document.addEventListener(\"click\", function (event) {\n        if (!elements.suggestions.contains(event.target) && event.target !== elements.input) {\n          hideSuggestions();\n        }\n      });\n\n      window.addEventListener(\"resize\", function () {\n        if (elements.suggestions.style.display === \"block\") {\n          positionSuggestions();\n        }\n      });\n\n      window.addEventListener(\"scroll\", function () {\n        if (elements.suggestions.style.display === \"block\") {\n          positionSuggestions();\n        }\n      }, true);\n\n      if (window.visualViewport) {\n        window.visualViewport.addEventListener(\"resize\", function () {\n          if (elements.suggestions.style.display === \"block\") {\n            positionSuggestions();\n          }\n        });\n\n        window.visualViewport.addEventListener(\"scroll\", function () {\n          if (elements.suggestions.style.display === \"block\") {\n            positionSuggestions();\n          }\n        });\n      }\n\n      renderApp();\n    })();\n  <\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-63a1ec3 elementor-widget elementor-widget-html\" data-id=\"63a1ec3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div class=\"ranked-board-widget ranked-sidebar-board\" data-game-key=\"feat\">\n  <div class=\"ranked-sidebar-board-inner\">\n    <div class=\"ranked-board-controls\" aria-label=\"Seleziona mese classifica\">\n      <select class=\"ranked-board-period-select\">\n        <option value=\"\">Caricamento...<\/option>\n      <\/select>\n    <\/div>\n\n    <img decoding=\"async\" class=\"ranked-sidebar-board-heading-image\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/LeadBasico.png\" alt=\"Classificato\">\n\n    <div class=\"ranked-board-list\"><\/div>\n\n    <div class=\"ranked-board-pager\">\n      <button class=\"ranked-board-prev\" type=\"button\" aria-label=\"Pagina precedente\">&#8249;<\/button>\n      <span class=\"ranked-board-page\">1\/1<\/span>\n      <button class=\"ranked-board-next\" type=\"button\" aria-label=\"Pagina successiva\">&#8250;<\/button>\n    <\/div>\n\n    <div class=\"ranked-board-msg\">Caricamento classifica...<\/div>\n  <\/div>\n<\/div>\n\n<script src=\"\/bulldogle\/ranked-leaderboard.js?v=58\"><\/script>\n\n<style>\n.ranked-sidebar-board {\n  --ranked-accent: #952800;\n  --ranked-accent-2: #a83100;\n  --ranked-accent-3: #7d2100;\n  --ranked-ink: #17110d;\n  --ranked-ink-soft: rgba(23, 17, 13, 0.72);\n  --ranked-cream: #f8f0e8;\n  width: 100%;\n  max-width: 100%;\n  margin: 0;\n  font-family: Verdana, Geneva, sans-serif;\n}\n\n.ranked-sidebar-board-inner {\n  position: relative;\n  width: 100%;\n  padding: 22px 22px 20px;\n  border-radius: 34px;\n  overflow: hidden;\n  background: var(--ranked-accent);\n  box-shadow:\n    inset 0 1px 0 rgba(255, 255, 255, 0.16),\n    0 18px 34px rgba(0, 0, 0, 0.18);\n  color: var(--ranked-ink);\n  text-align: center;\n}\n\n.ranked-sidebar-board-heading-image {\n  display: block;\n  width: min(100%, 206px) !important;\n  height: auto;\n  margin: 2px auto 16px;\n}\n\n.ranked-sidebar-board .ranked-board-controls {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-bottom: 12px;\n}\n\n.ranked-sidebar-board .ranked-board-controls select {\n  width: 100% !important;\n  max-width: 182px;\n  min-width: 0;\n  height: 40px;\n  padding: 0 14px !important;\n  border: 1px solid rgba(23, 17, 13, 0.12) !important;\n  border-radius: 999px !important;\n  background: rgba(12, 8, 6, 0.9) !important;\n  color: var(--ranked-cream) !important;\n  font-family: Verdana, Geneva, sans-serif;\n  font-size: 12px !important;\n  font-weight: 700;\n  text-align: center;\n  box-shadow: none !important;\n  outline: none;\n  appearance: none;\n  -webkit-appearance: none;\n}\n\n.ranked-sidebar-board .ranked-board-list {\n  display: grid;\n  gap: 10px;\n  margin: 0;\n}\n\n.ranked-sidebar-board .ranked-board-row {\n  display: grid;\n  grid-template-columns: 66px minmax(0, 1fr) 64px;\n  align-items: center;\n  gap: 8px;\n  min-height: 52px;\n  padding: 10px 14px;\n  border: 0;\n  border-radius: 18px;\n  background: #000000;\n  color: var(--ranked-cream);\n  text-align: center;\n}\n\n.ranked-sidebar-board .ranked-board-row:first-child {\n  background: #000000;\n}\n\n.ranked-sidebar-board .ranked-board-rank {\n  color: #ffffff;\n  font-size: 13px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-name {\n  min-width: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  color: #ffffff;\n  font-size: 13px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-score {\n  color: #ffffff;\n  font-size: 13px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-pager {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 12px;\n  margin-top: 14px;\n}\n\n.ranked-sidebar-board .ranked-board-pager button {\n  appearance: none !important;\n  display: inline-flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  width: 36px !important;\n  min-width: 36px !important;\n  height: 36px !important;\n  min-height: 36px !important;\n  padding: 0 !important;\n  margin: 0 !important;\n  border: 1px solid rgba(23, 17, 13, 0.12) !important;\n  border-radius: 999px !important;\n  background: #000000 !important;\n  color: #ffffff !important;\n  font-family: Verdana, Geneva, sans-serif !important;\n  font-size: 23px !important;\n  font-weight: 700 !important;\n  line-height: 1 !important;\n  box-shadow: none !important;\n  transform: none !important;\n  cursor: pointer;\n}\n\n.ranked-sidebar-board .ranked-board-pager button:hover {\n  background: #ffffff !important;\n  color: var(--ranked-ink) !important;\n}\n\n.ranked-sidebar-board .ranked-board-pager button:disabled {\n  opacity: 0.34;\n  cursor: not-allowed;\n}\n\n.ranked-sidebar-board .ranked-board-page {\n  color: rgba(23, 17, 13, 0.72);\n  font-size: 12px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-msg {\n  min-height: 18px;\n  margin-top: 12px;\n  color: rgba(23, 17, 13, 0.72);\n  font-size: 12px;\n  line-height: 1.35;\n  font-weight: 700;\n  text-align: center;\n}\n\n@media (max-width: 767px) {\n  .ranked-sidebar-board-inner {\n    padding: 20px 18px 18px;\n    border-radius: 28px;\n  }\n\n  .ranked-sidebar-board .ranked-board-row {\n    grid-template-columns: 58px minmax(0, 1fr) 58px;\n    min-height: 48px;\n    padding: 9px 12px;\n  }\n\n  .ranked-sidebar-board-heading-image {\n    width: min(100%, 174px);\n  }\n}\n<\/style>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6158da7a elementor-hidden-desktop elementor-hidden-tablet e-flex e-con-boxed wcf-starter-animations-none e-con e-parent\" data-id=\"6158da7a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7e9d091 show-when-ranked wcf-starter-animations-none elementor-widget elementor-widget-image\" data-id=\"7e9d091\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;wcf_starter_animations&quot;:&quot;none&quot;,&quot;wcf_anim_duration&quot;:1000,&quot;wcf_anim_delay&quot;:0,&quot;wcf_anim_ease&quot;:&quot;ease&quot;}\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato-1024x576.png\" class=\"attachment-large size-large wp-image-14981\" alt=\"\" srcset=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato-1024x576.png 1024w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato-300x169.png 300w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato-768x432.png 768w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato-1320x742.png 1320w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato.png 1366w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e375a5d hide-when-ranked wcf-starter-animations-none elementor-widget elementor-widget-image\" data-id=\"e375a5d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;wcf_starter_animations&quot;:&quot;none&quot;,&quot;wcf_anim_duration&quot;:1000,&quot;wcf_anim_delay&quot;:0,&quot;wcf_anim_ease&quot;:&quot;ease&quot;}\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1-1024x576.png\" class=\"attachment-large size-large wp-image-14980\" alt=\"\" srcset=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1-1024x576.png 1024w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1-300x169.png 300w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1-768x432.png 768w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1-1320x742.png 1320w, https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1.png 1366w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf7a446 elementor-widget elementor-widget-wcf--floating-elements\" data-id=\"cf7a446\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"wcf--floating-elements.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"wcf--floating-elements\">\r\n\t\t\t                <div class=\"floating-element wcf-live-anim-wiggle elementor-repeater-item-d4c5f46   \">\r\n\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Coppa.png\" alt=\"Coppa\" \/>\t\t\t\t<\/div>\r\n\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0260560 elementor-widget-divider--view-line_text elementor-widget-mobile__width-initial elementor-widget-divider--element-align-center elementor-widget elementor-widget-divider\" data-id=\"0260560\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t\t<span class=\"elementor-divider__text elementor-divider__element\">\n\t\t\t\tModalit\u00e0\t\t\t\t<\/span>\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3817e633 elementor-widget-mobile__width-initial elementor-widget elementor-widget-html\" data-id=\"3817e633\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"it\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>BulldogFeat Demo<\/title>\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Instrument+Sans:wght@400;500;600;700;800&family=Space+Grotesk:wght@500;700&display=swap\" rel=\"stylesheet\">\n  <style>\n    :root {\n      --bg: #000;\n      --panel: #070707;\n      --panel-2: #0b0b0b;\n      --line: rgba(255, 255, 255, 0.08);\n      --line-faint: rgba(255, 255, 255, 0.05);\n      --line-strong: rgba(241, 108, 29, 0.28);\n      --white: #f7f4ef;\n      --copy: rgba(247, 244, 239, 0.76);\n      --copy-soft: rgba(247, 244, 239, 0.56);\n      --copy-faint: rgba(247, 244, 239, 0.34);\n      --accent: #f16c1d;\n      --success: #7dc56a;\n      --danger: #ff7e59;\n      --ease: 220ms cubic-bezier(.2,.9,.2,1);\n    }\n\n    * { box-sizing: border-box; }\n\n    html,\n    body {\n      margin: 0;\n      min-height: 100%;\n      background: var(--bg);\n      color: var(--white);\n      font-family: \"Instrument Sans\", system-ui, sans-serif;\n      overflow-x: hidden;\n    }\n\n    button,\n    input,\n    iframe {\n      font: inherit;\n    }\n\n    .demo-app {\n      width: min(760px, calc(100vw - 20px));\n      margin: 0 auto;\n      padding: 18px 0 24px;\n    }\n\n    .app-shell {\n      position: relative;\n      isolation: isolate;\n      padding: 14px;\n      border: 1px solid var(--line);\n      border-radius: 22px;\n      background: linear-gradient(180deg, rgba(14, 14, 14, 0.98), rgba(7, 7, 7, 0.98));\n      overflow: visible;\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n    }\n\n    .app-shell::after {\n      content: \"\";\n      position: absolute;\n      inset: 0;\n      border-radius: inherit;\n      background-image: url(\"data:image\/svg+xml,%3Csvg%20xmlns='http:\/\/www.w3.org\/2000\/svg'%20viewBox='0%200%20180%20180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='.9'%20numOctaves='3'%20stitchTiles='stitch'\/%3E%3CfeColorMatrix%20type='saturate'%20values='0'\/%3E%3CfeComponentTransfer%3E%3CfeFuncA%20type='table'%20tableValues='0%20.58'\/%3E%3C\/feComponentTransfer%3E%3C\/filter%3E%3Crect%20width='180'%20height='180'%20filter='url(%23n)'%20opacity='1'\/%3E%3C\/svg%3E\");\n      background-size: 180px 180px;\n      mix-blend-mode: overlay;\n      opacity: 0.1;\n      pointer-events: none;\n    }\n\n    .app-shell > * {\n      position: relative;\n      z-index: 1;\n    }\n\n    .topbar {\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      gap: 0;\n      padding: 10px 8px 14px;\n    }\n\n    .top-logo {\n      display: none;\n      width: min(320px, 58vw);\n      height: auto;\n    }\n    \n    @media (max-width: 768px) {\n  .top-logo {\n    display: none !important;\n  }\n\n    .controls-shell {\n      margin-top: 0;\n      padding: 14px 0 14px;\n      border-top: 1px solid var(--line);\n    }\n\n    .controls-inner {\n      display: grid;\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 8px;\n    }\n\n    .shell {\n      margin-top: 0;\n      padding-top: 14px;\n      border-top: 1px solid var(--line);\n    }\n\n    .game-shell {\n      position: relative;\n      padding: 2px 0 6px;\n      overflow: visible;\n    }\n\n    .tab,\n    .ghost-button,\n    .button,\n    .secondary-button,\n    .streak-card {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      width: 100%;\n      min-width: 0;\n      min-height: 36px;\n      padding: 0 10px;\n      border-radius: 999px;\n      border: 1px solid var(--line);\n      background: rgba(255, 255, 255, 0.03);\n      color: var(--white);\n      font-size: 12px;\n      font-weight: 700;\n      text-decoration: none;\n      cursor: pointer;\n      transition: transform var(--ease), border-color var(--ease), background var(--ease), color var(--ease), opacity var(--ease);\n    }\n\n    .tab.is-active,\n    .ghost-button.is-active {\n      border-color: var(--line-strong);\n      background: rgba(241, 108, 29, 0.12);\n    }\n\n    .demo-app.is-ranked-mode #rankedModeButton.is-active,\n    .demo-app.is-ranked-mode .ghost-button.is-active {\n      border-color: rgba(149, 40, 0, 0.28);\n      background: rgba(149, 40, 0, 0.12);\n    }\n\n    .tab-ranked-mobile {\n      display: none;\n    }\n\n    .demo-app.is-ranked-mode .hide-when-ranked,\n    body.bulldogfeat-ranked-mode-active .hide-when-ranked,\n    html.bulldogfeat-ranked-mode-active .hide-when-ranked,\n    .demo-app.is-ranked-mode .hide.when.ranked,\n    body.bulldogfeat-ranked-mode-active .hide.when.ranked,\n    html.bulldogfeat-ranked-mode-active .hide.when.ranked {\n      display: none !important;\n    }\n\n    .show-when-ranked,\n    .show.when.ranked,\n    .show-when-ranked-flex,\n    .show.flex.when.ranked,\n    .show-when-ranked-grid,\n    .show.grid.when.ranked,\n    .show-when-ranked-inline {\n      display: none !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked,\n    .demo-app.is-ranked-mode .show.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.when.ranked {\n      display: block !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked-flex,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-flex,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-flex,\n    .demo-app.is-ranked-mode .show.flex.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.flex.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.flex.when.ranked {\n      display: flex !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked-grid,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-grid,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-grid,\n    .demo-app.is-ranked-mode .show.grid.when.ranked,\n    body.bulldogfeat-ranked-mode-active .show.grid.when.ranked,\n    html.bulldogfeat-ranked-mode-active .show.grid.when.ranked {\n      display: grid !important;\n    }\n\n    .demo-app.is-ranked-mode .show-when-ranked-inline,\n    body.bulldogfeat-ranked-mode-active .show-when-ranked-inline,\n    html.bulldogfeat-ranked-mode-active .show-when-ranked-inline {\n      display: inline-flex !important;\n    }\n\n    .button,\n    .secondary-button,\n    .attempts-card,\n    .streak-card {\n      min-width: 152px;\n      min-height: 56px;\n      height: 56px;\n      padding: 0 22px;\n      border-radius: 12px;\n      font-size: 15px;\n      line-height: 1;\n      font-weight: 700;\n      letter-spacing: 0;\n      text-transform: uppercase;\n      box-shadow: none;\n    }\n\n    .button,\n    .secondary-button.is-primary,\n    .streak-card {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #111;\n    }\n\n    .demo-app:not(.is-ranked-mode) #submitButton.button {\n      background: #f16c1d !important;\n      border-color: #f16c1d !important;\n      color: #111 !important;\n    }\n\n    .secondary-button.is-muted {\n      background: rgba(255, 255, 255, 0.03);\n      border-color: var(--line);\n      color: var(--white);\n    }\n\n    .button:hover,\n    .secondary-button:hover,\n    .streak-card.is-guest:hover {\n      background: #fff;\n      border-color: #fff;\n      color: #111;\n    }\n\n    .demo-app:not(.is-ranked-mode) #submitButton.button:hover {\n      background: #fff !important;\n      border-color: #fff !important;\n      color: #111 !important;\n    }\n\n    .tab:hover,\n    .ghost-button:hover,\n    .button:hover,\n    .secondary-button:hover,\n    .streak-card.is-guest:hover,\n    .suggestion:hover {\n      transform: translateY(-1px);\n    }\n\n    .button:disabled,\n    .secondary-button:disabled {\n      cursor: not-allowed;\n      opacity: 0.45;\n      transform: none;\n    }\n\n    .help-panel {\n      max-height: 0;\n      overflow: hidden;\n      padding-bottom: 0;\n      border-bottom: 1px solid transparent;\n      transition: max-height 240ms ease, margin 240ms ease, padding-bottom 240ms ease, border-color 240ms ease;\n      margin: 0;\n    }\n\n    .help-panel.is-open {\n      max-height: 1200px;\n      padding-bottom: 12px;\n      border-bottom-color: var(--line);\n      margin: 0 0 12px;\n    }\n\n    .help-panel-mobile-slot {\n      display: none;\n    }\n\n    .help-grid {\n      display: grid;\n      grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n      gap: 10px;\n    }\n\n    .help-card {\n      min-height: 100%;\n      padding: 12px 13px;\n      border: 1px solid var(--line);\n      border-radius: 12px;\n      background: rgba(255, 255, 255, 0.03);\n    }\n\n    .help-card strong {\n      display: block;\n      margin-bottom: 8px;\n      font-size: 13px;\n    }\n\n    .help-card span {\n      display: block;\n      color: var(--copy-soft);\n      font-size: 12px;\n      line-height: 1.45;\n    }\n\n    .feat-panel,\n    .feat-ranked-panel {\n      display: grid;\n      gap: 12px;\n    }\n\n    .feat-meta-grid {\n      display: grid;\n      grid-template-columns: repeat(2, minmax(0, 1fr));\n      gap: 10px;\n      margin-bottom: 0;\n    }\n\n    .feat-meta-card {\n      min-height: 74px;\n      padding: 12px 14px;\n      border: 1px solid var(--line);\n      border-radius: 16px;\n      background: rgba(255, 255, 255, 0.03);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      gap: 8px;\n      text-align: left;\n    }\n\n    .feat-meta-card.is-accent {\n      border-color: rgba(149, 40, 0, 0.24);\n      background: rgba(149, 40, 0, 0.08);\n    }\n\n    .feat-meta-label {\n      display: block;\n      color: var(--copy-soft);\n      font-size: 11px;\n      font-weight: 800;\n      letter-spacing: 0.12em;\n      text-transform: uppercase;\n    }\n\n    .feat-meta-value {\n      display: block;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(24px, 3.2vw, 30px);\n      line-height: 1;\n      letter-spacing: -0.05em;\n    }\n\n    .feat-board-shell {\n      width: 100%;\n      display: flex;\n      justify-content: center;\n      padding: 2px 0 4px;\n    }\n\n    .feat-board-shell.hidden {\n      display: none !important;\n    }\n\n    #rankedGamePanel #rankedBoardShell {\n      display: none;\n    }\n\n    #rankedGamePanel #rankedBoardShell.is-visible {\n      display: flex !important;\n    }\n\n    .feat-circle {\n      position: relative;\n      width: 320px;\n      height: 320px;\n    }\n\n    .feat-center-slot {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      transform: translate(-50%, -62%);\n      z-index: 10;\n    }\n\n    .feat-hint-slot {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      width: 76px;\n      height: 76px;\n      margin-left: -38px;\n      margin-top: -38px;\n      transition: transform 360ms cubic-bezier(.22,1,.36,1), opacity 220ms ease;\n    }\n\n    .feat-node {\n      width: 100%;\n      height: 100%;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      gap: 5px;\n      padding: 8px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      border-radius: 18px;\n      background: rgba(255, 255, 255, 0.04);\n      text-align: center;\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n    }\n\n    .feat-node.is-center {\n      width: 92px;\n      height: 92px;\n      padding: 10px;\n      border-radius: 24px;\n      background: rgba(255, 255, 255, 0.05);\n      border-color: rgba(255, 255, 255, 0.12);\n    }\n\n    .feat-node.is-center.is-won {\n      border-color: rgba(125, 197, 106, 0.42);\n    }\n\n    .feat-node.is-center.is-lost {\n      border-color: rgba(255, 126, 89, 0.42);\n    }\n\n    .feat-node.is-important {\n      border-color: rgba(241, 108, 29, 0.28);\n      background: rgba(241, 108, 29, 0.08);\n    }\n\n    .feat-avatar {\n      width: 34px;\n      height: 34px;\n      flex: 0 0 34px;\n      aspect-ratio: 1 \/ 1;\n      border-radius: 50%;\n      overflow: hidden;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background:\n        radial-gradient(circle at 32% 28%, rgba(241, 108, 29, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(241, 108, 29, 0.16), rgba(255, 255, 255, 0.03));\n      color: var(--white);\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: 14px;\n      font-weight: 700;\n      letter-spacing: -0.04em;\n      text-transform: uppercase;\n    }\n\n    .feat-avatar img {\n      width: 100%;\n      height: 100%;\n      object-fit: cover;\n      display: block;\n    }\n\n    .feat-avatar.is-mystery {\n      font-size: 18px;\n      background: rgba(255, 255, 255, 0.08);\n    }\n\n    .feat-node.is-center .feat-avatar {\n      width: 40px;\n      height: 40px;\n      flex-basis: 40px;\n      font-size: 16px;\n    }\n\n    .feat-label {\n      max-width: 100%;\n      color: var(--white);\n      font-size: 9px;\n      line-height: 1.15;\n      font-weight: 700;\n      text-align: center;\n      white-space: nowrap;\n      overflow: hidden;\n      text-overflow: ellipsis;\n    }\n\n    .feat-node.is-center .feat-label {\n      font-size: 10px;\n    }\n\n    .feat-node.is-center .feat-label,\n    .feat-node.is-center .feat-index {\n      white-space: normal;\n      overflow: visible;\n      text-overflow: clip;\n      max-width: 100%;\n      word-break: break-word;\n      overflow-wrap: anywhere;\n    }\n\n    .feat-index {\n      color: var(--copy-soft);\n      font-size: 8px;\n      line-height: 1;\n      font-weight: 700;\n    }\n\n    .input-grid {\n      display: grid;\n      grid-template-columns: 152px minmax(0, 1fr) 152px 152px;\n      gap: 10px;\n      align-items: stretch;\n      width: 100%;\n      margin: 0 auto;\n    }\n\n    .attempts-card {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      border: 1px solid #fff;\n      background: #fff;\n      color: #111;\n      text-align: center;\n      white-space: nowrap;\n    }\n\n    .action-slot {\n      width: 152px;\n      min-width: 152px;\n      align-self: stretch;\n    }\n\n    .input-shell {\n      position: relative;\n      z-index: 4;\n      min-width: 0;\n    }\n\n    .input-label {\n      display: none;\n    }\n\n    .search-field {\n      width: 100%;\n      min-height: 56px;\n      height: 56px;\n      padding: 0 16px;\n      border-radius: 12px;\n      border: 1px solid rgba(255, 255, 255, 0.1);\n      background: #101010;\n      color: var(--white);\n      font-size: 15px;\n      outline: none;\n      transition: border-color var(--ease), background var(--ease), opacity var(--ease);\n    }\n\n    .search-field:focus {\n      border-color: rgba(255, 255, 255, 0.18);\n      background: #111;\n    }\n\n    .search-field::placeholder {\n      color: var(--copy-faint);\n    }\n\n    .search-field:disabled {\n      opacity: 0.5;\n      cursor: not-allowed;\n    }\n\n    .streak-card {\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      gap: 5px;\n      text-align: center;\n    }\n\n    .streak-main {\n      font-size: 15px;\n      line-height: 1;\n      font-weight: 700;\n    }\n\n    .streak-sub {\n      color: rgba(17, 17, 17, 0.74);\n      font-size: 11px;\n      line-height: 1.1;\n      font-weight: 700;\n      text-transform: none;\n      letter-spacing: 0;\n    }\n\n    .streak-card:not(.is-guest) {\n      cursor: default;\n    }\n\n    .streak-card:not(.is-guest):hover {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #111;\n      transform: none;\n    }\n\n    .suggestions {\n      position: fixed;\n      top: 0;\n      left: 0;\n      width: 280px;\n      max-height: min(280px, calc(100dvh - 24px));\n      overflow-y: auto;\n      z-index: 2147483001;\n      display: none;\n      padding: 6px;\n      border: 1px solid var(--line);\n      border-radius: 14px;\n      background: rgba(9, 9, 9, 0.98);\n      box-shadow: 0 22px 50px rgba(0, 0, 0, 0.55);\n      backdrop-filter: blur(12px);\n      overscroll-behavior: contain;\n      -webkit-overflow-scrolling: touch;\n    }\n\n    .suggestion {\n      width: 100%;\n      display: flex;\n      justify-content: space-between;\n      gap: 8px;\n      padding: 11px 12px;\n      border: 0;\n      border-radius: 10px;\n      background: transparent;\n      color: var(--white);\n      text-align: left;\n      cursor: pointer;\n    }\n\n    .suggestion small {\n      color: var(--copy-faint);\n      font-size: 11px;\n    }\n\n    .message {\n      display: none;\n      width: 100%;\n      margin: 0;\n      padding: 10px 12px;\n      border-radius: 999px;\n      border: 1px solid var(--line);\n      background: rgba(255, 255, 255, 0.03);\n      color: var(--copy);\n      font-size: 13px;\n      line-height: 1.45;\n      text-align: center;\n    }\n\n    .message.is-visible {\n      display: block;\n    }\n\n    .message.is-success {\n      border-color: rgba(125, 197, 106, 0.36);\n      background: rgba(125, 197, 106, 0.1);\n      color: #daf2d3;\n    }\n\n    .message.is-error,\n    .message.is-error-final {\n      border-color: rgba(255, 126, 89, 0.32);\n      background: rgba(255, 126, 89, 0.1);\n      color: #ffd7c6;\n    }\n\n    .results-list {\n      display: grid;\n      gap: 12px;\n      margin-top: 0;\n      width: 100%;\n    }\n\n    .empty-state {\n      padding: 16px;\n      border: 1px dashed rgba(255, 255, 255, 0.15);\n      border-radius: 12px;\n      color: var(--copy-soft);\n      font-size: 13px;\n      line-height: 1.5;\n      text-align: center;\n    }\n\n    .answer-card {\n      padding: 18px;\n      border: 1px solid var(--line-faint);\n      border-radius: 22px;\n      background: linear-gradient(180deg, rgba(14, 14, 14, 0.96), rgba(10, 10, 10, 0.96));\n      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n      text-align: left;\n    }\n\n    .answer-card.is-correct {\n      border-color: rgba(125, 197, 106, 0.34);\n    }\n\n    .demo-app.is-ranked-mode .feat-node.is-important {\n      border-color: rgba(149, 40, 0, 0.32);\n      background: rgba(149, 40, 0, 0.09);\n    }\n\n    .demo-app.is-ranked-mode .feat-avatar {\n      background:\n        radial-gradient(circle at 32% 28%, rgba(149, 40, 0, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(149, 40, 0, 0.16), rgba(255, 255, 255, 0.03));\n    }\n\n    .demo-app.is-ranked-mode #rankedSubmitButton.button,\n    .demo-app.is-ranked-mode #rankedSideActionButton.secondary-button.is-primary {\n      background: #952800 !important;\n      border-color: #952800 !important;\n      color: #111 !important;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .button:hover,\n    .demo-app.is-ranked-mode .feat-ranked-form .secondary-button.is-primary:hover {\n      background: #fff;\n      border-color: #fff;\n      color: #111;\n    }\n\n    .demo-app.is-ranked-mode #rankedSubmitButton.button:hover,\n    .demo-app.is-ranked-mode #rankedSideActionButton.secondary-button.is-primary:hover {\n      background: #fff !important;\n      border-color: #fff !important;\n      color: #111 !important;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .input-shell {\n      border: 2px solid #080808;\n      border-radius: 0;\n      background: #101010;\n      overflow: hidden;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .action-slot,\n    .demo-app.is-ranked-mode .feat-ranked-form .button,\n    .demo-app.is-ranked-mode .feat-ranked-form .secondary-button {\n      position: relative;\n      z-index: 8;\n      pointer-events: auto;\n      touch-action: manipulation;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .search-field {\n      border: 0;\n      border-radius: 0;\n      background: transparent;\n      box-shadow: none;\n      transition: none;\n      appearance: none;\n      -webkit-appearance: none;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .search-field:focus {\n      background: transparent;\n      box-shadow: none;\n      border-color: transparent;\n    }\n\n    .demo-app.is-ranked-mode .feat-ranked-form .search-field::placeholder {\n      color: rgba(247, 244, 239, 0.18);\n      opacity: 1;\n    }\n\n    .demo-app.is-ranked-mode .message.is-error,\n    .demo-app.is-ranked-mode .message.is-error-final {\n      border-color: rgba(149, 40, 0, 0.32);\n      background: rgba(149, 40, 0, 0.1);\n      color: #ffd7b5;\n    }\n\n    .ranked-summary-panel {\n      margin-top: 0;\n      padding: 16px;\n      border: 1px solid rgba(149, 40, 0, 0.28);\n      border-radius: 18px;\n      background: rgba(149, 40, 0, 0.08);\n    }\n\n    .ranked-summary-panel.hidden {\n      display: none;\n    }\n\n    .ranked-summary-panel.is-record {\n      border-color: rgba(125, 197, 106, 0.32);\n      background: rgba(125, 197, 106, 0.08);\n    }\n\n    .ranked-summary-title {\n      margin: 0 0 10px;\n      color: #fff;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(22px, 4vw, 28px);\n      line-height: 1;\n      letter-spacing: -0.04em;\n      font-weight: 800;\n    }\n\n    .ranked-summary-lines {\n      display: grid;\n      gap: 5px;\n    }\n\n    .ranked-summary-line {\n      color: var(--white);\n      font-size: 14px;\n      line-height: 1.5;\n      font-weight: 600;\n    }\n\n    .ranked-summary-line strong {\n      font-weight: 800;\n    }\n\n    .answer-card-head {\n      display: grid;\n      grid-template-columns: 92px minmax(0, 1fr);\n      gap: 16px;\n      align-items: center;\n      margin-bottom: 14px;\n    }\n\n    .answer-cover {\n      position: relative;\n      width: 92px;\n      height: 92px;\n      border: 1px solid rgba(255, 255, 255, 0.12);\n      border-radius: 50%;\n      background:\n        radial-gradient(circle at 32% 28%, rgba(241, 108, 29, 0.34), transparent 44%),\n        linear-gradient(145deg, rgba(241, 108, 29, 0.16), rgba(255, 255, 255, 0.03));\n      overflow: hidden;\n      box-shadow: 0 18px 34px rgba(0, 0, 0, 0.34);\n    }\n\n    .answer-cover img {\n      width: 100%;\n      height: 100%;\n      object-fit: cover;\n      display: block;\n    }\n\n    .answer-cover-fallback {\n      width: 100%;\n      height: 100%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      color: var(--white);\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: 28px;\n      font-weight: 700;\n      letter-spacing: -0.04em;\n      text-transform: uppercase;\n    }\n\n    .answer-copy {\n      min-width: 0;\n      display: flex;\n      flex-direction: column;\n      gap: 10px;\n      align-items: flex-start;\n    }\n\n    .answer-badge {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      min-height: 28px;\n      padding: 0 12px;\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      color: var(--copy-soft);\n      font-size: 11px;\n      font-weight: 700;\n    }\n\n    .answer-name {\n      margin: 0;\n      font-family: \"Space Grotesk\", sans-serif;\n      font-size: clamp(28px, 4vw, 34px);\n      line-height: 1;\n      letter-spacing: -0.04em;\n    }\n\n    .answer-sub {\n      margin: -2px 0 0;\n      color: var(--copy-soft);\n      font-size: 12px;\n      line-height: 1.45;\n    }\n\n    .answer-stats {\n      display: grid;\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n      gap: 8px;\n    }\n\n    .answer-stat {\n      min-height: 90px;\n      padding: 12px 10px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      border-radius: 14px;\n      background: rgba(255, 255, 255, 0.04);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      align-items: center;\n      text-align: center;\n    }\n\n    .answer-stat-label {\n      display: block;\n      color: var(--white);\n      opacity: 0.92;\n      font-size: 12px;\n      font-weight: 700;\n    }\n\n    .answer-stat-value {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      font-size: clamp(15px, 1.8vw, 18px);\n      line-height: 1.06;\n      font-weight: 800;\n      letter-spacing: -0.03em;\n      text-align: center;\n    }\n\n    .feat-embed-shell {\n      margin-top: 12px;\n      padding-top: 12px;\n      border-top: 1px solid var(--line);\n    }\n\n    .feat-embed-shell::after {\n      content: \"\";\n      display: block;\n      margin-top: 12px;\n      border-top: 1px solid var(--line);\n    }\n\n    .feat-embed-shell iframe {\n      width: 100%;\n      min-height: 152px;\n      border: 0;\n      border-radius: 16px;\n      background: #0b0b0b;\n    }\n\n    .feat-tip {\n      margin-top: 12px;\n      color: var(--white);\n      font-size: 15px;\n      line-height: 1.55;\n    }\n\n    .hidden {\n      display: none !important;\n    }\n\n    @media (max-width: 720px) {\n      .demo-app {\n        width: 100%;\n        max-width: 100%;\n        padding: max(6px, env(safe-area-inset-top, 0px)) 4px calc(10px + env(safe-area-inset-bottom, 0px));\n      }\n\n      .app-shell {\n        display: flex;\n        flex-direction: column;\n        padding: 8px 6px 10px;\n        border: 0;\n        border-radius: 0;\n        background: transparent;\n        box-shadow: none;\n      }\n\n      .app-shell::after {\n        display: none;\n      }\n\n      .controls-shell {\n        order: 1;\n        position: relative;\n        border-top: 0;\n        border-bottom: 1px solid var(--line);\n        padding-top: 10px;\n        padding-bottom: 20px;\n      }\n\n      .controls-shell::after {\n        content: \"Gioca\";\n        position: absolute;\n        left: 50%;\n        bottom: -11px;\n        transform: translateX(-50%) translateY(-2px);\n        padding: 0 14px;\n        background: var(--bg);\n        color: #9E9E9E;\n        font-size: 15px;\n        line-height: 1;\n      }\n\n      .topbar {\n        order: 2;\n        padding: 12px 4px 4px;\n      }\n\n      .top-logo {\n        width: min(260px, 66vw);\n      }\n\n      .shell {\n        order: 3;\n        border-top: 0;\n        padding-top: 14px;\n      }\n\n      .help-panel-mobile-slot {\n        display: block;\n      }\n\n      .controls-shell .help-panel.is-open {\n        margin: 10px 0 0;\n        padding-bottom: 0;\n        border-bottom-color: transparent;\n      }\n\n      .tab-ranked-mobile {\n        display: inline-flex;\n      }\n\n      .controls-inner .tab-ranked-mobile {\n        display: inline-flex !important;\n        width: 100%;\n      }\n\n      .input-grid {\n        grid-template-columns: repeat(2, minmax(0, 1fr));\n        gap: 8px;\n        width: 100%;\n      }\n\n      .attempts-card {\n        order: 1;\n        min-width: 0;\n        min-height: 48px;\n        height: 48px;\n        padding: 0 10px;\n        font-size: 13px;\n      }\n\n      .action-slot {\n        order: 2;\n        width: auto;\n        min-width: 0;\n      }\n\n      .input-shell {\n        grid-column: 1 \/ -1;\n        order: 3;\n      }\n\n      .input-grid > .button {\n        order: 4;\n        grid-column: 1 \/ -1;\n      }\n\n      .input-grid > .attempts-card,\n      .input-grid > .button,\n      .action-slot > .secondary-button,\n      .action-slot > .streak-card,\n      .input-grid > .action-slot {\n        width: 100%;\n        min-width: 0;\n        min-height: 48px;\n        height: 48px;\n      }\n\n      .action-slot,\n      .attempts-card,\n      .button,\n      .secondary-button,\n      .streak-card,\n      .search-field {\n        min-width: 0;\n      }\n\n      .search-field {\n        min-height: 48px;\n        height: 48px;\n        font-size: 16px;\n      }\n\n      .feat-circle {\n        width: 284px;\n        height: 284px;\n      }\n\n      .feat-hint-slot {\n        width: 68px;\n        height: 68px;\n        margin-left: -34px;\n        margin-top: -34px;\n      }\n\n      .feat-node.is-center {\n        width: 84px;\n        height: 84px;\n        padding: 8px 6px;\n        gap: 4px;\n      }\n\n      .feat-node.is-center .feat-label {\n        font-size: 9px;\n        line-height: 1.05;\n      }\n\n      .feat-node.is-center .feat-index {\n        font-size: 7px;\n      }\n\n      .answer-card {\n        padding: 12px;\n        border-radius: 16px;\n      }\n\n      .answer-card-head {\n        grid-template-columns: 72px minmax(0, 1fr);\n        gap: 12px;\n      }\n\n      .answer-cover {\n        width: 72px;\n        height: 72px;\n      }\n\n      .answer-name {\n        font-size: clamp(20px, 7vw, 26px);\n      }\n\n      .answer-stats {\n        grid-template-columns: 1fr;\n      }\n\n      .help-grid,\n      .feat-meta-grid,\n      .answer-stats {\n        grid-template-columns: 1fr;\n      }\n    }\n\n    @media (max-width: 520px) {\n      .demo-app {\n        padding-inline: 3px;\n      }\n\n      .controls-shell {\n        padding-top: 8px;\n      }\n\n      .top-logo {\n        width: min(232px, 64vw);\n      }\n\n      .controls-inner {\n        grid-template-columns: 1fr;\n      }\n\n      .controls-inner .tab-ranked-mobile {\n        display: inline-flex !important;\n        width: 100%;\n      }\n    }\n\n    @media (max-width: 400px) {\n      .demo-app {\n        padding-inline: 2px;\n      }\n\n      .top-logo {\n        width: min(214px, 62vw);\n      }\n\n      .attempts-card,\n      .button,\n      .secondary-button,\n      .streak-main {\n        font-size: 12px;\n      }\n\n      .streak-sub {\n        font-size: 8px;\n      }\n\n      .feat-circle {\n        width: 268px;\n        height: 268px;\n      }\n\n      .feat-node.is-center {\n        width: 82px;\n        height: 82px;\n      }\n    }\n\n    @media (hover: none), (pointer: coarse) {\n      .tab:hover,\n      .ghost-button:hover,\n      .button:hover,\n      .secondary-button:hover,\n      .streak-card.is-guest:hover,\n      .suggestion:hover {\n        transform: none;\n      }\n\n      .button:hover,\n      .secondary-button.is-primary:hover,\n      .streak-card.is-guest:hover {\n        background: var(--accent);\n        border-color: var(--accent);\n        color: #111;\n      }\n\n      .secondary-button.is-muted:hover {\n        background: rgba(255, 255, 255, 0.03);\n        border-color: var(--line);\n        color: var(--white);\n      }\n\n      .button:active,\n      .secondary-button:active,\n      .streak-card.is-guest:active,\n      .tab:active,\n      .ghost-button:active,\n      .suggestion:active {\n        transform: scale(0.99);\n      }\n    }\n\n    @media (max-width: 720px) {\n      .demo-app .top-logo {\n        margin-top: 14px !important;\n      }\n\n      .demo-app .controls-inner {\n        margin-bottom: 18px !important;\n      }\n    }\n  <\/style>\n<\/head>\n<body>\n  <div class=\"demo-app\">\n    <div class=\"app-shell\">\n      <header class=\"topbar\">\n        <img decoding=\"async\" class=\"top-logo\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1.png\" alt=\"BulldogFeat\">\n      <\/header>\n\n      <section class=\"controls-shell\" aria-label=\"Controlli BulldogFeat\">\n        <div class=\"controls-inner\">\n          <button class=\"tab is-active\" data-mode=\"classic\" type=\"button\">Daily<\/button>\n          <button class=\"tab\" data-mode=\"practice\" type=\"button\">Allenamento<\/button>\n          <button id=\"rankedModeButton\" class=\"tab tab-ranked-mobile\" type=\"button\">Classificata<\/button>\n          <button id=\"helpToggle\" class=\"ghost-button\" type=\"button\">Come si gioca<\/button>\n        <\/div>\n        <div id=\"helpPanelMobileSlot\" class=\"help-panel-mobile-slot\"><\/div>\n      <\/section>\n\n      <main class=\"shell\">\n        <section class=\"game-shell\">\n          <section id=\"helpPanel\" class=\"help-panel\" aria-hidden=\"true\">\n            <div class=\"help-grid\">\n              <div class=\"help-card\">\n                <strong>Obiettivo<\/strong>\n                <span>Trova il rapper segreto partendo dalle sue collaborazioni.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Centro<\/strong>\n                <span>Al centro vedi il tipo dell'artista corretto: Rapper, Producer, Gruppo o Duo.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Feat<\/strong>\n                <span>Ogni errore svela un nuovo feat. Le ultime 2 carte evidenziate sono le collaborazioni piu forti.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Daily<\/strong>\n                <span>Hai 5 tentativi. La partita del giorno si salva in locale.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Allenamento<\/strong>\n                <span>Puoi cambiare artista quando vuoi con NUOVO e continuare a fare pratica.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Progressione<\/strong>\n                <span>Parti da 1 feat visibile. Ogni errore ne sblocca un altro.<\/span>\n              <\/div>\n            <\/div>\n          <\/section>\n\n          <section id=\"rankedHelpPanel\" class=\"help-panel hidden\" aria-hidden=\"true\">\n            <div class=\"help-grid\">\n              <div class=\"help-card\">\n                <strong>Timer<\/strong>\n                <span>Hai 2 minuti per fare il punteggio piu alto possibile.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Punti<\/strong>\n                <span>Ogni rapper corretto vale 1 punto e aggiunge 15 secondi.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Skip<\/strong>\n                <span>Puoi saltare il round corrente, ma perdi 15 secondi.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Tentativi<\/strong>\n                <span>Hai 5 tentativi per round. Se li finisci, passi al successivo.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Reveal<\/strong>\n                <span>L'artista corretto del round chiuso resta come indizio iniziale del round dopo.<\/span>\n              <\/div>\n              <div class=\"help-card\">\n                <strong>Record<\/strong>\n                <span>Il punteggio migliore viene salvato nella classifica mensile della classificata.<\/span>\n              <\/div>\n            <\/div>\n          <\/section>\n\n          <section id=\"standardGamePanel\" class=\"feat-panel\">\n            <div id=\"gameMsg\" class=\"message\" aria-live=\"polite\"><\/div>\n\n            <div id=\"resultsList\" class=\"results-list\">\n            <\/div>\n\n            <div class=\"feat-board-shell\">\n              <div class=\"feat-circle\">\n                <div id=\"centerArtist\" class=\"feat-center-slot\"><\/div>\n                <div id=\"hint-0\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-1\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-2\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-3\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"hint-4\" class=\"feat-hint-slot\"><\/div>\n              <\/div>\n            <\/div>\n\n            <form id=\"guessForm\" class=\"input-grid\" autocomplete=\"off\">\n              <div id=\"attemptsCard\" class=\"attempts-card\" aria-live=\"polite\">5 TENTATIVI<\/div>\n\n              <div class=\"input-shell\">\n                <label id=\"inputLabel\" class=\"input-label\" for=\"artistInput\">inserisci un artista<\/label>\n                <input id=\"artistInput\" class=\"search-field\" type=\"text\" placeholder=\"inserisci un artista\" aria-describedby=\"gameMsg\">\n                <div id=\"suggestions\" class=\"suggestions\" role=\"listbox\" aria-label=\"Suggerimenti artisti\"><\/div>\n              <\/div>\n\n              <button id=\"submitButton\" class=\"button\" type=\"submit\">PROVA<\/button>\n\n              <div class=\"action-slot\">\n                <button id=\"modeActionButton\" class=\"secondary-button is-primary hidden\" type=\"button\">NUOVO<\/button>\n                <a id=\"dailyStreakCard\" class=\"streak-card hidden is-guest\" href=\"https:\/\/bulldogmusik.it\/account-login\/\" aria-label=\"Accedi per salvare la streak\">\n                  <span id=\"dailyStreakMain\" class=\"streak-main\">STREAK<\/span>\n                  <span id=\"dailyStreakSub\" class=\"streak-sub\">Accedi per salvarla<\/span>\n                <\/a>\n              <\/div>\n            <\/form>\n          <\/section>\n\n          <section id=\"rankedGamePanel\" class=\"feat-ranked-panel hidden\">\n            <section class=\"feat-meta-grid\" aria-label=\"Statistiche Classificata\">\n              <article class=\"feat-meta-card is-accent\">\n                <span class=\"feat-meta-label\">Tempo<\/span>\n                <strong id=\"rankedTimerValue\" class=\"feat-meta-value\">2:00<\/strong>\n              <\/article>\n              <article class=\"feat-meta-card\">\n                <span class=\"feat-meta-label\">Punti<\/span>\n                <strong id=\"rankedScoreValue\" class=\"feat-meta-value\">0<\/strong>\n              <\/article>\n            <\/section>\n\n            <section id=\"rankedSummaryPanel\" class=\"ranked-summary-panel hidden\" aria-live=\"polite\">\n              <h3 id=\"rankedSummaryTitle\" class=\"ranked-summary-title\">Partita conclusa<\/h3>\n              <div id=\"rankedSummaryLines\" class=\"ranked-summary-lines\"><\/div>\n            <\/section>\n\n            <div id=\"rankedGameMsg\" class=\"message\" aria-live=\"polite\"><\/div>\n\n            <div id=\"rankedResultsList\" class=\"results-list\">\n            <\/div>\n\n            <div id=\"rankedBoardShell\" class=\"feat-board-shell hidden\">\n              <div class=\"feat-circle\">\n                <div id=\"rankedCenterArtist\" class=\"feat-center-slot\"><\/div>\n                <div id=\"ranked-hint-0\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-1\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-2\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-3\" class=\"feat-hint-slot\"><\/div>\n                <div id=\"ranked-hint-4\" class=\"feat-hint-slot\"><\/div>\n              <\/div>\n            <\/div>\n\n            <form id=\"rankedGuessForm\" class=\"input-grid feat-ranked-form\" autocomplete=\"off\">\n              <div id=\"rankedAttemptsCard\" class=\"attempts-card\" aria-live=\"polite\">5 TENTATIVI<\/div>\n\n              <div class=\"input-shell\">\n                <input id=\"rankedArtistInput\" class=\"search-field\" type=\"text\" placeholder=\"inserisci un artista\" aria-describedby=\"rankedGameMsg\">\n                <div id=\"rankedSuggestions\" class=\"suggestions\" role=\"listbox\" aria-label=\"Suggerimenti artisti classificata\"><\/div>\n              <\/div>\n\n              <button id=\"rankedSubmitButton\" class=\"button\" type=\"submit\">PROVA<\/button>\n\n              <div class=\"action-slot\">\n                <button id=\"rankedSideActionButton\" class=\"secondary-button is-primary\" type=\"button\" data-action=\"start\">INIZIA<\/button>\n              <\/div>\n            <\/form>\n          <\/section>\n        <\/section>\n      <\/main>\n    <\/div>\n  <\/div>\n\n  <script>\n    (async function () {\n      const bootstrapScript = document.currentScript;\n\n      async function loadScriptSource(src) {\n        return new Promise((resolve) => {\n          const existing = Array.from(document.querySelectorAll(\"script[src]\")).find((node) => node.src === src);\n          if (existing && Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n            resolve(true);\n            return;\n          }\n\n          const script = document.createElement(\"script\");\n          script.src = src;\n          script.async = false;\n          script.onload = () => resolve(true);\n          script.onerror = () => resolve(false);\n          document.head.appendChild(script);\n        });\n      }\n\n      async function ensureArtistsLoaded() {\n        if (Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n          return window.bulldogleArtists;\n        }\n\n        const sources = [\n          \".\/artists.js\",\n          \"artists.js\",\n          \"\/bulldogle\/artists.js?v=31\"\n        ];\n\n        if (window.location && \/^https?:\/i.test(window.location.protocol) && window.location.origin) {\n          sources.push(window.location.origin + \"\/bulldogle\/artists.js?v=31\");\n        }\n\n        sources.push(\"https:\/\/bulldogmusik.it\/bulldogle\/artists.js?v=31\");\n\n        for (const source of sources) {\n          const loaded = await loadScriptSource(source);\n          if (loaded && Array.isArray(window.bulldogleArtists) && window.bulldogleArtists.length) {\n            return window.bulldogleArtists;\n          }\n        }\n\n        return [];\n      }\n\n      const artistsSource = await ensureArtistsLoaded();\n      const featConfig = window.bulldogleFeatConfig || {};\n      const rankedConfig = window.bulldogleRankedConfig || {};\n      const guestLoginUrl = \"https:\/\/bulldogmusik.it\/account-login\/\";\n      const MAX_ATTEMPTS = 5;\n      const CLASSIC_LOGO_URL = \"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogFeat-Logo-1.png\";\n      const RANKED_LOGO_URL = \"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Feat-Classificato.png\";\n      const RANKED_ATTEMPTS = 5;\n      const RANKED_INITIAL_TIME = 120;\n      const RANKED_CORRECT_BONUS = 15;\n      const RANKED_SKIP_PENALTY = 15;\n      const RANKED_ROUND_TRANSITION_MS = 1000;\n      const RANKED_GAME_KEY = \"feat\";\n      const hasRankedBackend = Boolean(rankedConfig && rankedConfig.ajaxUrl && rankedConfig.nonce);\n      const spotifyThumbStorageKey = \"bulldogfeat-spotify-thumbs-v1\";\n\n      const demoRoots = Array.from(document.querySelectorAll(\".demo-app\"));\n      const appRoot = bootstrapScript &&\n        bootstrapScript.previousElementSibling &&\n        bootstrapScript.previousElementSibling.classList &&\n        bootstrapScript.previousElementSibling.classList.contains(\"demo-app\")\n          ? bootstrapScript.previousElementSibling\n          : demoRoots[demoRoots.length - 1];\n\n      if (!appRoot) return;\n\n      const elements = {\n        topLogo: appRoot.querySelector(\".top-logo\"),\n        tabs: Array.from(appRoot.querySelectorAll(\".tab[data-mode]\")),\n        rankedModeButton: appRoot.querySelector(\"#rankedModeButton\"),\n        helpToggle: appRoot.querySelector(\"#helpToggle\"),\n        helpPanel: appRoot.querySelector(\"#helpPanel\"),\n        rankedHelpPanel: appRoot.querySelector(\"#rankedHelpPanel\"),\n        helpPanelMobileSlot: appRoot.querySelector(\"#helpPanelMobileSlot\"),\n        standardGamePanel: appRoot.querySelector(\"#standardGamePanel\"),\n        rankedGamePanel: appRoot.querySelector(\"#rankedGamePanel\"),\n        attemptsCard: appRoot.querySelector(\"#attemptsCard\"),\n        guessForm: appRoot.querySelector(\"#guessForm\"),\n        input: appRoot.querySelector(\"#artistInput\"),\n        suggestions: appRoot.querySelector(\"#suggestions\"),\n        submitButton: appRoot.querySelector(\"#submitButton\"),\n        modeActionButton: appRoot.querySelector(\"#modeActionButton\"),\n        dailyStreakCard: appRoot.querySelector(\"#dailyStreakCard\"),\n        dailyStreakMain: appRoot.querySelector(\"#dailyStreakMain\"),\n        dailyStreakSub: appRoot.querySelector(\"#dailyStreakSub\"),\n        message: appRoot.querySelector(\"#gameMsg\"),\n        resultsList: appRoot.querySelector(\"#resultsList\"),\n        centerArtist: appRoot.querySelector(\"#centerArtist\"),\n        hints: Array.from({ length: 5 }, (_, index) => appRoot.querySelector(\"#hint-\" + index)),\n        rankedTimerValue: appRoot.querySelector(\"#rankedTimerValue\"),\n        rankedScoreValue: appRoot.querySelector(\"#rankedScoreValue\"),\n        rankedAttemptsCard: appRoot.querySelector(\"#rankedAttemptsCard\"),\n        rankedGuessForm: appRoot.querySelector(\"#rankedGuessForm\"),\n        rankedInput: appRoot.querySelector(\"#rankedArtistInput\"),\n        rankedSuggestions: appRoot.querySelector(\"#rankedSuggestions\"),\n        rankedSubmitButton: appRoot.querySelector(\"#rankedSubmitButton\"),\n        rankedSideActionButton: appRoot.querySelector(\"#rankedSideActionButton\"),\n        rankedSummaryPanel: appRoot.querySelector(\"#rankedSummaryPanel\"),\n        rankedSummaryTitle: appRoot.querySelector(\"#rankedSummaryTitle\"),\n        rankedSummaryLines: appRoot.querySelector(\"#rankedSummaryLines\"),\n        rankedMessage: appRoot.querySelector(\"#rankedGameMsg\"),\n        rankedResultsList: appRoot.querySelector(\"#rankedResultsList\"),\n        rankedBoardShell: appRoot.querySelector(\"#rankedBoardShell\"),\n        rankedCenterArtist: appRoot.querySelector(\"#rankedCenterArtist\"),\n        rankedHints: Array.from({ length: 5 }, (_, index) => appRoot.querySelector(\"#ranked-hint-\" + index))\n      };\n\n      if (!elements.guessForm || !elements.input || !elements.submitButton || !elements.suggestions) {\n        return;\n      }\n\n      const desktopHelpPanelParent = elements.helpPanel ? elements.helpPanel.parentElement : null;\n      const desktopHelpPanelNextSibling = elements.helpPanel ? elements.helpPanel.nextElementSibling : null;\n      const desktopRankedHelpPanelParent = elements.rankedHelpPanel ? elements.rankedHelpPanel.parentElement : null;\n      const desktopRankedHelpPanelNextSibling = elements.rankedHelpPanel ? elements.rankedHelpPanel.nextElementSibling : null;\n\n      if (elements.suggestions.parentElement !== document.body) {\n        document.body.appendChild(elements.suggestions);\n      }\n      if (elements.rankedSuggestions && elements.rankedSuggestions.parentElement !== document.body) {\n        document.body.appendChild(elements.rankedSuggestions);\n      }\n\n      const spotifyThumbCache = new Map();\n      const spotifyThumbRequests = new Map();\n      let messageTimeoutId = 0;\n      let streakLoading = false;\n      let rankedMessageTimeoutId = 0;\n\n      try {\n        const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n        Object.keys(storedThumbs).forEach((spotifyId) => {\n          if (storedThumbs[spotifyId]) {\n            spotifyThumbCache.set(spotifyId, String(storedThumbs[spotifyId]));\n          }\n        });\n      } catch (_) {}\n\n      const artists = artistsSource.map((artist) => ({\n        id: Number(artist.id),\n        name: String(artist.name || \"\").trim(),\n        city: String(artist.city || \"\").trim(),\n        region: String(artist.region || \"\").trim(),\n        debutYear: Number(artist.debutYear || 0),\n        members: String(artist.members || \"\").trim(),\n        popularity: String(artist.popularity || \"\").trim(),\n        spotifyId: String(artist.spotifyId || \"\").trim(),\n        collab: String(artist.collab || \"\").trim(),\n        collabmid: String(artist.collabmid || \"\").trim(),\n        tip: String(artist.tip || \"\").trim()\n      })).filter((artist) => artist.id && artist.name);\n\n      const validArtists = artists.filter((artist) => {\n        const midCount = splitList(artist.collabmid).length;\n        const collabCount = splitList(artist.collab).length;\n        return midCount >= 3 && (midCount + collabCount) >= 5;\n      });\n\n      if (!validArtists.length) {\n        setMessage(\"Nessun artista valido trovato per BulldogFeat.\", \"error-final\");\n        disableInput(true);\n        return;\n      }\n\n      const italyDateInfo = getItalyDateInfo();\n      const dailyStorageKey = \"bulldogle_feat_\" + italyDateInfo.dayKey;\n      const localRankedBestKey = \"bulldogle_feat_ranked_best\";\n\n      const app = {\n        mode: \"classic\",\n        modes: {\n          classic: createGameState(pickDailyTarget()),\n          practice: createGameState(pickRandomValidArtist())\n        },\n        ranked: {\n          active: false,\n          preparing: false,\n          submitting: false,\n          complete: false,\n          betweenRounds: false,\n          sessionToken: \"\",\n          currentArtist: null,\n          hints: [],\n          revealedHints: 1,\n          roundAttempts: 0,\n          roundGuessedIds: new Set(),\n          usedTargetIds: new Set(),\n          score: 0,\n          timeLeft: RANKED_INITIAL_TIME,\n          results: [],\n          timerId: 0,\n          roundTransitionId: 0,\n          summaryTitle: \"Partita conclusa\",\n          summaryLines: [],\n          isRecord: false,\n          lastRoundSolved: false\n        }\n      };\n\n      function createGameState(targetArtist) {\n        return {\n          target: targetArtist,\n          hints: buildHintSet(targetArtist),\n          attempts: 0,\n          revealedHints: 1,\n          guessedIds: new Set(),\n          complete: false,\n          status: \"playing\"\n        };\n      }\n\n      function normalize(value) {\n        return String(value || \"\").trim().toLowerCase();\n      }\n\n      function splitList(value) {\n        return String(value || \"\")\n          .split(\",\")\n          .map((entry) => entry.trim())\n          .filter(Boolean);\n      }\n\n      function hashString(value) {\n        let hash = 2166136261;\n        for (let index = 0; index < value.length; index++) {\n          hash ^= value.charCodeAt(index);\n          hash = Math.imul(hash, 16777619);\n        }\n        return hash >>> 0;\n      }\n\n      function createSeededRandom(seed) {\n        let randomState = seed >>> 0;\n        return function () {\n          randomState += 0x6D2B79F5;\n          let value = Math.imul(randomState ^ (randomState >>> 15), 1 | randomState);\n          value ^= value + Math.imul(value ^ (value >>> 7), 61 | value);\n          return ((value ^ (value >>> 14)) >>> 0) \/ 4294967296;\n        };\n      }\n\n      function shuffle(array, randomFn) {\n        const next = array.slice();\n        for (let index = next.length - 1; index > 0; index--) {\n          const swapIndex = Math.floor(randomFn() * (index + 1));\n          const temp = next[index];\n          next[index] = next[swapIndex];\n          next[swapIndex] = temp;\n        }\n        return next;\n      }\n\n      function getItalyDateInfo() {\n        const formatter = new Intl.DateTimeFormat(\"en-CA\", {\n          timeZone: \"Europe\/Rome\",\n          year: \"numeric\",\n          month: \"2-digit\",\n          day: \"2-digit\"\n        });\n\n        const parts = formatter.formatToParts(new Date());\n        const year = Number(parts.find((part) => part.type === \"year\").value);\n        const month = Number(parts.find((part) => part.type === \"month\").value);\n        const day = Number(parts.find((part) => part.type === \"day\").value);\n\n        return {\n          dayKey: year + \"-\" + String(month).padStart(2, \"0\") + \"-\" + String(day).padStart(2, \"0\")\n        };\n      }\n\n      function formatTime(totalSeconds) {\n        const safeTime = Math.max(0, Number(totalSeconds || 0));\n        const minutes = Math.floor(safeTime \/ 60);\n        const seconds = String(safeTime % 60).padStart(2, \"0\");\n        return minutes + \":\" + seconds;\n      }\n\n      function findArtistByName(name) {\n        const normalized = normalize(name);\n        return artists.find((artist) => normalize(artist.name) === normalized);\n      }\n\n      function findArtistById(id) {\n        return artists.find((artist) => artist.id === id);\n      }\n\n      function pickDailyTarget() {\n        const random = createSeededRandom(hashString(\"feat|\" + italyDateInfo.dayKey));\n        const index = Math.floor(random() * validArtists.length);\n        return validArtists[index] || validArtists[0];\n      }\n\n      function pickRandomValidArtist(excludedIds) {\n        const blocked = excludedIds || new Set();\n        let pool = validArtists.filter((artist) => !blocked.has(artist.id));\n        if (!pool.length) {\n          pool = validArtists.slice();\n        }\n        return pool[Math.floor(Math.random() * pool.length)];\n      }\n\n      function buildHintSet(targetArtist) {\n        const usedIds = new Set([targetArtist.id]);\n        const hints = [];\n\n        addHintsFromNames(splitList(targetArtist.collabmid), 3, \"collabmid\");\n        addHintsFromNames(splitList(targetArtist.collab), 2, \"collab\");\n\n        if (hints.length < 5) {\n          const fallback = shuffle(\n            artists.filter((artist) => !usedIds.has(artist.id)),\n            Math.random\n          );\n\n          for (const artist of fallback) {\n            if (hints.length >= 5) break;\n            hints.push({ artist: artist, source: \"fallback\" });\n            usedIds.add(artist.id);\n          }\n        }\n\n        return hints.slice(0, 5);\n\n        function addHintsFromNames(names, limit, source) {\n          const pool = shuffle(Array.from(new Set(names)), Math.random);\n          for (const name of pool) {\n            if (hints.filter((hint) => hint.source === source).length >= limit || hints.length >= 5) {\n              break;\n            }\n            const artist = findArtistByName(name);\n            if (!artist || usedIds.has(artist.id)) {\n              continue;\n            }\n            hints.push({ artist: artist, source: source });\n            usedIds.add(artist.id);\n          }\n        }\n      }\n\n      function serializeHints(hints) {\n        return hints.map((hint) => ({\n          id: hint.artist.id,\n          source: hint.source\n        }));\n      }\n\n      function restoreHints(savedHints) {\n        if (!Array.isArray(savedHints) || savedHints.length !== 5) {\n          return null;\n        }\n\n        const restored = [];\n        const usedIds = new Set();\n        for (const savedHint of savedHints) {\n          const artist = findArtistById(Number(savedHint.id));\n          if (!artist || usedIds.has(artist.id)) {\n            return null;\n          }\n          restored.push({ artist: artist, source: savedHint.source || \"fallback\" });\n          usedIds.add(artist.id);\n        }\n        return restored;\n      }\n\n      function getInitials(name) {\n        return String(name || \"\")\n          .split(\/\\s+\/)\n          .filter(Boolean)\n          .map((word) => word.charAt(0))\n          .join(\"\")\n          .slice(0, 2)\n          .toUpperCase() || \"BF\";\n      }\n\n      function persistSpotifyThumbnailUrl(spotifyId, thumbnailUrl) {\n        if (!spotifyId || !thumbnailUrl) return;\n        try {\n          const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n          storedThumbs[spotifyId] = thumbnailUrl;\n          window.localStorage.setItem(spotifyThumbStorageKey, JSON.stringify(storedThumbs));\n        } catch (_) {}\n      }\n\n      function clearSpotifyThumbnailUrl(spotifyId) {\n        if (!spotifyId) return;\n        spotifyThumbCache.delete(spotifyId);\n        spotifyThumbRequests.delete(spotifyId);\n        try {\n          const storedThumbs = JSON.parse(window.localStorage.getItem(spotifyThumbStorageKey) || \"{}\");\n          delete storedThumbs[spotifyId];\n          window.localStorage.setItem(spotifyThumbStorageKey, JSON.stringify(storedThumbs));\n        } catch (_) {}\n      }\n\n      async function getSpotifyThumbnailUrl(spotifyId) {\n        if (!spotifyId) return \"\";\n        if (spotifyThumbCache.has(spotifyId)) {\n          return spotifyThumbCache.get(spotifyId);\n        }\n        if (spotifyThumbRequests.has(spotifyId)) {\n          return spotifyThumbRequests.get(spotifyId);\n        }\n\n        const request = (async function () {\n          const sources = [\n            \"https:\/\/open.spotify.com\/oembed?url=\" + encodeURIComponent(\"https:\/\/open.spotify.com\/artist\/\" + spotifyId),\n            \"https:\/\/open.spotify.com\/oembed?url=\" + encodeURIComponent(\"spotify:artist:\" + spotifyId)\n          ];\n\n          for (const source of sources) {\n            try {\n              const response = await fetch(source, { credentials: \"omit\" });\n              if (!response.ok) continue;\n              const payload = await response.json();\n              const thumbnailUrl = payload && payload.thumbnail_url ? String(payload.thumbnail_url) : \"\";\n              if (thumbnailUrl) {\n                spotifyThumbCache.set(spotifyId, thumbnailUrl);\n                persistSpotifyThumbnailUrl(spotifyId, thumbnailUrl);\n                return thumbnailUrl;\n              }\n            } catch (_) {}\n          }\n\n          return \"\";\n        })().finally(function () {\n          spotifyThumbRequests.delete(spotifyId);\n        });\n\n        spotifyThumbRequests.set(spotifyId, request);\n        return request;\n      }\n\n      function buildAvatar(artist, mystery, sizeClass) {\n        const avatar = document.createElement(\"div\");\n        avatar.className = \"feat-avatar\" + (mystery ? \" is-mystery\" : \"\");\n        avatar.textContent = mystery ? \"?\" : getInitials(artist.name);\n\n        if (!mystery && artist.spotifyId) {\n          getSpotifyThumbnailUrl(artist.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = artist.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              avatar.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(artist.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        return avatar;\n      }\n\n      function renderCenterCard(state) {\n        elements.centerArtist.innerHTML = \"\";\n        const node = document.createElement(\"div\");\n        node.className = \"feat-node is-center\";\n\n        if (state.complete) {\n          node.classList.add(state.status === \"won\" ? \"is-won\" : \"is-lost\");\n          node.appendChild(buildAvatar(state.target, false));\n          const name = document.createElement(\"div\");\n          name.className = \"feat-label\";\n          name.textContent = state.target.name;\n          const members = document.createElement(\"div\");\n          members.className = \"feat-index\";\n          members.textContent = state.target.members || \"Artista\";\n          node.appendChild(name);\n          node.appendChild(members);\n        } else {\n          node.appendChild(buildAvatar(state.target, true));\n          const members = document.createElement(\"div\");\n          members.className = \"feat-label\";\n          members.textContent = state.target.members || \"Artista\";\n          node.appendChild(members);\n        }\n\n        elements.centerArtist.appendChild(node);\n      }\n\n      function renderHints(state) {\n        const positions = [0, 72, 144, 216, 288];\n        const radius = 105;\n\n        state.hints.forEach((hint, index) => {\n          const angle = positions[index] * (Math.PI \/ 180);\n          const x = Math.sin(angle) * radius;\n          const y = -Math.cos(angle) * radius;\n          const slot = elements.hints[index];\n          if (!slot) return;\n\n          const isRevealed = index < state.revealedHints || state.complete;\n          slot.style.transform = \"translate(\" + x + \"px, \" + y + \"px)\";\n          slot.innerHTML = \"\";\n\n          const node = document.createElement(\"div\");\n          node.className = \"feat-node\" + (index >= 3 ? \" is-important\" : \"\") + (!isRevealed ? \" is-hidden\" : \"\");\n          node.appendChild(buildAvatar(hint.artist, !isRevealed));\n\n          const label = document.createElement(\"div\");\n          label.className = \"feat-label\";\n          label.textContent = isRevealed ? hint.artist.name : \"?\";\n          node.appendChild(label);\n\n          if (!isRevealed) {\n            const number = document.createElement(\"div\");\n            number.className = \"feat-index\";\n            number.textContent = String(index + 1);\n            node.appendChild(number);\n          }\n\n          slot.appendChild(node);\n        });\n      }\n\n      function renderBoard() {\n        const state = getCurrentState();\n        renderCenterCard(state);\n        renderHints(state);\n      }\n\n      function buildAnswerCard(state, solved) {\n        const article = document.createElement(\"article\");\n        article.className = \"answer-card\" + (solved ? \" is-correct\" : \"\");\n\n        const top = document.createElement(\"div\");\n        top.className = \"answer-card-head\";\n\n        const cover = document.createElement(\"div\");\n        cover.className = \"answer-cover\";\n        const coverFallback = document.createElement(\"div\");\n        coverFallback.className = \"answer-cover-fallback\";\n        coverFallback.textContent = getInitials(state.target.name);\n        cover.appendChild(coverFallback);\n\n        if (state.target.spotifyId) {\n          getSpotifyThumbnailUrl(state.target.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = state.target.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              cover.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(state.target.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        const copy = document.createElement(\"div\");\n        copy.className = \"answer-copy\";\n\n        const badge = document.createElement(\"span\");\n        badge.className = \"answer-badge\";\n        badge.textContent = solved ? \"Hai indovinato\" : \"Artista corretto\";\n\n        const name = document.createElement(\"h3\");\n        name.className = \"answer-name\";\n        name.textContent = state.target.name;\n\n        const sub = document.createElement(\"p\");\n        sub.className = \"answer-sub\";\n        sub.textContent = (state.target.members || \"Artista\") + \" \u2022 \" + state.revealedHints + \"\/5 feat visibili\";\n\n        copy.appendChild(badge);\n        copy.appendChild(name);\n        copy.appendChild(sub);\n        top.appendChild(cover);\n        top.appendChild(copy);\n        article.appendChild(top);\n\n        const strongFeatCount = splitList(state.target.collabmid).length;\n        const allFeatCount = strongFeatCount + splitList(state.target.collab).length;\n        const stats = [\n          { label: \"Tipo\", value: state.target.members || \"Artista\" },\n          { label: \"Feat stretti\", value: String(strongFeatCount) },\n          { label: \"Feat totali\", value: String(allFeatCount) }\n        ];\n\n        const statsGrid = document.createElement(\"div\");\n        statsGrid.className = \"answer-stats\";\n        stats.forEach((stat) => {\n          const item = document.createElement(\"div\");\n          item.className = \"answer-stat\";\n          const label = document.createElement(\"span\");\n          label.className = \"answer-stat-label\";\n          label.textContent = stat.label;\n          const value = document.createElement(\"span\");\n          value.className = \"answer-stat-value\";\n          value.textContent = stat.value;\n          item.appendChild(label);\n          item.appendChild(value);\n          statsGrid.appendChild(item);\n        });\n        article.appendChild(statsGrid);\n\n        if (state.target.spotifyId) {\n          const embedShell = document.createElement(\"div\");\n          embedShell.className = \"feat-embed-shell\";\n          const iframe = document.createElement(\"iframe\");\n          iframe.loading = \"lazy\";\n          iframe.allow = \"autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture\";\n          iframe.src = \"https:\/\/open.spotify.com\/embed\/artist\/\" + state.target.spotifyId + \"?utm_source=generator&theme=0\";\n          iframe.title = \"Spotify di \" + state.target.name;\n          embedShell.appendChild(iframe);\n          article.appendChild(embedShell);\n        }\n\n        if (state.target.tip) {\n          const tip = document.createElement(\"div\");\n          tip.className = \"feat-tip\";\n          tip.textContent = state.target.tip;\n          article.appendChild(tip);\n        }\n\n        return article;\n      }\n\n      function getCurrentState() {\n        return app.modes[app.mode];\n      }\n\n      function isRankedMode() {\n        return app.mode === \"ranked\";\n      }\n\n      function renderAttempts() {\n        const state = getCurrentState();\n        const attemptsLeft = Math.max(0, MAX_ATTEMPTS - state.attempts);\n        elements.attemptsCard.textContent = attemptsLeft + \" \" + (attemptsLeft === 1 ? \"TENTATIVO\" : \"TENTATIVI\");\n      }\n\n      function renderActionSlot() {\n        const practice = app.mode === \"practice\";\n        elements.modeActionButton.classList.toggle(\"hidden\", !practice);\n        elements.dailyStreakCard.classList.toggle(\"hidden\", practice);\n        elements.dailyStreakCard.classList.toggle(\"is-guest\", !practice && !featConfig.isLoggedIn);\n      }\n\n      function renderResults() {\n        elements.resultsList.innerHTML = \"\";\n        return;\n      }\n\n      function disableInput(disabled) {\n        elements.input.disabled = disabled;\n        elements.submitButton.disabled = disabled;\n      }\n\n      function renderInputState() {\n        const state = getCurrentState();\n        const disabled = state.complete;\n        disableInput(disabled);\n        if (state.complete && app.mode === \"classic\") {\n          elements.input.placeholder = \"Torna domani!\";\n        } else {\n          elements.input.placeholder = \"inserisci un artista\";\n        }\n      }\n\n      function renderTabs() {\n        elements.tabs.forEach((tab) => {\n          tab.classList.toggle(\"is-active\", tab.dataset.mode === app.mode);\n        });\n        if (elements.rankedModeButton) {\n          elements.rankedModeButton.classList.toggle(\"is-active\", isRankedMode());\n        }\n      }\n\n      function getCurrentHelpPanel() {\n        return isRankedMode() ? elements.rankedHelpPanel : elements.helpPanel;\n      }\n\n      function closeAllHelpPanels() {\n        [elements.helpPanel, elements.rankedHelpPanel].forEach((panel) => {\n          if (!panel) return;\n          panel.classList.remove(\"is-open\");\n          panel.setAttribute(\"aria-hidden\", \"true\");\n        });\n        elements.helpToggle.classList.remove(\"is-active\");\n      }\n\n      function syncHelpToggleState() {\n        const panel = getCurrentHelpPanel();\n        elements.helpToggle.classList.toggle(\"is-active\", !!panel && panel.classList.contains(\"is-open\"));\n      }\n\n      function restorePanelPlacement(panel, parent, nextSibling) {\n        if (!panel || !parent) return;\n        if (panel.parentElement === parent) return;\n\n        if (nextSibling && nextSibling.parentElement === parent) {\n          parent.insertBefore(panel, nextSibling);\n          return;\n        }\n\n        parent.appendChild(panel);\n      }\n\n      function syncHelpPanelPlacement() {\n        if (!elements.helpPanelMobileSlot) return;\n\n        const isMobileLayout = window.matchMedia(\"(max-width: 720px)\").matches;\n        const activePanel = getCurrentHelpPanel();\n\n        if (isMobileLayout) {\n          [elements.helpPanel, elements.rankedHelpPanel].forEach((panel) => {\n            if (!panel) return;\n\n            if (panel === activePanel) {\n              if (panel.parentElement !== elements.helpPanelMobileSlot) {\n                elements.helpPanelMobileSlot.appendChild(panel);\n              }\n              return;\n            }\n\n            if (panel === elements.helpPanel) {\n              restorePanelPlacement(panel, desktopHelpPanelParent, desktopHelpPanelNextSibling);\n              return;\n            }\n\n            restorePanelPlacement(panel, desktopRankedHelpPanelParent, desktopRankedHelpPanelNextSibling);\n          });\n          return;\n        }\n\n        restorePanelPlacement(elements.helpPanel, desktopHelpPanelParent, desktopHelpPanelNextSibling);\n        restorePanelPlacement(elements.rankedHelpPanel, desktopRankedHelpPanelParent, desktopRankedHelpPanelNextSibling);\n      }\n\n      function syncHelpPanelVisibility() {\n        const rankedActive = isRankedMode();\n        if (elements.helpPanel) {\n          elements.helpPanel.classList.toggle(\"hidden\", rankedActive);\n        }\n        if (elements.rankedHelpPanel) {\n          elements.rankedHelpPanel.classList.toggle(\"hidden\", !rankedActive);\n        }\n      }\n\n      function renderBranding() {\n        const rankedActive = isRankedMode();\n        elements.topLogo.src = rankedActive ? RANKED_LOGO_URL : CLASSIC_LOGO_URL;\n        elements.topLogo.alt = rankedActive ? \"BulldogFeat Classificata\" : \"BulldogFeat\";\n        appRoot.classList.toggle(\"is-ranked-mode\", rankedActive);\n        document.body.classList.toggle(\"bulldogfeat-ranked-mode-active\", rankedActive);\n        document.documentElement.classList.toggle(\"bulldogfeat-ranked-mode-active\", rankedActive);\n      }\n\n      function renderPanels() {\n        const rankedActive = isRankedMode();\n        elements.standardGamePanel.classList.toggle(\"hidden\", rankedActive);\n        elements.rankedGamePanel.classList.toggle(\"hidden\", !rankedActive);\n        syncHelpPanelVisibility();\n        syncHelpPanelPlacement();\n      }\n\n      function renderRankedCenterCard() {\n        elements.rankedCenterArtist.innerHTML = \"\";\n        const node = document.createElement(\"div\");\n        node.className = \"feat-node is-center\";\n\n        if (app.ranked.currentArtist && (app.ranked.complete || app.ranked.betweenRounds)) {\n          node.classList.add(app.ranked.lastRoundSolved ? \"is-won\" : \"is-lost\");\n          node.appendChild(buildAvatar(app.ranked.currentArtist, false));\n          const name = document.createElement(\"div\");\n          name.className = \"feat-label\";\n          name.textContent = app.ranked.currentArtist.name;\n          const members = document.createElement(\"div\");\n          members.className = \"feat-index\";\n          members.textContent = app.ranked.currentArtist.members || \"Artista\";\n          node.appendChild(name);\n          node.appendChild(members);\n        } else if (app.ranked.currentArtist) {\n          node.appendChild(buildAvatar(app.ranked.currentArtist, true));\n          const members = document.createElement(\"div\");\n          members.className = \"feat-label\";\n          members.textContent = app.ranked.currentArtist.members || \"Artista\";\n          node.appendChild(members);\n        }\n\n        elements.rankedCenterArtist.appendChild(node);\n      }\n\n      function renderRankedHints() {\n        const positions = [0, 72, 144, 216, 288];\n        const radius = 105;\n\n        app.ranked.hints.forEach((hint, index) => {\n          const angle = positions[index] * (Math.PI \/ 180);\n          const x = Math.sin(angle) * radius;\n          const y = -Math.cos(angle) * radius;\n          const slot = elements.rankedHints[index];\n          if (!slot) return;\n\n          const isRevealed = index < app.ranked.revealedHints || app.ranked.complete || app.ranked.betweenRounds;\n          slot.style.transform = \"translate(\" + x + \"px, \" + y + \"px)\";\n          slot.innerHTML = \"\";\n\n          const node = document.createElement(\"div\");\n          node.className = \"feat-node\" + (index >= 3 ? \" is-important\" : \"\");\n          node.appendChild(buildAvatar(hint.artist, !isRevealed));\n\n          const label = document.createElement(\"div\");\n          label.className = \"feat-label\";\n          label.textContent = isRevealed ? hint.artist.name : \"?\";\n          node.appendChild(label);\n\n          if (!isRevealed) {\n            const number = document.createElement(\"div\");\n            number.className = \"feat-index\";\n            number.textContent = String(index + 1);\n            node.appendChild(number);\n          }\n\n          slot.appendChild(node);\n        });\n      }\n\n      function buildRankedAnswerCard(result) {\n        const article = document.createElement(\"article\");\n        article.className = \"answer-card\" + (result.solved ? \" is-correct\" : \"\");\n\n        const top = document.createElement(\"div\");\n        top.className = \"answer-card-head\";\n\n        const cover = document.createElement(\"div\");\n        cover.className = \"answer-cover\";\n        const coverFallback = document.createElement(\"div\");\n        coverFallback.className = \"answer-cover-fallback\";\n        coverFallback.textContent = getInitials(result.artist.name);\n        cover.appendChild(coverFallback);\n\n        if (result.artist.spotifyId) {\n          getSpotifyThumbnailUrl(result.artist.spotifyId).then((thumbnailUrl) => {\n            if (!thumbnailUrl) return;\n            const image = document.createElement(\"img\");\n            image.alt = result.artist.name;\n            image.loading = \"eager\";\n            image.decoding = \"async\";\n            image.referrerPolicy = \"no-referrer\";\n\n            function applyThumbnail() {\n              cover.replaceChildren(image);\n            }\n\n            function handleThumbnailError() {\n              clearSpotifyThumbnailUrl(result.artist.spotifyId);\n            }\n\n            image.addEventListener(\"load\", applyThumbnail, { once: true });\n            image.addEventListener(\"error\", handleThumbnailError, { once: true });\n            image.src = thumbnailUrl;\n\n            if (image.complete) {\n              if (image.naturalWidth > 0) {\n                applyThumbnail();\n              } else {\n                handleThumbnailError();\n              }\n            }\n          });\n        }\n\n        const copy = document.createElement(\"div\");\n        copy.className = \"answer-copy\";\n\n        const badge = document.createElement(\"span\");\n        badge.className = \"answer-badge\";\n        badge.textContent = result.label;\n\n        const name = document.createElement(\"h3\");\n        name.className = \"answer-name\";\n        name.textContent = result.artist.name;\n\n        const sub = document.createElement(\"p\");\n        sub.className = \"answer-sub\";\n        sub.textContent = (result.artist.members || \"Artista\") + \" \u2022 \" + result.revealedHints + \"\/5 feat visibili\";\n\n        copy.appendChild(badge);\n        copy.appendChild(name);\n        copy.appendChild(sub);\n        top.appendChild(cover);\n        top.appendChild(copy);\n        article.appendChild(top);\n\n        const strongFeatCount = splitList(result.artist.collabmid).length;\n        const allFeatCount = strongFeatCount + splitList(result.artist.collab).length;\n        const stats = [\n          { label: \"Tipo\", value: result.artist.members || \"Artista\" },\n          { label: \"Feat stretti\", value: String(strongFeatCount) },\n          { label: \"Feat totali\", value: String(allFeatCount) }\n        ];\n\n        const statsGrid = document.createElement(\"div\");\n        statsGrid.className = \"answer-stats\";\n        stats.forEach((stat) => {\n          const item = document.createElement(\"div\");\n          item.className = \"answer-stat\";\n          const label = document.createElement(\"span\");\n          label.className = \"answer-stat-label\";\n          label.textContent = stat.label;\n          const value = document.createElement(\"span\");\n          value.className = \"answer-stat-value\";\n          value.textContent = stat.value;\n          item.appendChild(label);\n          item.appendChild(value);\n          statsGrid.appendChild(item);\n        });\n        article.appendChild(statsGrid);\n\n        return article;\n      }\n\n      function renderRankedMeta() {\n        elements.rankedTimerValue.textContent = formatTime(app.ranked.timeLeft);\n        elements.rankedScoreValue.textContent = String(app.ranked.score);\n      }\n\n      function renderRankedAttempts() {\n        const attemptsLeft = Math.max(0, RANKED_ATTEMPTS - app.ranked.roundAttempts);\n        elements.rankedAttemptsCard.textContent = attemptsLeft + \" \" + (attemptsLeft === 1 ? \"TENTATIVO\" : \"TENTATIVI\");\n      }\n\n      function renderRankedInputState() {\n        const disabled = !app.ranked.active || app.ranked.betweenRounds || app.ranked.preparing || app.ranked.submitting;\n        elements.rankedInput.disabled = disabled;\n        elements.rankedSubmitButton.disabled = disabled;\n        elements.rankedInput.placeholder = app.ranked.active ? \"inserisci un artista\" : (app.ranked.complete ? \"Partita conclusa\" : \"inserisci un artista\");\n      }\n\n      function renderRankedActionButton() {\n        const button = elements.rankedSideActionButton;\n        button.className = \"secondary-button is-primary\";\n        button.disabled = false;\n\n        if (app.ranked.preparing || app.ranked.submitting) {\n          button.textContent = \"...\";\n          button.disabled = true;\n          button.dataset.action = \"wait\";\n          return;\n        }\n\n        if (app.ranked.active) {\n          if (app.ranked.betweenRounds) {\n            button.textContent = \"ATTENDI\";\n            button.disabled = true;\n            button.dataset.action = \"wait\";\n            return;\n          }\n          button.textContent = \"SKIP\";\n          button.dataset.action = \"skip\";\n          return;\n        }\n\n        if (app.ranked.complete) {\n          button.textContent = \"RIGIOCA\";\n          button.dataset.action = \"restart\";\n          return;\n        }\n\n        if (hasRankedBackend && !rankedConfig.isLoggedIn) {\n          button.textContent = \"ACCEDI\";\n          button.dataset.action = \"login\";\n          return;\n        }\n\n        button.textContent = \"INIZIA\";\n        button.dataset.action = \"start\";\n      }\n\n      function renderRankedSummary() {\n        elements.rankedSummaryPanel.classList.toggle(\"hidden\", !app.ranked.complete || !app.ranked.summaryLines.length);\n        elements.rankedSummaryPanel.classList.toggle(\"is-record\", app.ranked.isRecord);\n        elements.rankedSummaryTitle.textContent = app.ranked.summaryTitle || \"Partita conclusa\";\n        elements.rankedSummaryLines.innerHTML = \"\";\n\n        app.ranked.summaryLines.forEach((line) => {\n          const row = document.createElement(\"div\");\n          row.className = \"ranked-summary-line\";\n          row.innerHTML = line;\n          elements.rankedSummaryLines.appendChild(row);\n        });\n      }\n\n      function renderRankedResults() {\n        elements.rankedResultsList.innerHTML = \"\";\n        return;\n      }\n\n      function renderRankedBoard() {\n        const boardVisible = app.ranked.active || app.ranked.complete || app.ranked.betweenRounds;\n        elements.rankedBoardShell.classList.toggle(\"hidden\", !boardVisible);\n        elements.rankedBoardShell.classList.toggle(\"is-visible\", boardVisible);\n        renderRankedCenterCard();\n        renderRankedHints();\n      }\n\n      function renderRankedPanel() {\n        renderRankedMeta();\n        renderRankedAttempts();\n        renderRankedInputState();\n        renderRankedActionButton();\n        renderRankedSummary();\n        renderRankedBoard();\n        renderRankedResults();\n        hideRankedSuggestions();\n      }\n\n      function renderShell() {\n        renderBranding();\n        renderTabs();\n        renderPanels();\n\n        if (isRankedMode()) {\n          renderRankedPanel();\n          hideSuggestions();\n          syncHelpToggleState();\n          return;\n        }\n\n        renderAttempts();\n        renderActionSlot();\n        renderInputState();\n        renderBoard();\n        renderResults();\n        hideSuggestions();\n        hideRankedSuggestions();\n        syncHelpToggleState();\n      }\n\n      function setMessage(text, tone) {\n        if (messageTimeoutId) {\n          window.clearTimeout(messageTimeoutId);\n          messageTimeoutId = 0;\n        }\n\n        elements.message.className = \"message\";\n        if (text && tone) {\n          elements.message.textContent = text;\n          elements.message.classList.add(\"is-visible\", \"is-\" + tone);\n          if (tone !== \"success\" && tone !== \"error-final\") {\n            messageTimeoutId = window.setTimeout(function () {\n              elements.message.className = \"message\";\n              elements.message.textContent = \"\";\n              messageTimeoutId = 0;\n            }, 2500);\n          }\n          return;\n        }\n\n        elements.message.textContent = \"\";\n      }\n\n      function setRankedMessage(text, tone) {\n        if (rankedMessageTimeoutId) {\n          window.clearTimeout(rankedMessageTimeoutId);\n          rankedMessageTimeoutId = 0;\n        }\n\n        elements.rankedMessage.className = \"message\";\n        if (text && tone) {\n          elements.rankedMessage.textContent = text;\n          elements.rankedMessage.classList.add(\"is-visible\", \"is-\" + tone);\n          if (tone !== \"success\" && tone !== \"error-final\") {\n            rankedMessageTimeoutId = window.setTimeout(function () {\n              elements.rankedMessage.className = \"message\";\n              elements.rankedMessage.textContent = \"\";\n              rankedMessageTimeoutId = 0;\n            }, 2200);\n          }\n          return;\n        }\n\n        elements.rankedMessage.textContent = \"\";\n      }\n\n      function readLocalRankedBest() {\n        try {\n          return Number(window.localStorage.getItem(localRankedBestKey) || 0);\n        } catch (_) {\n          return 0;\n        }\n      }\n\n      function writeLocalRankedBest(score) {\n        const best = Math.max(readLocalRankedBest(), Number(score || 0));\n        try {\n          window.localStorage.setItem(localRankedBestKey, String(best));\n        } catch (_) {}\n        return best;\n      }\n\n      function saveDailyState() {\n        const state = app.modes.classic;\n        const payload = {\n          targetId: state.target.id,\n          attempts: state.attempts,\n          gameOver: state.complete,\n          revealedHints: state.revealedHints,\n          complete: state.complete,\n          status: state.status,\n          guessedIds: Array.from(state.guessedIds),\n          hints: serializeHints(state.hints)\n        };\n\n        try {\n          window.localStorage.setItem(dailyStorageKey, JSON.stringify(payload));\n        } catch (_) {}\n      }\n\n      function loadDailyState() {\n        try {\n          const raw = window.localStorage.getItem(dailyStorageKey);\n          if (!raw) return;\n          const saved = JSON.parse(raw);\n          const state = app.modes.classic;\n          if (!saved || Number(saved.targetId) !== state.target.id) {\n            try {\n              window.localStorage.removeItem(dailyStorageKey);\n            } catch (_) {}\n            return;\n          }\n\n          const restoredHints = restoreHints(saved.hints);\n          if (restoredHints) {\n            state.hints = restoredHints;\n          }\n          state.attempts = Number(saved.attempts || 0);\n          state.revealedHints = Math.max(1, Number(saved.revealedHints || 1));\n          state.complete = Boolean(saved.complete || saved.gameOver);\n          state.status = saved.status || \"playing\";\n          state.guessedIds = new Set((saved.guessedIds || []).map(Number));\n\n          if (state.status === \"won\") {\n            setMessage(\"Hai indovinato \" + state.target.name + \".\", \"success\");\n            syncStreakResult(\"won\");\n            return;\n          }\n\n          if (state.status === \"lost\") {\n            setMessage(\"Hai finito i tentativi. Era \" + state.target.name + \".\", \"error-final\");\n            syncStreakResult(\"lost\");\n            return;\n          }\n\n          setMessage(\"\", \"\");\n        } catch (_) {\n          try {\n            window.localStorage.removeItem(dailyStorageKey);\n          } catch (_) {}\n        }\n      }\n\n      function resetPracticeState() {\n        app.modes.practice = createGameState(pickRandomValidArtist());\n      }\n\n      function completeCurrentGame(status) {\n        const state = getCurrentState();\n        state.complete = true;\n        state.status = status;\n        state.revealedHints = 5;\n        renderShell();\n\n        if (app.mode === \"classic\") {\n          saveDailyState();\n          syncStreakResult(status === \"won\" ? \"won\" : \"lost\");\n        }\n      }\n\n      function makeGuess() {\n        const state = getCurrentState();\n        if (state.complete) return;\n\n        const guessArtist = findArtistByName(elements.input.value.trim());\n        if (!guessArtist) {\n          setMessage(\"Artista non trovato nella lista.\", \"error\");\n          return;\n        }\n\n        if (state.guessedIds.has(guessArtist.id)) {\n          setMessage(\"Hai gia provato questo artista.\", \"error\");\n          elements.input.value = \"\";\n          return;\n        }\n\n        state.guessedIds.add(guessArtist.id);\n        state.attempts += 1;\n        elements.input.value = \"\";\n        hideSuggestions();\n\n        if (guessArtist.id === state.target.id) {\n          setMessage(\"Hai indovinato \" + state.target.name + \".\", \"success\");\n          completeCurrentGame(\"won\");\n          return;\n        }\n\n        if (state.revealedHints < 5) {\n          state.revealedHints += 1;\n        }\n\n        if (state.attempts >= MAX_ATTEMPTS) {\n          setMessage(\"Hai finito i tentativi. Era \" + state.target.name + \".\", \"error-final\");\n          completeCurrentGame(\"lost\");\n          return;\n        }\n\n        renderShell();\n        if (app.mode === \"classic\") {\n          saveDailyState();\n        }\n      }\n\n      function showSuggestions() {\n        positionSuggestionsFor(elements.input, elements.suggestions);\n        elements.suggestions.style.display = \"block\";\n      }\n\n      function hideSuggestions() {\n        elements.suggestions.style.display = \"none\";\n      }\n\n      function showRankedSuggestions() {\n        positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n        elements.rankedSuggestions.style.display = \"block\";\n      }\n\n      function hideRankedSuggestions() {\n        elements.rankedSuggestions.style.display = \"none\";\n      }\n\n      function positionSuggestionsFor(inputElement, suggestionElement) {\n        const rect = inputElement.getBoundingClientRect();\n        const viewportPadding = 8;\n        const width = Math.max(240, rect.width);\n        const left = Math.min(\n          window.innerWidth - width - viewportPadding,\n          Math.max(viewportPadding, rect.left)\n        );\n        const viewportHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight;\n        const spaceBelow = viewportHeight - rect.bottom - viewportPadding;\n        const maxHeight = Math.max(140, Math.min(280, spaceBelow - 8));\n\n        suggestionElement.style.width = width + \"px\";\n        suggestionElement.style.left = left + \"px\";\n        suggestionElement.style.top = Math.max(viewportPadding, rect.bottom + 8) + \"px\";\n        suggestionElement.style.maxHeight = maxHeight + \"px\";\n      }\n\n      function updateSuggestions() {\n        const state = getCurrentState();\n        const value = normalize(elements.input.value);\n        elements.suggestions.innerHTML = \"\";\n\n        if (!value || state.complete) {\n          hideSuggestions();\n          return;\n        }\n\n        const matches = artists.filter((artist) => {\n          return normalize(artist.name).includes(value) && !state.guessedIds.has(artist.id);\n        }).slice(0, 8);\n\n        if (!matches.length) {\n          hideSuggestions();\n          return;\n        }\n\n        matches.forEach((artist) => {\n          const button = document.createElement(\"button\");\n          button.type = \"button\";\n          button.className = \"suggestion\";\n          const left = document.createElement(\"span\");\n          left.textContent = artist.name;\n          const right = document.createElement(\"small\");\n          right.textContent = artist.members || \"Artista\";\n          button.appendChild(left);\n          button.appendChild(right);\n          button.addEventListener(\"click\", function () {\n            elements.input.value = artist.name;\n            hideSuggestions();\n            elements.input.focus();\n          });\n          elements.suggestions.appendChild(button);\n        });\n\n        showSuggestions();\n      }\n\n      function updateRankedSuggestions() {\n        const value = normalize(elements.rankedInput.value);\n        elements.rankedSuggestions.innerHTML = \"\";\n\n        if (!value || !app.ranked.active || app.ranked.betweenRounds || !app.ranked.currentArtist) {\n          hideRankedSuggestions();\n          return;\n        }\n\n        const matches = artists.filter((artist) => {\n          return normalize(artist.name).includes(value) && !app.ranked.roundGuessedIds.has(artist.id);\n        }).slice(0, 8);\n\n        if (!matches.length) {\n          hideRankedSuggestions();\n          return;\n        }\n\n        matches.forEach((artist) => {\n          const button = document.createElement(\"button\");\n          button.type = \"button\";\n          button.className = \"suggestion\";\n          const left = document.createElement(\"span\");\n          left.textContent = artist.name;\n          const right = document.createElement(\"small\");\n          right.textContent = artist.members || \"Artista\";\n          button.appendChild(left);\n          button.appendChild(right);\n          button.addEventListener(\"click\", function () {\n            elements.rankedInput.value = artist.name;\n            hideRankedSuggestions();\n            elements.rankedInput.focus();\n          });\n          elements.rankedSuggestions.appendChild(button);\n        });\n\n        showRankedSuggestions();\n      }\n\n      async function postRankedAction(action, extraData) {\n        const body = new URLSearchParams({\n          action: action,\n          nonce: rankedConfig.nonce || \"\",\n          game_key: RANKED_GAME_KEY,\n          ...(extraData || {})\n        });\n\n        const response = await fetch(rankedConfig.ajaxUrl, {\n          method: \"POST\",\n          credentials: \"same-origin\",\n          headers: {\n            \"Content-Type\": \"application\/x-www-form-urlencoded; charset=UTF-8\"\n          },\n          body: body.toString()\n        });\n\n        if (!response.ok) {\n          throw new Error(\"Richiesta ranked non riuscita\");\n        }\n\n        return response.json();\n      }\n\n      function getRankedLoginUrl() {\n        return rankedConfig.loginUrl || guestLoginUrl;\n      }\n\n      function resetRankedState() {\n        const state = app.ranked;\n        state.active = false;\n        state.preparing = false;\n        state.submitting = false;\n        state.complete = false;\n        state.betweenRounds = false;\n        state.sessionToken = \"\";\n        state.currentArtist = null;\n        state.hints = [];\n        state.revealedHints = 1;\n        state.roundAttempts = 0;\n        state.roundGuessedIds = new Set();\n        state.usedTargetIds = new Set();\n        state.score = 0;\n        state.timeLeft = RANKED_INITIAL_TIME;\n        state.results = [];\n        state.summaryTitle = \"Partita conclusa\";\n        state.summaryLines = [];\n        state.isRecord = false;\n        state.lastRoundSolved = false;\n        window.clearInterval(state.timerId);\n        window.clearTimeout(state.roundTransitionId);\n        state.timerId = 0;\n        state.roundTransitionId = 0;\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n        setRankedMessage(\"\", \"\");\n      }\n\n      function startNextRankedArtist() {\n        if (!app.ranked.active) return;\n\n        window.clearTimeout(app.ranked.roundTransitionId);\n        app.ranked.betweenRounds = false;\n\n        if (app.ranked.usedTargetIds.size >= validArtists.length) {\n          app.ranked.usedTargetIds.clear();\n        }\n\n        app.ranked.currentArtist = pickRandomValidArtist(app.ranked.usedTargetIds);\n        app.ranked.usedTargetIds.add(app.ranked.currentArtist.id);\n        app.ranked.hints = buildHintSet(app.ranked.currentArtist);\n        app.ranked.revealedHints = 1;\n        app.ranked.roundAttempts = 0;\n        app.ranked.roundGuessedIds = new Set();\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n        setRankedMessage(\"\", \"\");\n        renderRankedPanel();\n        if (isRankedMode()) {\n          elements.rankedInput.focus();\n        }\n      }\n\n      function completeRankedRound(message, tone, label, solved) {\n        app.ranked.results.unshift({\n          artist: app.ranked.currentArtist,\n          label: label,\n          solved: solved,\n          revealedHints: app.ranked.revealedHints\n        });\n\n        app.ranked.lastRoundSolved = solved;\n        app.ranked.betweenRounds = true;\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n        renderRankedPanel();\n        setRankedMessage(message, tone);\n\n        app.ranked.roundTransitionId = window.setTimeout(function () {\n          if (!app.ranked.active || app.ranked.timeLeft <= 0) return;\n          startNextRankedArtist();\n        }, RANKED_ROUND_TRANSITION_MS);\n      }\n\n      function tickRanked() {\n        if (!app.ranked.active) return;\n        app.ranked.timeLeft -= 1;\n        renderRankedMeta();\n        if (app.ranked.timeLeft <= 0) {\n          finishRankedGame();\n        }\n      }\n\n      async function startRankedGame() {\n        if (app.ranked.active || app.ranked.preparing) return;\n\n        if (hasRankedBackend && !rankedConfig.isLoggedIn) {\n          window.location.href = getRankedLoginUrl();\n          return;\n        }\n\n        app.ranked.preparing = true;\n        app.ranked.complete = false;\n        app.ranked.summaryLines = [];\n        renderRankedActionButton();\n\n        try {\n          if (hasRankedBackend) {\n            const response = await postRankedAction(\"bulldogle_ranked_start\");\n            if (!response || !response.success || !response.data || !response.data.is_logged_in) {\n              window.location.href = getRankedLoginUrl();\n              return;\n            }\n            app.ranked.sessionToken = String(response.data.token || \"\");\n          } else {\n            app.ranked.sessionToken = \"demo-\" + String(Date.now());\n          }\n\n          window.clearInterval(app.ranked.timerId);\n          window.clearTimeout(app.ranked.roundTransitionId);\n          app.ranked.active = true;\n          app.ranked.complete = false;\n          app.ranked.betweenRounds = false;\n          app.ranked.submitting = false;\n          app.ranked.score = 0;\n          app.ranked.timeLeft = RANKED_INITIAL_TIME;\n          app.ranked.roundAttempts = 0;\n          app.ranked.roundGuessedIds = new Set();\n          app.ranked.usedTargetIds = new Set();\n          app.ranked.results = [];\n          app.ranked.summaryTitle = \"Partita conclusa\";\n          app.ranked.summaryLines = [];\n          app.ranked.isRecord = false;\n          app.ranked.lastRoundSolved = false;\n          setRankedMessage(\"\", \"\");\n          startNextRankedArtist();\n          app.ranked.timerId = window.setInterval(tickRanked, 1000);\n        } catch (_) {\n          app.ranked.active = false;\n          app.ranked.complete = false;\n          app.ranked.betweenRounds = false;\n          app.ranked.submitting = false;\n          app.ranked.currentArtist = null;\n          app.ranked.hints = [];\n          app.ranked.revealedHints = 1;\n          app.ranked.roundAttempts = 0;\n          app.ranked.roundGuessedIds = new Set();\n          app.ranked.usedTargetIds = new Set();\n          app.ranked.results = [];\n          window.clearInterval(app.ranked.timerId);\n          window.clearTimeout(app.ranked.roundTransitionId);\n          app.ranked.timerId = 0;\n          app.ranked.roundTransitionId = 0;\n          setRankedMessage(\"Non sono riuscito ad avviare la partita. Riprova tra poco.\", \"error\");\n        } finally {\n          app.ranked.preparing = false;\n          renderRankedPanel();\n        }\n      }\n\n      function submitRankedGuess() {\n        if (!app.ranked.active || app.ranked.betweenRounds || !app.ranked.currentArtist) return;\n\n        const guessArtist = findArtistByName(elements.rankedInput.value.trim());\n        if (!guessArtist) {\n          setRankedMessage(\"Artista non trovato nella lista.\", \"error\");\n          return;\n        }\n\n        if (app.ranked.roundGuessedIds.has(guessArtist.id)) {\n          setRankedMessage(\"Hai gia provato questo artista.\", \"error\");\n          elements.rankedInput.value = \"\";\n          return;\n        }\n\n        app.ranked.roundGuessedIds.add(guessArtist.id);\n        app.ranked.roundAttempts += 1;\n        elements.rankedInput.value = \"\";\n        hideRankedSuggestions();\n\n        if (guessArtist.id === app.ranked.currentArtist.id) {\n          app.ranked.score += 1;\n          app.ranked.timeLeft += RANKED_CORRECT_BONUS;\n          renderRankedMeta();\n          setRankedMessage(\"Hai indovinato!\", \"success\");\n          completeRankedRound(\"Hai indovinato!\", \"success\", \"Hai indovinato\", true);\n          return;\n        }\n\n        if (app.ranked.revealedHints < 5) {\n          app.ranked.revealedHints += 1;\n        }\n\n        if (app.ranked.roundAttempts >= RANKED_ATTEMPTS) {\n          setRankedMessage(\"Hai finito i tentativi! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\");\n          completeRankedRound(\"Hai finito i tentativi! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\", \"Reveal del round\", false);\n          return;\n        }\n\n        renderRankedPanel();\n      }\n\n      function skipRankedArtist() {\n        if (!app.ranked.active || app.ranked.betweenRounds || !app.ranked.currentArtist) return;\n        app.ranked.timeLeft = Math.max(0, app.ranked.timeLeft - RANKED_SKIP_PENALTY);\n        renderRankedMeta();\n\n        if (app.ranked.timeLeft <= 0) {\n          finishRankedGame();\n          return;\n        }\n\n        setRankedMessage(\"Hai skippato! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\");\n        completeRankedRound(\"Hai skippato! Era \" + app.ranked.currentArtist.name + \".\", \"error-final\", \"Skip\", false);\n      }\n\n      function escapeHtml(value) {\n        const div = document.createElement(\"div\");\n        div.textContent = value || \"\";\n        return div.innerHTML;\n      }\n\n      function buildRankedSummaryLines(data) {\n        const lines = [];\n        if (app.ranked.currentArtist && app.ranked.currentArtist.name) {\n          lines.push(\"L'ultimo artista era: <strong>\" + escapeHtml(app.ranked.currentArtist.name) + \"<\/strong>\");\n        }\n        lines.push(\"Punteggio finale: <strong>\" + String(app.ranked.score) + \"<\/strong>\");\n\n        if (data && typeof data.best_score !== \"undefined\") {\n          lines.push(\"Record mensile: <strong>\" + String(data.best_score) + \"<\/strong>\");\n          lines.push(\"Migliore posizione: <strong>\" + (data.best_rank ? \"#\" + data.best_rank : \"Fuori top 50\") + \"<\/strong>\");\n        } else {\n          const localBest = writeLocalRankedBest(app.ranked.score);\n          lines.push(\"Record demo: <strong>\" + String(localBest) + \"<\/strong>\");\n        }\n\n        return lines;\n      }\n\n      async function finishRankedGame() {\n        if (!app.ranked.active || app.ranked.submitting) return;\n\n        app.ranked.active = false;\n        app.ranked.complete = true;\n        app.ranked.betweenRounds = false;\n        app.ranked.submitting = true;\n        app.ranked.timeLeft = 0;\n        window.clearInterval(app.ranked.timerId);\n        window.clearTimeout(app.ranked.roundTransitionId);\n        app.ranked.timerId = 0;\n        app.ranked.roundTransitionId = 0;\n        hideRankedSuggestions();\n        setRankedMessage(\"\", \"\");\n        renderRankedMeta();\n        renderRankedInputState();\n        renderRankedActionButton();\n        app.ranked.summaryTitle = \"Partita conclusa\";\n        app.ranked.summaryLines = [\"Salvataggio record...\"];\n        app.ranked.isRecord = false;\n        renderRankedSummary();\n\n        try {\n          let data = null;\n          if (hasRankedBackend) {\n            const response = await postRankedAction(\"bulldogle_ranked_submit\", {\n              token: app.ranked.sessionToken,\n              score: String(app.ranked.score)\n            });\n            data = response && response.success ? response.data : null;\n          }\n\n          if (data) {\n            app.ranked.summaryTitle = data.is_record ? \"Nuovo record!\" : \"Partita conclusa\";\n            app.ranked.summaryLines = buildRankedSummaryLines(data);\n            app.ranked.isRecord = Boolean(data.is_record);\n          } else {\n            const previousBest = readLocalRankedBest();\n            const nextBest = Math.max(previousBest, app.ranked.score);\n            writeLocalRankedBest(nextBest);\n            app.ranked.summaryTitle = nextBest === app.ranked.score && app.ranked.score > previousBest ? \"Nuovo record!\" : \"Partita conclusa\";\n            app.ranked.summaryLines = buildRankedSummaryLines(null);\n            app.ranked.isRecord = app.ranked.score > previousBest;\n          }\n        } catch (_) {\n          const previousBest = readLocalRankedBest();\n          const nextBest = Math.max(previousBest, app.ranked.score);\n          writeLocalRankedBest(nextBest);\n          app.ranked.summaryTitle = \"Partita conclusa\";\n          app.ranked.summaryLines = buildRankedSummaryLines(null);\n          app.ranked.isRecord = app.ranked.score > previousBest;\n        } finally {\n          app.ranked.submitting = false;\n          renderRankedPanel();\n        }\n      }\n\n      function handleRankedSideAction() {\n        const action = elements.rankedSideActionButton.dataset.action;\n\n        if (action === \"login\") {\n          window.location.href = getRankedLoginUrl();\n          return;\n        }\n\n        if (action === \"start\" || action === \"restart\") {\n          startRankedGame();\n          return;\n        }\n\n        if (action === \"skip\") {\n          skipRankedArtist();\n        }\n      }\n\n      function bindTouchAction(node, handler) {\n        if (!node) return;\n\n        let touchHandled = false;\n\n        node.addEventListener(\"touchend\", function (event) {\n          if (node.disabled) return;\n          event.preventDefault();\n          touchHandled = true;\n          handler();\n          window.setTimeout(function () {\n            touchHandled = false;\n          }, 350);\n        }, { passive: false });\n\n        node.addEventListener(\"click\", function (event) {\n          if (node.disabled) return;\n          if (touchHandled) {\n            event.preventDefault();\n            return;\n          }\n          handler();\n        });\n      }\n\n      function renderStreakGuestState() {\n        elements.dailyStreakCard.classList.add(\"is-guest\");\n        elements.dailyStreakCard.href = guestLoginUrl;\n        elements.dailyStreakCard.setAttribute(\"aria-label\", \"Accedi per salvare la streak\");\n        elements.dailyStreakMain.textContent = \"STREAK\";\n        elements.dailyStreakSub.textContent = \"Accedi per salvarla\";\n      }\n\n      function renderStreakLoadingState() {\n        elements.dailyStreakCard.classList.remove(\"is-guest\");\n        elements.dailyStreakCard.removeAttribute(\"href\");\n        elements.dailyStreakMain.textContent = \"...\";\n        elements.dailyStreakSub.textContent = \"Caricamento streak\";\n      }\n\n      function renderStreakState(data) {\n        if (!data || !data.is_logged_in) {\n          renderStreakGuestState();\n          return;\n        }\n\n        elements.dailyStreakCard.classList.remove(\"is-guest\");\n        elements.dailyStreakCard.removeAttribute(\"href\");\n        const streakValue = Number(data.current_streak || 0);\n        elements.dailyStreakMain.textContent = streakValue + \" \" + (streakValue === 1 ? \"GIORNO\" : \"GIORNI\");\n\n        if (data.today_result === \"won\") {\n          elements.dailyStreakSub.textContent = \"Indovinata oggi \u2022 Record \" + (data.best_streak || data.current_streak || 0);\n        } else if (data.today_result === \"lost\") {\n          elements.dailyStreakSub.textContent = \"Interrotta oggi \u2022 Record \" + (data.best_streak || 0);\n        } else {\n          elements.dailyStreakSub.textContent = \"Record \" + (data.best_streak || data.current_streak || 0);\n        }\n      }\n\n      async function postStreakAction(action, extraData) {\n        const ajaxUrl = featConfig.ajaxUrl;\n        if (!ajaxUrl) {\n          throw new Error(\"Config streak WordPress non trovata\");\n        }\n\n        const body = new URLSearchParams({\n          action: action,\n          nonce: featConfig.nonce || \"\",\n          ...(extraData || {})\n        });\n\n        const response = await fetch(ajaxUrl, {\n          method: \"POST\",\n          credentials: \"same-origin\",\n          headers: {\n            \"Content-Type\": \"application\/x-www-form-urlencoded; charset=UTF-8\"\n          },\n          body: body.toString()\n        });\n\n        if (!response.ok) {\n          throw new Error(\"Richiesta streak non riuscita\");\n        }\n\n        return response.json();\n      }\n\n      async function loadStreakStatus() {\n        if (!featConfig.isLoggedIn) {\n          renderStreakGuestState();\n          return;\n        }\n\n        if (streakLoading) return;\n        streakLoading = true;\n        renderStreakLoadingState();\n\n        try {\n          const response = await postStreakAction(\"bulldogle_feat_streak_status\");\n          if (response && response.success) {\n            renderStreakState(response.data);\n          } else {\n            renderStreakGuestState();\n          }\n        } catch (_) {\n          renderStreakGuestState();\n        } finally {\n          streakLoading = false;\n        }\n      }\n\n      async function syncStreakResult(result) {\n        if (!featConfig.isLoggedIn) return;\n        try {\n          const response = await postStreakAction(\"bulldogle_feat_streak_update\", {\n            result: result,\n            day_key: italyDateInfo.dayKey\n          });\n\n          if (response && response.success) {\n            renderStreakState(response.data);\n          }\n        } catch (_) {}\n      }\n\n      function switchMode(nextMode) {\n        if (nextMode === app.mode) return;\n        if (app.mode === \"ranked\" && nextMode !== \"ranked\") {\n          resetRankedState();\n        }\n        app.mode = nextMode;\n        setMessage(\"\", \"\");\n        setRankedMessage(\"\", \"\");\n        hideSuggestions();\n        hideRankedSuggestions();\n        closeAllHelpPanels();\n        renderShell();\n        if (app.mode === \"classic\") {\n          loadStreakStatus();\n        }\n      }\n\n      elements.tabs.forEach((tab) => {\n        tab.addEventListener(\"click\", function () {\n          switchMode(tab.dataset.mode);\n        });\n      });\n\n      if (elements.rankedModeButton) {\n        elements.rankedModeButton.addEventListener(\"click\", function () {\n          switchMode(\"ranked\");\n        });\n      }\n\n      elements.helpToggle.addEventListener(\"click\", function () {\n        const panel = getCurrentHelpPanel();\n        if (!panel) return;\n\n        const shouldOpen = !panel.classList.contains(\"is-open\");\n        closeAllHelpPanels();\n\n        if (shouldOpen) {\n          panel.classList.add(\"is-open\");\n          panel.setAttribute(\"aria-hidden\", \"false\");\n        }\n\n        syncHelpToggleState();\n      });\n\n      elements.guessForm.addEventListener(\"submit\", function (event) {\n        event.preventDefault();\n        makeGuess();\n      });\n\n      elements.rankedGuessForm.addEventListener(\"submit\", function (event) {\n        event.preventDefault();\n        submitRankedGuess();\n        renderRankedPanel();\n      });\n\n      elements.modeActionButton.addEventListener(\"click\", function () {\n        if (app.mode !== \"practice\") return;\n        resetPracticeState();\n        setMessage(\"\", \"\");\n        hideSuggestions();\n        renderShell();\n      });\n\n      bindTouchAction(elements.rankedSideActionButton, handleRankedSideAction);\n\n      elements.input.addEventListener(\"input\", updateSuggestions);\n      elements.input.addEventListener(\"focus\", updateSuggestions);\n      elements.rankedInput.addEventListener(\"input\", updateRankedSuggestions);\n      elements.rankedInput.addEventListener(\"focus\", updateRankedSuggestions);\n\n      document.addEventListener(\"click\", function (event) {\n        if (!elements.suggestions.contains(event.target) && event.target !== elements.input) {\n          hideSuggestions();\n        }\n\n        if (!elements.rankedSuggestions.contains(event.target) && event.target !== elements.rankedInput) {\n          hideRankedSuggestions();\n        }\n      });\n\n      window.addEventListener(\"resize\", function () {\n        syncHelpPanelPlacement();\n        if (elements.suggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.input, elements.suggestions);\n        }\n        if (elements.rankedSuggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n        }\n      });\n\n      window.addEventListener(\"scroll\", function () {\n        if (elements.suggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.input, elements.suggestions);\n        }\n        if (elements.rankedSuggestions.style.display === \"block\") {\n          positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n        }\n      }, true);\n\n      if (window.visualViewport) {\n        window.visualViewport.addEventListener(\"resize\", function () {\n          syncHelpPanelPlacement();\n          if (elements.suggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.input, elements.suggestions);\n          }\n          if (elements.rankedSuggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n          }\n        });\n\n        window.visualViewport.addEventListener(\"scroll\", function () {\n          if (elements.suggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.input, elements.suggestions);\n          }\n          if (elements.rankedSuggestions.style.display === \"block\") {\n            positionSuggestionsFor(elements.rankedInput, elements.rankedSuggestions);\n          }\n        });\n      }\n\n      loadDailyState();\n      syncHelpPanelPlacement();\n      renderShell();\n      loadStreakStatus();\n    })();\n  <\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8499403 elementor-widget-divider--view-line_text elementor-widget-mobile__width-initial hide-when-ranked elementor-widget-divider--element-align-center elementor-widget elementor-widget-divider\" data-id=\"8499403\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t\t<span class=\"elementor-divider__text elementor-divider__element\">\n\t\t\t\tAltri Giochi\t\t\t\t<\/span>\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ed3955d hide-when-ranked elementor-widget__width-initial elementor-widget elementor-widget-post-widget\" data-id=\"ed3955d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;posts_per_page&quot;:100,&quot;post_type&quot;:[&quot;page&quot;],&quot;nb_columns&quot;:&quot;1&quot;,&quot;classic_layout&quot;:&quot;grid&quot;,&quot;nb_columns_tablet&quot;:&quot;3&quot;,&quot;nb_columns_mobile&quot;:&quot;1&quot;,&quot;post_status&quot;:&quot;publish&quot;,&quot;pagination&quot;:&quot;none&quot;}\" data-widget_type=\"post-widget.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"post-container none classic\" data-total-post=\"2\" ><div class=\"post-container-inner\"><div class=\"elementor-grid\" ><article class=\"post-wrapper\"  data-post-id=\"7057\" ><div class=\"post-image\"><a href=\"https:\/\/bulldogmusik.it\/en\/bulldogle-rap-ita\/\" ><img loading=\"lazy\" decoding=\"async\" width=\"1366\" height=\"768\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Bulldogle-Classico-New.png\" class=\"bpfwe-post-thumbnail\" alt=\"\" data-bpfwe-src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/Bulldogle-Classico-New.png\" loading=\"lazy\" \/><\/a><\/div><div class=\"inner-content\"><div class=\"post-content elementor-repeater-item-0b20400\"><p>Indovina il rapper in meno di 10 tentativi, ogni tentativo scopri nuove informazioni...<\/p><\/div><\/div><\/article><article class=\"post-wrapper\"  data-post-id=\"8209\" ><div class=\"post-image\"><a href=\"https:\/\/bulldogmusik.it\/en\/bulldogmatch-ita\/\" ><img loading=\"lazy\" decoding=\"async\" width=\"1366\" height=\"768\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogMatch-New.png\" class=\"bpfwe-post-thumbnail\" alt=\"\" data-bpfwe-src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/BulldogMatch-New.png\" loading=\"lazy\" \/><\/a><\/div><div class=\"inner-content\"><div class=\"post-content elementor-repeater-item-0b20400\"><p>Indovina in rapper in meno di 20 tentativi, ogni tentativo scopri diverse affinit\u00e0....<\/p><\/div><\/div><\/article><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f3cbce2 elementor-widget-divider--view-line_text elementor-widget-mobile__width-initial show-when-ranked elementor-widget-divider--element-align-center elementor-widget elementor-widget-divider\" data-id=\"f3cbce2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t\t<span class=\"elementor-divider__text elementor-divider__element\">\n\t\t\t\tRanked\t\t\t\t<\/span>\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-47afb4d7 elementor-widget-mobile__width-initial show-when-ranked elementor-widget elementor-widget-html\" data-id=\"47afb4d7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div class=\"ranked-board-widget ranked-sidebar-board\" data-game-key=\"feat\">\n  <div class=\"ranked-sidebar-board-inner\">\n    <div class=\"ranked-board-controls\" aria-label=\"Seleziona mese classifica\">\n      <select class=\"ranked-board-period-select\">\n        <option value=\"\">Caricamento...<\/option>\n      <\/select>\n    <\/div>\n\n    <img decoding=\"async\" class=\"ranked-sidebar-board-heading-image\" src=\"https:\/\/bulldogmusik.it\/wp-content\/uploads\/2026\/05\/LeadBasico.png\" alt=\"Classificato\">\n\n    <div class=\"ranked-board-list\"><\/div>\n\n    <div class=\"ranked-board-pager\">\n      <button class=\"ranked-board-prev\" type=\"button\" aria-label=\"Pagina precedente\">&#8249;<\/button>\n      <span class=\"ranked-board-page\">1\/1<\/span>\n      <button class=\"ranked-board-next\" type=\"button\" aria-label=\"Pagina successiva\">&#8250;<\/button>\n    <\/div>\n\n    <div class=\"ranked-board-msg\">Caricamento classifica...<\/div>\n  <\/div>\n<\/div>\n\n<script src=\"\/bulldogle\/ranked-leaderboard.js?v=58\"><\/script>\n\n<style>\n.ranked-sidebar-board {\n  --ranked-accent: #952800;\n  --ranked-accent-2: #a83100;\n  --ranked-accent-3: #7d2100;\n  --ranked-ink: #17110d;\n  --ranked-ink-soft: rgba(23, 17, 13, 0.72);\n  --ranked-cream: #f8f0e8;\n  width: 100%;\n  max-width: 100%;\n  margin: 0;\n  font-family: Verdana, Geneva, sans-serif;\n}\n\n.ranked-sidebar-board-inner {\n  position: relative;\n  width: 100%;\n  padding: 22px 22px 20px;\n  border-radius: 34px;\n  overflow: hidden;\n  background: var(--ranked-accent);\n  box-shadow:\n    inset 0 1px 0 rgba(255, 255, 255, 0.16),\n    0 18px 34px rgba(0, 0, 0, 0.18);\n  color: var(--ranked-ink);\n  text-align: center;\n}\n\n.ranked-sidebar-board-heading-image {\n  display: block;\n  width: min(100%, 206px) !important;\n  height: auto;\n  margin: 2px auto 16px;\n}\n\n.ranked-sidebar-board .ranked-board-controls {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-bottom: 12px;\n}\n\n.ranked-sidebar-board .ranked-board-controls select {\n  width: 100% !important;\n  max-width: 182px;\n  min-width: 0;\n  height: 40px;\n  padding: 0 14px !important;\n  border: 1px solid rgba(23, 17, 13, 0.12) !important;\n  border-radius: 999px !important;\n  background: rgba(12, 8, 6, 0.9) !important;\n  color: var(--ranked-cream) !important;\n  font-family: Verdana, Geneva, sans-serif;\n  font-size: 12px !important;\n  font-weight: 700;\n  text-align: center;\n  box-shadow: none !important;\n  outline: none;\n  appearance: none;\n  -webkit-appearance: none;\n}\n\n.ranked-sidebar-board .ranked-board-list {\n  display: grid;\n  gap: 10px;\n  margin: 0;\n}\n\n.ranked-sidebar-board .ranked-board-row {\n  display: grid;\n  grid-template-columns: 66px minmax(0, 1fr) 64px;\n  align-items: center;\n  gap: 8px;\n  min-height: 52px;\n  padding: 10px 14px;\n  border: 0;\n  border-radius: 18px;\n  background: #000000;\n  color: var(--ranked-cream);\n  text-align: center;\n}\n\n.ranked-sidebar-board .ranked-board-row:first-child {\n  background: #000000;\n}\n\n.ranked-sidebar-board .ranked-board-rank {\n  color: #ffffff;\n  font-size: 13px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-name {\n  min-width: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  color: #ffffff;\n  font-size: 13px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-score {\n  color: #ffffff;\n  font-size: 13px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-pager {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 12px;\n  margin-top: 14px;\n}\n\n.ranked-sidebar-board .ranked-board-pager button {\n  appearance: none !important;\n  display: inline-flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  width: 36px !important;\n  min-width: 36px !important;\n  height: 36px !important;\n  min-height: 36px !important;\n  padding: 0 !important;\n  margin: 0 !important;\n  border: 1px solid rgba(23, 17, 13, 0.12) !important;\n  border-radius: 999px !important;\n  background: #000000 !important;\n  color: #ffffff !important;\n  font-family: Verdana, Geneva, sans-serif !important;\n  font-size: 23px !important;\n  font-weight: 700 !important;\n  line-height: 1 !important;\n  box-shadow: none !important;\n  transform: none !important;\n  cursor: pointer;\n}\n\n.ranked-sidebar-board .ranked-board-pager button:hover {\n  background: #ffffff !important;\n  color: var(--ranked-ink) !important;\n}\n\n.ranked-sidebar-board .ranked-board-pager button:disabled {\n  opacity: 0.34;\n  cursor: not-allowed;\n}\n\n.ranked-sidebar-board .ranked-board-page {\n  color: rgba(23, 17, 13, 0.72);\n  font-size: 12px;\n  font-weight: 700;\n}\n\n.ranked-sidebar-board .ranked-board-msg {\n  min-height: 18px;\n  margin-top: 12px;\n  color: rgba(23, 17, 13, 0.72);\n  font-size: 12px;\n  line-height: 1.35;\n  font-weight: 700;\n  text-align: center;\n}\n\n@media (max-width: 767px) {\n  .ranked-sidebar-board-inner {\n    padding: 20px 18px 18px;\n    border-radius: 28px;\n  }\n\n  .ranked-sidebar-board .ranked-board-row {\n    grid-template-columns: 58px minmax(0, 1fr) 58px;\n    min-height: 48px;\n    padding: 9px 12px;\n  }\n\n  .ranked-sidebar-board-heading-image {\n    width: min(100%, 174px);\n  }\n}\n<\/style>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d224bbf e-flex e-con-boxed wcf-starter-animations-none e-con e-parent\" data-id=\"d224bbf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ef479c3 elementor-widget elementor-widget-html\" data-id=\"ef479c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style id=\"bulldogle-modern-font-900-override\">\n.demo-app button,\n.demo-app button *,\n.demo-app .attempts-card,\n.demo-app .attempts-card *,\n.demo-app .classic-attempts-badge,\n.demo-app .classic-attempts-badge *,\n.demo-app .classic-streak-badge,\n.demo-app .classic-streak-badge *,\n.demo-app .streak-card,\n.demo-app .streak-card *,\n.ranked-demo-app button,\n.ranked-demo-app button *,\n.ranked-demo-app .attempts-card,\n.ranked-demo-app .attempts-card *,\n.ranked-demo-app .classic-attempts-badge,\n.ranked-demo-app .classic-attempts-badge *,\n.ranked-demo-app .classic-streak-badge,\n.ranked-demo-app .classic-streak-badge *,\n.ranked-demo-app .streak-card,\n.ranked-demo-app .streak-card *,\n.demo-app .guess-name,\n.demo-app .guess-name *,\n.demo-app .artist-name,\n.demo-app .artist-name *,\n.demo-app .result-name,\n.demo-app .result-name *,\n.demo-app .board-row .name,\n.demo-app .board-row .name *,\n.ranked-demo-app .guess-name,\n.ranked-demo-app .guess-name *,\n.ranked-demo-app .artist-name,\n.ranked-demo-app .artist-name *,\n.ranked-demo-app .result-name,\n.ranked-demo-app .result-name *,\n.ranked-demo-app .board-row .name,\n.ranked-demo-app .board-row .name * {\n  font-family: Verdana, Geneva, sans-serif !important;\n  font-weight: 900 !important;\n  -webkit-text-stroke: 0.18px currentColor;\n  text-shadow: 0.18px 0 currentColor;\n}\n\n.demo-app .controls-inner .tab,\n.demo-app .controls-inner .ghost-button {\n  min-height: 56px !important;\n  height: 56px !important;\n  padding: 0 22px !important;\n  border-radius: 12px !important;\n  font-size: 15px !important;\n  line-height: 1.1 !important;\n  text-transform: uppercase !important;\n}\n\n.ranked-demo-app .meta-card,\n.ranked-demo-app .meta-button,\n.ranked-demo-app .ranked-meta-button {\n  min-height: 74px !important;\n  height: 74px !important;\n  padding: 12px 14px !important;\n  border-radius: 16px !important;\n  font-size: 15px !important;\n  line-height: 1.1 !important;\n  text-transform: uppercase !important;\n}\n\n.ranked-demo-app .meta-label,\n.ranked-demo-app .meta-value {\n  line-height: 1.1 !important;\n}\n\n.demo-app.is-ranked-mode .match-meta-grid > .match-meta-card,\n.demo-app.is-ranked-mode .match-meta-grid > .ranked-meta-button,\nbody.bulldogmatch-ranked-mode-active .demo-app .match-meta-grid > .match-meta-card,\nbody.bulldogmatch-ranked-mode-active .demo-app .match-meta-grid > .ranked-meta-button,\n.ranked-demo-app .match-meta-grid > .match-meta-card,\n.ranked-demo-app .match-meta-grid > .ranked-meta-button {\n  min-height: 74px !important;\n  height: 74px !important;\n  align-self: stretch !important;\n}\n\n.ranked-demo-app .match-meta-label,\n.ranked-demo-app .match-meta-value {\n  line-height: 1.1 !important;\n}\n\n@media (max-width: 720px) {\n  .demo-app .top-logo,\n  .ranked-demo-app .top-logo {\n    margin-top: 14px !important;\n  }\n\n  .demo-app .controls-inner,\n  .ranked-demo-app .controls-inner {\n    margin-bottom: 18px !important;\n  }\n}\n\n<\/style>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Indovina in rapper in meno di 5 tentativi, ogni tentativo scopri altre collaborazioni. Giornaliera Classificata BulldogFeat Demo Daily Allenamento Classificata Come si gioca Obiettivo Trova il rapper segreto partendo dalle sue collaborazioni. Centro Al centro vedi il tipo dell&#8217;artista corretto: Rapper, Producer, Gruppo o Duo. Feat Ogni errore svela un nuovo feat. Le ultime 2 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":14980,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_eb_attr":"","footnotes":""},"categories":[35],"tags":[],"class_list":["post-8846","page","type-page","status-publish","has-post-thumbnail","hentry","category-min"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":8}},"_links":{"self":[{"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/pages\/8846","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/comments?post=8846"}],"version-history":[{"count":20,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/pages\/8846\/revisions"}],"predecessor-version":[{"id":15506,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/pages\/8846\/revisions\/15506"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/media\/14980"}],"wp:attachment":[{"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/media?parent=8846"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/categories?post=8846"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bulldogmusik.it\/en\/wp-json\/wp\/v2\/tags?post=8846"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}