{"id":13535,"date":"2026-09-09T07:55:42","date_gmt":"2026-09-09T07:55:42","guid":{"rendered":"https:\/\/comparetiger.com\/?page_id=13535"},"modified":"2026-09-09T10:18:02","modified_gmt":"2026-09-09T10:18:02","slug":"pickleball","status":"publish","type":"page","link":"https:\/\/comparetiger.com\/?page_id=13535","title":{"rendered":"Pickleball Score Tracker"},"content":{"rendered":"<style id=\"pickleball-page-override\">\n  \/* === ReHub \/ Jetpack Boost bypass ===\n     Force dark_body class and use high-specificity bg override. *\/\n  body.page-id-13535 { background-color: var(--bg) !important; }\n  html body.page-id-13535 { background-color: var(--bg) !important; }<\/p>\n<p>  \/* Hide ReHub theme chrome *\/\n  body.page-id-13535 header#main_header,\n  body.page-id-13535 .header_wrap,\n  body.page-id-13535 .sticky-wrapper,\n  body.page-id-13535 #theme_footer,\n  body.page-id-13535 .breadcrumbs,\n  body.page-id-13535 #rhLoader,\n  body.page-id-13535 .entry-title,\n  body.page-id-13535 h1[class*=\"entry\"] { display: none !important; }<\/p>\n<p>  \/* Strip theme padding *\/\n  body.page-id-13535 .rh-content-wrap,\n  body.page-id-13535 .main-side,\n  body.page-id-13535 #content,\n  body.page-id-13535 .page,\n  body.page-id-13535 .entry-content,\n  body.page-id-13535 .visual_page_builder,\n  body.page-id-13535 .rh-container { padding: 0 !important; margin: 0 !important; max-width: 100% !important; }<\/p>\n<p>  \/* Force .app to fill viewport and own its bg *\/\n  body.page-id-13535 .app {\n    max-width: 480px !important;\n    margin: 0 auto !important;\n    min-height: 100vh !important;\n    min-height: 100dvh !important;\n    background-color: var(-bg) !important;\n    color: var(-text) !important;\n    flex: 1 !important;\n    width: 100% !important;\n    box-sizing: border-box !important;\n    position: relative !important;\n  }\n<\/style>\n<style>\n    \/* ===== THEME TOKENS ===== *\/\n    :root, [data-theme=\"dark\"] {\n      --bg: #000000;\n      --card: #0f0f10;\n      --card-2: #151516;\n      --line: #2a2a2c;\n      --line-soft: #1c1c1e;\n      --text: #ffffff;\n      --text-2: #8e8e93;\n      --text-3: #6e6e73;\n      --accent: #8b8cf8;\n      --accent-bg: rgba(139, 140, 248, 0.05);\n      --accent-glow: rgba(139, 140, 248, 0.25);\n      --good: #32d74b;\n      --warn: #ff9f0a;\n      --bad: #ff453a;\n      --btn: #1c1c1e;\n      --btn-hover: #2c2c2e;\n    }\n    [data-theme=\"light\"] {\n      --bg: #f5f5f7;\n      --card: #ffffff;\n      --card-2: #fbfbfd;\n      --line: #e5e5ea;\n      --line-soft: #f0f0f3;\n      --text: #1d1d1f;\n      --text-2: #6e6e73;\n      --text-3: #86868b;\n      --accent: #5856d6;\n      --accent-bg: rgba(88, 86, 214, 0.06);\n      --accent-glow: rgba(88, 86, 214, 0.22);\n      --good: #16a34a;\n      --warn: #f59e0b;\n      --bad: #ef4444;\n      --btn: #ffffff;\n      --btn-hover: #f0f0f3;\n    }<\/p>\n<p>    \/* ===== BASE ===== *\/\n    *, *::before, *::after { box-sizing: border-box; }\n    html, body { margin: 0; padding: 0; background-color: var(--bg); }\n    body {\n      background-color: var(--bg);\n      color: var(--text);\n      font-family: -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n      overscroll-behavior-y: none;\n      min-height: 100vh;\n      min-height: 100dvh;\n      -webkit-font-smoothing: antialiased;\n      display: flex;\n      flex-direction: column;\n    }\n    button { font: inherit; color: inherit; }\n    .app {\n      max-width: 480px;\n      margin: 0 auto;\n      min-height: 100vh;\n      min-height: 100dvh;\n      padding: 16px 16px 120px;\n      background-color: var(--bg) !important;\n      color: var(--text);\n      flex: 1;\n      width: 100%;\n      box-sizing: border-box;\n      position: relative;\n    }\n    .app *, .app *::before, .app *::after { transition: background-color .25s ease, color .25s ease, border-color .25s ease; }<\/p>\n<p>    \/* ===== Cantonese font for zh-HK ===== *\/\n    :lang(zh-HK) {\n      font-family: -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"PingFang TC\", \"PingFang HK\", \"Hiragino Sans\", \"Microsoft JhengHei\", \"Noto Sans CJK TC\", sans-serif;\n    }\n    :lang(zh-HK) #timer-display,\n    :lang(zh-HK) .timer-pill {\n      font-family: -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"PingFang TC\", ui-monospace, \"SF Mono\", Menlo, monospace;\n      letter-spacing: 0.02em;\n    }<\/p>\n<p>    \/* ===== Top bar ===== *\/\n    .topbar { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 4px 4px 14px; }\n    .topbar h1 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }\n    .controls { display: flex; gap: 8px; align-items: center; }<\/p>\n<p>    \/* ===== Language toggle ===== *\/\n    .lang-toggle {\n      display: inline-flex;\n      align-items: center;\n      background: var(--btn);\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      padding: 2px;\n      height: 40px;\n      font-size: 11px;\n      font-weight: 700;\n      letter-spacing: 0.04em;\n    }\n    .lang-btn {\n      background: transparent;\n      border: 0;\n      padding: 4px 10px;\n      border-radius: 999px;\n      cursor: pointer;\n      color: var(--text-3);\n      font-weight: 700;\n      font-size: 11px;\n      letter-spacing: 0.04em;\n      transition: background .15s, color .15s;\n      min-width: 32px;\n      line-height: 1;\n    }\n    .lang-btn:hover { color: var(--text); }\n    .lang-btn.active {\n      background: var(--accent);\n      color: #fff;\n      box-shadow: 0 1px 3px rgba(0,0,0,0.25);\n    }<\/p>\n<p>    \/* ===== Timer pill ===== *\/\n    .timer-pill {\n      display: inline-flex;\n      align-items: center;\n      gap: 6px;\n      background: var(--btn);\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      padding: 0 14px;\n      height: 40px;\n      cursor: pointer;\n      font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n      font-size: 14px;\n      font-weight: 600;\n      color: var(--text-2);\n      transition: background .15s, color .15s;\n    }\n    .timer-pill:hover { background: var(--btn-hover); color: var(--text); }\n    .timer-pill.is-running {\n      background: rgba(52, 199, 89, 0.12);\n      border-color: rgba(52, 199, 89, 0.45);\n      color: var(--good);\n    }\n    [data-theme=\"light\"] .timer-pill.is-running {\n      background: rgba(22, 163, 74, 0.12);\n      border-color: rgba(22, 163, 74, 0.45);\n    }<\/p>\n<p>    @keyframes timer-pulse {\n      0%, 100% { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0.5); transform: scale(1); }\n      50%      { box-shadow: 0 0 0 5px rgba(52, 199, 89, 0); transform: scale(1.18); }\n    }\n    .timer-pill .play-dot {\n      width: 8px; height: 8px;\n      border-radius: 50%;\n      background: var(--text-3);\n      transition: none;\n      flex-shrink: 0;\n    }\n    .timer-pill.is-running .play-dot {\n      background: var(--good);\n      transition: none;\n    }\n    #timer-display { font-variant-numeric: tabular-nums; font-size: 15px; }<\/p>\n<p>    \/* ===== Icon buttons ===== *\/\n    .icon-btn {\n      width: 40px;\n      height: 40px;\n      border-radius: 50%;\n      background: var(--btn);\n      border: 1px solid var(--line);\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      cursor: pointer;\n      color: var(--text-2);\n      transition: background .15s, transform .1s, color .15s;\n    }\n    .icon-btn:hover { background: var(--btn-hover); color: var(--text); transform: scale(1.05); }\n    .icon-btn:active { transform: scale(0.92); }\n    .icon-btn svg { width: 18px; height: 18px; }<\/p>\n<p>    \/* ===== Theme toggle: show current state more clearly ===== *\/\n    .theme-toggle { position: relative; }\n    .theme-toggle .moon,\n    .theme-toggle .sun {\n      position: absolute;\n      inset: 0;\n      margin: auto;\n      transition: opacity .2s, transform .2s, color .2s;\n    }\n    .theme-toggle .sun { opacity: 0; transform: rotate(-90deg) scale(0.6); }\n    .theme-toggle .moon { opacity: 1; transform: rotate(0) scale(1); color: var(--accent); }\n    [data-theme=\"light\"] .theme-toggle .sun { opacity: 1; transform: rotate(0) scale(1); color: #f59e0b; }\n    [data-theme=\"light\"] .theme-toggle .moon { opacity: 0; transform: rotate(90deg) scale(0.6); }\n    \/* When html has no data-theme (auto mode), show half-accent icon *\/\n    html:not([data-theme]) .theme-toggle { color: var(--accent); }<\/p>\n<p>    \/* ===== Score box ===== *\/\n    .score-box {\n      background-color: var(--card);\n      border: 1px solid var(--line);\n      border-radius: 16px;\n      padding: 22px 20px;\n      text-align: center;\n      margin-bottom: 14px;\n    }\n    .serving-indicator {\n      color: var(--accent);\n      font-size: 11px;\n      font-weight: 700;\n      letter-spacing: 0.12em;\n      text-transform: uppercase;\n      margin-bottom: 12px;\n    }\n    .main-score {\n      font-size: 56px;\n      font-weight: 700;\n      letter-spacing: -0.02em;\n      color: var(--text);\n      line-height: 1;\n      margin-bottom: 12px;\n      font-variant-numeric: tabular-nums;\n    }\n    .main-score.bump { animation: scoreBump .35s ease-out; }\n    @keyframes scoreBump {\n      0% { transform: scale(1); }\n      40% { transform: scale(1.08); }\n      100% { transform: scale(1); }\n    }\n    .score-legend { display: flex; justify-content: center; align-items: center; gap: 8px; color: var(--text-2); font-size: 11px; }\n    .score-legend .dot { color: var(--text-3); font-size: 8px; }<\/p>\n<p>    \/* ===== Teams grid ===== *\/\n    .teams-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }\n    .team-box {\n      background-color: var(--card);\n      border: 1px solid var(--line);\n      border-radius: 14px;\n      padding: 14px 12px;\n      text-align: center;\n      transition: border-color .2s, background-color .2s;\n    }\n    .team-box.is-serving {\n      border-color: var(--accent);\n      background-color: var(--accent-bg);\n      box-shadow: 0 0 0 1px var(--accent), 0 0 24px var(--accent-glow);\n    }\n    .team-label { color: var(--text-2); font-size: 10px; font-weight: 700; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.06em; }\n    .team-score {\n      font-size: 32px;\n      font-weight: 700;\n      color: var(--text);\n      font-variant-numeric: tabular-nums;\n      line-height: 1;\n    }\n    .team-score.bump { animation: scoreBump .35s ease-out; }<\/p>\n<p>    \/* ===== Status bar ===== *\/\n    .status-bar {\n      background-color: var(--card);\n      border: 1px solid var(--line);\n      border-radius: 14px;\n      padding: 12px 14px;\n      display: flex;\n      align-items: center;\n      gap: 10px;\n    }\n    #status-dot {\n      width: 8px; height: 8px; border-radius: 50%;\n      background: var(--good);\n      box-shadow: 0 0 8px rgba(50, 215, 75, 0.6);\n      flex-shrink: 0;\n    }\n    #status-dot.over { background: var(--accent); box-shadow: 0 0 8px var(--accent-glow); }\n    #status-text { font-size: 14px; color: var(--text); }<\/p>\n<p>    \/* ===== Footer info ===== *\/\n    .footer-info { display: flex; justify-content: center; align-items: center; gap: 32px; margin-top: 32px; }\n    .footer-col { display: flex; flex-direction: column; align-items: center; text-align: center; }\n    .footer-col .label { color: var(--text-2); font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 4px; }\n    .footer-col .value { font-size: 15px; font-weight: 600; color: var(--text); }\n    .footer-divider { width: 1px; height: 32px; background: var(--line); }<\/p>\n<p>    \/* ===== Action bar ===== *\/\n    .action-bar {\n      position: fixed;\n      bottom: 0;\n      left: 50%;\n      transform: translateX(-50%);\n      width: 100%;\n      max-width: 480px;\n      padding: 14px 16px calc(14px + env(safe-area-inset-bottom));\n      background: rgba(0, 0, 0, 0.85);\n      backdrop-filter: blur(12px);\n      -webkit-backdrop-filter: blur(12px);\n      border-top: 1px solid var(--line-soft);\n      z-index: 10;\n    }\n    .action-bar-row { display: flex; gap: 10px; }\n    .btn-action {\n      flex: 1;\n      background-color: var(--btn);\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      padding: 14px 12px;\n      text-align: center;\n      font-size: 13px;\n      font-weight: 600;\n      color: var(--text);\n      cursor: pointer;\n      transition: background-color .15s, transform .1s;\n    }\n    .btn-action:hover { background-color: var(--btn-hover); }\n    .btn-action:active { transform: scale(0.97); }\n    .btn-action:disabled { opacity: 0.4; pointer-events: none; }<\/p>\n<p>    \/* ===== Toast ===== *\/\n    .toast {\n      position: fixed;\n      top: 14px;\n      left: 50%;\n      transform: translateX(-50%) translateY(-80px);\n      background: var(--card-2);\n      color: var(--text);\n      border: 1px solid var(--line);\n      border-radius: 12px;\n      padding: 10px 18px;\n      font-size: 14px;\n      font-weight: 600;\n      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n      transition: transform .3s ease, opacity .3s ease;\n      opacity: 0;\n      pointer-events: none;\n      z-index: 50;\n      max-width: 90%;\n      text-align: center;\n    }\n    .toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }<\/p>\n<p>    \/* ===== Settings sheet ===== *\/\n    .sheet-overlay {\n      position: fixed;\n      inset: 0;\n      background: rgba(0, 0, 0, 0.5);\n      opacity: 0;\n      pointer-events: none;\n      transition: opacity .2s;\n      z-index: 30;\n    }\n    .sheet-overlay.open { opacity: 1; pointer-events: auto; }\n    .sheet {\n      position: fixed;\n      bottom: 0;\n      left: 50%;\n      transform: translateX(-50%) translateY(100%);\n      width: 100%;\n      max-width: 480px;\n      background-color: var(--card-2);\n      border-top-left-radius: 22px;\n      border-top-right-radius: 22px;\n      padding: 12px 22px calc(24px + env(safe-area-inset-bottom));\n      transition: transform .3s ease;\n      z-index: 31;\n      max-height: 80vh;\n      overflow-y: auto;\n    }\n    .sheet .grabber {\n      width: 36px;\n      height: 4px;\n      border-radius: 999px;\n      background: var(--text-3);\n      margin: 0 auto 14px;\n      opacity: 0.5;\n    }\n    .sheet h2 { margin: 0 0 16px; font-size: 17px; font-weight: 700; }\n    .setting-row {\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      padding: 14px 0;\n      border-bottom: 1px solid var(--line);\n    }\n    .setting-row:last-child { border-bottom: 0; }\n    .setting-row .label { font-size: 15px; font-weight: 600; margin-bottom: 2px; }\n    .setting-row .desc { font-size: 12px; color: var(--text-2); }\n    .seg {\n      display: inline-flex;\n      background: var(--btn);\n      border: 1px solid var(--line);\n      border-radius: 999px;\n      padding: 2px;\n      font-size: 12px;\n      font-weight: 700;\n    }\n    .seg button {\n      background: transparent;\n      border: 0;\n      padding: 6px 12px;\n      border-radius: 999px;\n      color: var(--text-3);\n      cursor: pointer;\n      transition: background .15s, color .15s;\n      font-weight: 700;\n      font-size: 12px;\n    }\n    .seg button:hover { color: var(--text); }\n    .seg button.on {\n      background: var(--accent);\n      color: #fff;\n    }<\/p>\n<p>    @media (prefers-reduced-motion: reduce) {<\/p>\n<p>      *, *::before, *::after { transition-duration: 0.01ms !important; }\n    }\n  <\/style>\n<div style=\"background:linear-gradient(135deg,#34c759,#1a7f37);color:#fff;padding:12px 20px;text-align:center;font-weight:600;font-size:13px;letter-spacing:.04em;\">\n  Pickleball Score Tracker\n<\/div>\n<div style=\"padding:12px 20px;text-align:center;font-size:13px;color:#a1a1a6;background:#151516;\">\n  <a href=\"\/\" style=\"color:#8b8cf8;text-decoration:underline;\">Back to comparetiger.com<\/a>\n<\/div>\n<div class=\"app\">\n    <!-- Top bar --><\/p>\n<div class=\"topbar\">\n<h1 data-i18n=\"title\">Pickleball Score Tracker<\/h1>\n<div class=\"controls\">\n<div id=\"lang-toggle\" class=\"lang-toggle\" role=\"group\" aria-label=\"Language\">\n          <button class=\"lang-btn active\" data-lang=\"en\" type=\"button\">EN<\/button><br \/>\n          <button class=\"lang-btn\" data-lang=\"zh-HK\" type=\"button\">\u7e41\u9ad4<\/button>\n        <\/div>\n<p>        <button id=\"timer-pill\" class=\"timer-pill\" title=\"Start \/ Pause Timer\" aria-label=\"Timer\"><br \/>\n          <span class=\"play-dot\"><\/span><br \/>\n          <span id=\"timer-display\">00:00<\/span><br \/>\n        <\/button><br \/>\n        <button id=\"theme-toggle\" class=\"icon-btn theme-toggle\" aria-label=\"Toggle theme\"><br \/>\n          <svg class=\"moon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n            <path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\"\/>\n          <\/svg><br \/>\n          <svg class=\"sun\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n            <circle cx=\"12\" cy=\"12\" r=\"4\"\/>\n            <path d=\"M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41\"\/>\n          <\/svg><br \/>\n        <\/button><br \/>\n        <button id=\"settings-btn\" class=\"icon-btn\" aria-label=\"Settings\"><br \/>\n          <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n            <circle cx=\"12\" cy=\"12\" r=\"3\"\/>\n            <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"\/>\n          <\/svg><br \/>\n        <\/button><br \/>\n        <button id=\"reset-btn\" class=\"icon-btn\" aria-label=\"Reset game\" title=\"Reset game\"><br \/>\n          <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n            <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"\/><path d=\"M3 3v5h5\"\/>\n          <\/svg><br \/>\n        <\/button>\n      <\/div>\n<\/p><\/div>\n<p>    <!-- Score Display Box --><\/p>\n<div class=\"score-box\">\n<div id=\"serving-indicator-text\" class=\"serving-indicator\" data-i18n=\"servingIndicatorA\">Team A Serving<\/div>\n<div id=\"main-score\" class=\"main-score\">0-0-2<\/div>\n<div class=\"score-legend\">\n        <span data-i18n=\"server_score\">Server Score<\/span><br \/>\n        <span class=\"dot\">&bull;<\/span><br \/>\n        <span data-i18n=\"receiver_score\">Receiver Score<\/span><br \/>\n        <span class=\"dot\">&bull;<\/span><br \/>\n        <span data-i18n=\"server_num\">Server #<\/span>\n      <\/div>\n<\/p><\/div>\n<p>    <!-- Team Scores Grid --><\/p>\n<div class=\"teams-grid\">\n<div id=\"team-a-box\" class=\"team-box is-serving\">\n<div id=\"team-a-label\" class=\"team-label\" data-i18n=\"teamA_serving\">Team A (Serving)<\/div>\n<div id=\"team-a-score\" class=\"team-score\">0<\/div>\n<\/p><\/div>\n<div id=\"team-b-box\" class=\"team-box\">\n<div id=\"team-b-label\" class=\"team-label\" data-i18n=\"teamB_receiving\">Team B (Receiving)<\/div>\n<div id=\"team-b-score\" class=\"team-score\">0<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>    <!-- Status Bar --><\/p>\n<div class=\"status-bar\">\n<div id=\"status-dot\"><\/div>\n<div id=\"status-text\">New Game Started (0-0-2 rule)<\/div>\n<\/p><\/div>\n<p>    <!-- Footer Info --><\/p>\n<div class=\"footer-info\">\n<div class=\"footer-col\">\n        <span class=\"label\" data-i18n=\"footer_score\">Score<\/span><br \/>\n        <span id=\"footer-score\" class=\"value\">0-0-2<\/span>\n      <\/div>\n<div class=\"footer-divider\"><\/div>\n<div class=\"footer-col\">\n        <span class=\"label\" data-i18n=\"footer_status\">Status<\/span><br \/>\n        <span id=\"footer-status\" class=\"value\">New Game<\/span>\n      <\/div>\n<\/p><\/div>\n<p>    <!-- Fixed Bottom Controls --><\/p>\n<div class=\"action-bar\">\n<div class=\"action-bar-row\">\n        <button id=\"btn-win\" class=\"btn-action win\" data-i18n=\"btn_serving_wins\">Serving Team Wins Rally<\/button><br \/>\n        <button id=\"btn-lose\" class=\"btn-action lose\" data-i18n=\"btn_receiving_wins\">Receiving Team Wins Rally<\/button>\n      <\/div>\n<\/p><\/div>\n<p>    <!-- Toast --><\/p>\n<div class=\"toast\" id=\"toast\"><\/div>\n<p>    <!-- Settings sheet --><\/p>\n<div class=\"sheet-overlay\" id=\"sheet-overlay\"><\/div>\n<div class=\"sheet\" id=\"sheet\">\n<div class=\"grabber\"><\/div>\n<h2 data-i18n=\"settings_title\">Settings<\/h2>\n<div class=\"setting-row\">\n<div>\n<div class=\"label\" data-i18n=\"theme_label\">Theme<\/div>\n<div class=\"desc\" data-i18n=\"theme_desc\">Light, Dark, or follow your device<\/div>\n<\/p><\/div>\n<div class=\"seg\" id=\"theme-seg\">\n          <button data-mode=\"light\" data-i18n=\"theme_light\">Light<\/button><br \/>\n          <button data-mode=\"auto\" data-i18n=\"theme_auto\">Auto<\/button><br \/>\n          <button data-mode=\"dark\" data-i18n=\"theme_dark\">Dark<\/button>\n        <\/div>\n<\/p><\/div>\n<div class=\"setting-row\">\n<div>\n<div class=\"label\" data-i18n=\"game_length\">Game length<\/div>\n<div class=\"desc\" data-i18n=\"game_length_desc\">Points to win &#8211; win by 2<\/div>\n<\/p><\/div>\n<div class=\"seg\" id=\"target-seg\">\n          <button data-target=\"11\">11<\/button><br \/>\n          <button data-target=\"15\">15<\/button><br \/>\n          <button data-target=\"21\">21<\/button>\n        <\/div>\n<\/p><\/div>\n<div class=\"setting-row\">\n<div>\n<div class=\"label\" data-i18n=\"auto_timer\">Auto timer<\/div>\n<div class=\"desc\" data-i18n=\"auto_timer_desc\">Start timer on first rally<\/div>\n<\/p><\/div>\n<div class=\"seg\" id=\"auto-timer-seg\">\n          <button data-on=\"false\" data-i18n=\"off\">Off<\/button><br \/>\n          <button data-on=\"true\" data-i18n=\"on\">On<\/button>\n        <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p><script>\n    \/\/ ============================================================\n    \/\/ I18N: English \/ Cantonese Traditional Chinese (zh-HK)\n    \/\/ ============================================================\n    var SUPPORTED_LANGS = [\"en\", \"zh-HK\"];\n    var STRINGS = {\n      \"en\": {\n        \"title\": \"Pickleball Score Tracker\",\n        \"servingIndicatorA\": \"Team A Serving\",\n        \"servingIndicatorB\": \"Team B Serving\",\n        \"teamA_serving\": \"Team A (Serving)\",\n        \"teamA_receiving\": \"Team A (Receiving)\",\n        \"teamB_serving\": \"Team B (Serving)\",\n        \"teamB_receiving\": \"Team B (Receiving)\",\n        \"msg_point\": \"Point scored! Server switches sides.\",\n        \"msg_fault\": \"Fault! Second server takes over.\",\n        \"msg_side_out_prefix\": \"Side Out! Ball goes to Team \",\n        \"msg_game_over_prefix\": \"Game Over! Team \",\n        \"status_default\": \"New Game Started (0-0-2 rule)\",\n        \"status_point\": \"Point Scored\",\n        \"status_2nd_server\": \"2nd Server\",\n        \"status_side_out\": \"Side Out\",\n        \"status_new_game\": \"New Game\",\n        \"status_game_over\": \"Game Over\",\n        \"toast_win_suffix\": \" wins \",\n        \"confirm_reset\": \"Reset game? Current score will be lost.\",\n        \"btn_serving_wins\": \"Serving Team Wins Rally\",\n        \"btn_receiving_wins\": \"Receiving Team Wins Rally\",\n        \"theme_light\": \"Light\",\n        \"theme_auto\": \"Auto\",\n        \"theme_dark\": \"Dark\",\n        \"theme_label\": \"Theme\",\n        \"theme_desc\": \"Light, Dark, or follow your device\",\n        \"game_length\": \"Game length\",\n        \"game_length_desc\": \"Points to win - win by 2\",\n        \"auto_timer\": \"Auto timer\",\n        \"auto_timer_desc\": \"Start timer on first rally\",\n        \"off\": \"Off\",\n        \"on\": \"On\",\n        \"settings_title\": \"Settings\",\n        \"server_score\": \"Server Score\",\n        \"receiver_score\": \"Receiver Score\",\n        \"server_num\": \"Server #\",\n        \"footer_score\": \"Score\",\n        \"footer_status\": \"Status\",\n        \"timer_title\": \"Start \/ Pause Timer\",\n        \"theme_toggle_aria\": \"Toggle theme\",\n        \"settings_aria\": \"Settings\",\n        \"reset_aria\": \"Reset game\",\n        \"lang_aria\": \"Language\"\n      },\n      \"zh-HK\": {\n        \"title\": \"\u5339\u514b\u7403\u8a08\u5206\u677f\",\n        \"servingIndicatorA\": \"A \u968a\u958b\u7403\",\n        \"servingIndicatorB\": \"B \u968a\u958b\u7403\",\n        \"teamA_serving\": \"A \u968a\uff08\u958b\u7403\uff09\",\n        \"teamA_receiving\": \"A \u968a\uff08\u63a5\u6ce2\uff09\",\n        \"teamB_serving\": \"B \u968a\uff08\u958b\u7403\uff09\",\n        \"teamB_receiving\": \"B \u968a\uff08\u63a5\u6ce2\uff09\",\n        \"msg_point\": \"\u5f97\u5206\uff01\u958b\u6ce2\u65b9\u8f49\u908a\u3002\",\n        \"msg_fault\": \"\u72af\u898f\uff01\u7b2c\u4e8c\u4f4d\u958b\u7403\u54e1\u4e0a\u5834\u3002\",\n        \"msg_side_out_prefix\": \"\u63db\u908a\uff01\u6ce2\u8f2a\u5230 \",\n        \"msg_game_over_prefix\": \"\u6bd4\u8cfd\u7d50\u675f\uff01\",\n        \"status_default\": \"\u65b0\u4e00\u5c40\u958b\u59cb\uff080-0-2 \u898f\u5247\uff09\",\n        \"status_point\": \"\u5f97\u5206\",\n        \"status_2nd_server\": \"\u7b2c\u4e8c\u4f4d\u958b\u7403\u54e1\",\n        \"status_side_out\": \"\u63db\u908a\",\n        \"status_new_game\": \"\u65b0\u5c40\",\n        \"status_game_over\": \"\u6bd4\u8cfd\u7d50\u675f\",\n        \"toast_win_suffix\": \"\u968a\u8d0f \",\n        \"confirm_reset\": \"\u78ba\u5b9a\u8981\u91cd\u8a2d\u6bd4\u8cfd\uff1f\u76ee\u524d\u5206\u6578\u6703\u88ab\u6e05\u9664\u3002\",\n        \"btn_serving_wins\": \"\u958b\u7403\u65b9\u5f97\u5206\",\n        \"btn_receiving_wins\": \"\u63a5\u6ce2\u65b9\u5f97\u5206\",\n        \"theme_light\": \"\u6dfa\u8272\",\n        \"theme_auto\": \"\u81ea\u52d5\",\n        \"theme_dark\": \"\u6df1\u8272\",\n        \"theme_label\": \"\u4e3b\u984c\",\n        \"theme_desc\": \"\u6dfa\u8272\u3001\u6df1\u8272\uff0c\u6216\u8ddf\u88dd\u7f6e\u8a2d\u5b9a\",\n        \"game_length\": \"\u5c40\u5206\",\n        \"game_length_desc\": \"\u52dd\u5206 - \u9808\u8d0f\u5169\u5206\",\n        \"auto_timer\": \"\u81ea\u52d5\u8a08\u6642\",\n        \"auto_timer_desc\": \"\u7b2c\u4e00\u6b21\u5f97\u5206\u6642\u958b\u59cb\u8a08\u6642\",\n        \"off\": \"\u95dc\",\n        \"on\": \"\u958b\",\n        \"settings_title\": \"\u8a2d\u5b9a\",\n        \"server_score\": \"\u958b\u6ce2\u65b9\u5206\u6578\",\n        \"receiver_score\": \"\u63a5\u6ce2\u65b9\u5206\u6578\",\n        \"server_num\": \"\u958b\u6ce2\u54e1 #\",\n        \"footer_score\": \"\u6bd4\u5206\",\n        \"footer_status\": \"\u72c0\u614b\",\n        \"timer_title\": \"\u958b\u59cb\uff0f\u66ab\u505c\u8a08\u6642\",\n        \"theme_toggle_aria\": \"\u5207\u63db\u4e3b\u984c\",\n        \"settings_aria\": \"\u8a2d\u5b9a\",\n        \"reset_aria\": \"\u91cd\u8a2d\u6bd4\u8cfd\",\n        \"lang_aria\": \"\u8a9e\u8a00\"\n      }\n    };<\/p>\n<p>    var currentLang = \"en\";\n    function t(key) {\n      return (STRINGS[currentLang] && STRINGS[currentLang][key]) ||\n             (STRINGS.en && STRINGS.en[key]) ||\n             key;\n    }\n    function applyLang() {\n      document.documentElement.setAttribute(\"lang\", currentLang);\n      var els = document.querySelectorAll(\"[data-i18n]\");\n      for (var i = 0; i < els.length; i++) {\n        var key = els[i].getAttribute(\"data-i18n\");\n        var val = t(key);\n        if (val) els[i].innerText = val;\n      }\n      var ariaMap = {\n        \"timer-pill\": \"timer_title\",\n        \"theme-toggle\": \"theme_toggle_aria\",\n        \"settings-btn\": \"settings_aria\",\n        \"reset-btn\": \"reset_aria\",\n        \"lang-toggle\": \"lang_aria\"\n      };\n      for (var id in ariaMap) {\n        var el = document.getElementById(id);\n        if (el) el.setAttribute(\"aria-label\", t(ariaMap[id]));\n      }\n      var tp = document.getElementById(\"timer-pill\");\n      if (tp) tp.setAttribute(\"title\", t(\"timer_title\"));\n      var langBtns = document.querySelectorAll(\"#lang-toggle .lang-btn\");\n      for (var j = 0; j < langBtns.length; j++) {\n        langBtns[j].classList.toggle(\"active\", langBtns[j].dataset.lang === currentLang);\n      }\n      if (typeof updateDisplay === \"function\") updateDisplay();\n    }\n    function setLang(lang) {\n      if (SUPPORTED_LANGS.indexOf(lang) === -1) return;\n      currentLang = lang;\n      try { localStorage.setItem(\"pickleball-lang\", lang); } catch (e) {}\n      applyLang();\n    }\n\n    \/\/ Game State\n    var teamAScore = 0;\n    var teamBScore = 0;\n    var servingTeam = \"A\";\n    var serverNumber = 2;\n    var gameOver = false;\n    var targetScore = 11;\n\n    var timerInterval = null;\n    var secondsElapsed = 0;\n    var isTimerRunning = false;\n    var autoTimer = true;\n    var themeMode = \"auto\";\n\n    function pad(n) { return n < 10 ? \"0\" + n : \"\" + n; }\n    function formatTime(totalSeconds) {\n      return pad(Math.floor(totalSeconds \/ 60)) + \":\" + pad(totalSeconds % 60);\n    }\n    function updateTimerDisplay() {\n      document.getElementById(\"timer-display\").innerText = formatTime(secondsElapsed);\n      var pill = document.getElementById(\"timer-pill\");\n      if (pill) pill.classList.toggle(\"is-running\", isTimerRunning);\n    }\n    function startTimer() {\n      if (!isTimerRunning &#038;&#038; !gameOver) {\n        isTimerRunning = true;\n        if (timerInterval) clearInterval(timerInterval);\n        timerInterval = setInterval(function () {\n          secondsElapsed++;\n          updateTimerDisplay();\n        }, 1000);\n        updateTimerDisplay();\n      }\n    }\n    function stopTimer() {\n      if (isTimerRunning) {\n        isTimerRunning = false;\n        if (timerInterval) { clearInterval(timerInterval); timerInterval = null; }\n        updateTimerDisplay();\n      }\n    }\n    function toggleTimer() {\n      if (isTimerRunning) stopTimer(); else startTimer();\n    }\n    function resetTimer() {\n      stopTimer();\n      secondsElapsed = 0;\n      updateTimerDisplay();\n    }\n\n    function bumpScore(el) {\n      el.classList.remove(\"bump\");\n      void el.offsetWidth;\n      el.classList.add(\"bump\");\n    }\n\n    function updateDisplay(message, shortStatus) {\n      var serverScore = servingTeam === \"A\" ? teamAScore : teamBScore;\n      var receiverScore = servingTeam === \"A\" ? teamBScore : teamAScore;\n      var scoreStr = serverScore + \"-\" + receiverScore + \"-\" + serverNumber;\n\n      document.getElementById(\"main-score\").innerText = scoreStr;\n      document.getElementById(\"footer-score\").innerText = scoreStr;\n      document.getElementById(\"team-a-score\").innerText = teamAScore;\n      document.getElementById(\"team-b-score\").innerText = teamBScore;\n\n      var teamABox = document.getElementById(\"team-a-box\");\n      var teamBBox = document.getElementById(\"team-b-box\");\n      var teamALabel = document.getElementById(\"team-a-label\");\n      var teamBLabel = document.getElementById(\"team-b-label\");\n      var indicator = document.getElementById(\"serving-indicator-text\");\n\n      if (servingTeam === \"A\") {\n        teamABox.classList.add(\"is-serving\");\n        teamBBox.classList.remove(\"is-serving\");\n        teamALabel.innerText = t(\"teamA_serving\");\n        teamBLabel.innerText = t(\"teamB_receiving\");\n        indicator.innerText = t(\"servingIndicatorA\");\n      } else {\n        teamBBox.classList.add(\"is-serving\");\n        teamABox.classList.remove(\"is-serving\");\n        teamBLabel.innerText = t(\"teamB_serving\");\n        teamALabel.innerText = t(\"teamA_receiving\");\n        indicator.innerText = t(\"servingIndicatorB\");\n      }\n\n      if (message) document.getElementById(\"status-text\").innerText = message;\n      if (shortStatus) document.getElementById(\"footer-status\").innerText = shortStatus;\n    }\n\n    function serverWins() {\n      if (gameOver) return;\n      if (autoTimer &#038;&#038; !isTimerRunning &#038;&#038; secondsElapsed === 0) startTimer();\n      var ms = document.getElementById(\"main-score\");\n      var ts = document.getElementById(servingTeam === \"A\" ? \"team-a-score\" : \"team-b-score\");\n      if (servingTeam === \"A\") teamAScore++; else teamBScore++;\n      bumpScore(ms);\n      bumpScore(ts);\n      updateDisplay(t(\"msg_point\"), t(\"status_point\"));\n      checkWin();\n    }\n\n    function receiverWins() {\n      if (gameOver) return;\n      if (autoTimer &#038;&#038; !isTimerRunning &#038;&#038; secondsElapsed === 0) startTimer();\n      var ms = document.getElementById(\"main-score\");\n      bumpScore(ms);\n      if (serverNumber === 1) {\n        serverNumber = 2;\n        updateDisplay(t(\"msg_fault\"), t(\"status_2nd_server\"));\n      } else {\n        servingTeam = servingTeam === \"A\" ? \"B\" : \"A\";\n        serverNumber = 1;\n        updateDisplay(t(\"msg_side_out_prefix\") + servingTeam + \".\", t(\"status_side_out\"));\n      }\n      checkWin();\n    }\n\n    function checkWin() {\n      var aWins = teamAScore >= targetScore && teamAScore - teamBScore >= 2;\n      var bWins = teamBScore >= targetScore && teamBScore - teamAScore >= 2;\n      if (aWins || bWins) {\n        gameOver = true;\n        stopTimer();\n        var winner = aWins ? \"A\" : \"B\";\n        var timeStr = formatTime(secondsElapsed);\n        var toastWinner;\n        if (currentLang === \"zh-HK\") {\n          toastWinner = winner + t(\"toast_win_suffix\") + teamAScore + \"-\" + teamBScore;\n        } else {\n          toastWinner = \"Team \" + winner + t(\"toast_win_suffix\") + teamAScore + \"-\" + teamBScore;\n        }\n        updateDisplay(t(\"msg_game_over_prefix\") + winner + \" (\" + timeStr + \")\", t(\"status_game_over\"));\n        var dot = document.getElementById(\"status-dot\");\n        if (dot) dot.classList.add(\"over\");\n        showToast(toastWinner);\n        document.getElementById(\"btn-win\").disabled = true;\n        document.getElementById(\"btn-lose\").disabled = true;\n      }\n    }<\/p>\n<p>    function resetGame() {\n      teamAScore = 0;\n      teamBScore = 0;\n      servingTeam = \"A\";\n      serverNumber = 2;\n      gameOver = false;\n      resetTimer();\n      var dot = document.getElementById(\"status-dot\");\n      if (dot) dot.classList.remove(\"over\");\n      document.getElementById(\"btn-win\").disabled = false;\n      document.getElementById(\"btn-lose\").disabled = false;\n      updateDisplay(t(\"status_default\"), t(\"status_new_game\"));\n    }<\/p>\n<p>    function showToast(msg) {\n      var tEl = document.getElementById(\"toast\");\n      if (!tEl) return;\n      tEl.innerText = msg;\n      tEl.classList.add(\"show\");\n      if (showToast._t) clearTimeout(showToast._t);\n      showToast._t = setTimeout(function () { tEl.classList.remove(\"show\"); }, 2200);\n    }<\/p>\n<p>    function applyTheme() {\n      var html = document.documentElement;\n      if (themeMode === \"light\") html.setAttribute(\"data-theme\", \"light\");\n      else if (themeMode === \"dark\") html.setAttribute(\"data-theme\", \"dark\");\n      else html.removeAttribute(\"data-theme\");\n      var btns = document.querySelectorAll(\"#theme-seg button\");\n      for (var i = 0; i < btns.length; i++) {\n        btns[i].classList.toggle(\"on\", btns[i].dataset.mode === themeMode);\n      }\n    }\n    function quickToggleTheme() {\n      if (themeMode === \"auto\") themeMode = \"dark\";\n      else if (themeMode === \"dark\") themeMode = \"light\";\n      else themeMode = \"dark\";\n      applyTheme();\n    }\n\n    function openSheet() {\n      document.getElementById(\"sheet-overlay\").classList.add(\"open\");\n      document.getElementById(\"sheet\").style.transform = \"translateX(-50%) translateY(0)\";\n      var tBtns = document.querySelectorAll(\"#theme-seg button\");\n      for (var i = 0; i < tBtns.length; i++) {\n        tBtns[i].classList.toggle(\"on\", tBtns[i].dataset.mode === themeMode);\n      }\n      var tgBtns = document.querySelectorAll(\"#target-seg button\");\n      for (var j = 0; j < tgBtns.length; j++) {\n        tgBtns[j].classList.toggle(\"on\", parseInt(tgBtns[j].dataset.target, 10) === targetScore);\n      }\n      var atBtns = document.querySelectorAll(\"#auto-timer-seg button\");\n      for (var k = 0; k < atBtns.length; k++) {\n        atBtns[k].classList.toggle(\"on\", atBtns[k].dataset.on === String(autoTimer));\n      }\n    }\n    function closeSheet() {\n      document.getElementById(\"sheet-overlay\").classList.remove(\"open\");\n      document.getElementById(\"sheet\").style.transform = \"translateX(-50%) translateY(100%)\";\n    }\n\n    function init() {\n      \/\/ Load saved language preference\n      try {\n        var savedLang = localStorage.getItem(\"pickleball-lang\");\n        if (savedLang &#038;&#038; SUPPORTED_LANGS.indexOf(savedLang) !== -1) {\n          currentLang = savedLang;\n        }\n      } catch (e) {}\n\n      \/\/ Load saved settings\n      try {\n        var saved = localStorage.getItem(\"pickleball-settings\");\n        if (saved) {\n          var s = JSON.parse(saved);\n          if (s.themeMode) themeMode = s.themeMode;\n          if (s.targetScore) targetScore = s.targetScore;\n          if (typeof s.autoTimer === \"boolean\") autoTimer = s.autoTimer;\n        }\n      } catch (e) {}\n\n      \/\/ Pre-paint theme\n      if (themeMode === \"light\") document.documentElement.setAttribute(\"data-theme\", \"light\");\n      else if (themeMode === \"dark\") document.documentElement.setAttribute(\"data-theme\", \"dark\");\n      else {\n        var prefersDark = window.matchMedia &#038;&#038; window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n        if (!prefersDark) document.documentElement.setAttribute(\"data-theme\", \"light\");\n      }\n\n      applyLang();\n\n      document.getElementById(\"btn-win\").addEventListener(\"click\", serverWins);\n      document.getElementById(\"btn-lose\").addEventListener(\"click\", receiverWins);\n      document.getElementById(\"timer-pill\").addEventListener(\"click\", toggleTimer);\n      document.getElementById(\"reset-btn\").addEventListener(\"click\", function () {\n        if (teamAScore === 0 &#038;&#038; teamBScore === 0) { resetGame(); return; }\n        if (confirm(t(\"confirm_reset\"))) resetGame();\n      });\n      document.getElementById(\"theme-toggle\").addEventListener(\"click\", function () {\n        quickToggleTheme();\n        saveSettings();\n      });\n      document.getElementById(\"settings-btn\").addEventListener(\"click\", openSheet);\n      document.getElementById(\"sheet-overlay\").addEventListener(\"click\", closeSheet);\n\n      \/\/ Language toggle\n      var langBtns = document.querySelectorAll(\"#lang-toggle .lang-btn\");\n      for (var li = 0; li < langBtns.length; li++) {\n        langBtns[li].addEventListener(\"click\", function (e) {\n          setLang(e.currentTarget.dataset.lang);\n        });\n      }\n\n      \/\/ Theme segmented\n      var themeBtns = document.querySelectorAll(\"#theme-seg button\");\n      for (var i = 0; i < themeBtns.length; i++) {\n        themeBtns[i].addEventListener(\"click\", function (e) {\n          themeMode = e.target.dataset.mode;\n          applyTheme();\n          saveSettings();\n        });\n      }\n\n      \/\/ Target score segmented\n      var targetBtns = document.querySelectorAll(\"#target-seg button\");\n      for (var j = 0; j < targetBtns.length; j++) {\n        targetBtns[j].addEventListener(\"click\", function (e) {\n          targetScore = parseInt(e.target.dataset.target, 10);\n          var btns = document.querySelectorAll(\"#target-seg button\");\n          for (var m = 0; m < btns.length; m++) btns[m].classList.toggle(\"on\", btns[m] === e.target);\n          saveSettings();\n        });\n      }\n\n      \/\/ Auto timer segmented\n      var autoBtns = document.querySelectorAll(\"#auto-timer-seg button\");\n      for (var k = 0; k < autoBtns.length; k++) {\n        autoBtns[k].addEventListener(\"click\", function (e) {\n          autoTimer = e.target.dataset.on === \"true\";\n          var btns = document.querySelectorAll(\"#auto-timer-seg button\");\n          for (var n = 0; n < btns.length; n++) btns[n].classList.toggle(\"on\", btns[n] === e.target);\n          saveSettings();\n        });\n      }\n\n      \/\/ Keyboard shortcuts\n      document.addEventListener(\"keydown\", function (e) {\n        if (e.target &#038;&#038; e.target.tagName === \"INPUT\") return;\n        if (e.key === \"w\" || e.key === \"W\") serverWins();\n        else if (e.key === \"l\" || e.key === \"L\") receiverWins();\n        else if (e.key === \" \") { e.preventDefault(); toggleTimer(); }\n        else if (e.key === \"Escape\") closeSheet();\n      });\n\n      \/\/ Pause timer when tab hidden\n      document.addEventListener(\"visibilitychange\", function () {\n        if (document.hidden &#038;&#038; isTimerRunning) stopTimer();\n      });\n\n      resetGame();\n    }\n\n    function saveSettings() {\n      try {\n        localStorage.setItem(\"pickleball-settings\", JSON.stringify({\n          themeMode: themeMode,\n          targetScore: targetScore,\n          autoTimer: autoTimer\n        }));\n      } catch (e) {}\n    }\n\n    if (document.readyState === \"loading\") {\n      document.addEventListener(\"DOMContentLoaded\", init);\n    } else {\n      init();\n    }\n  <\/script><br \/>\n<script>\n    \/\/ ============================================================\n    \/\/ I18N: English \/ Cantonese Traditional Chinese (zh-HK)\n    \/\/ ============================================================\n    var SUPPORTED_LANGS = [\"en\", \"zh-HK\"];\n    var STRINGS = {\n      \"en\": {\n        \"title\": \"Pickleball Score Tracker\",\n        \"servingIndicatorA\": \"Team A Serving\",\n        \"servingIndicatorB\": \"Team B Serving\",\n        \"teamA_serving\": \"Team A (Serving)\",\n        \"teamA_receiving\": \"Team A (Receiving)\",\n        \"teamB_serving\": \"Team B (Serving)\",\n        \"teamB_receiving\": \"Team B (Receiving)\",\n        \"msg_point\": \"Point scored! Server switches sides.\",\n        \"msg_fault\": \"Fault! Second server takes over.\",\n        \"msg_side_out_prefix\": \"Side Out! Ball goes to Team \",\n        \"msg_game_over_prefix\": \"Game Over! Team \",\n        \"status_default\": \"New Game Started (0-0-2 rule)\",\n        \"status_point\": \"Point Scored\",\n        \"status_2nd_server\": \"2nd Server\",\n        \"status_side_out\": \"Side Out\",\n        \"status_new_game\": \"New Game\",\n        \"status_game_over\": \"Game Over\",\n        \"toast_win_suffix\": \" wins \",\n        \"confirm_reset\": \"Reset game? Current score will be lost.\",\n        \"btn_serving_wins\": \"Serving Team Wins Rally\",\n        \"btn_receiving_wins\": \"Receiving Team Wins Rally\",\n        \"theme_light\": \"Light\",\n        \"theme_auto\": \"Auto\",\n        \"theme_dark\": \"Dark\",\n        \"theme_label\": \"Theme\",\n        \"theme_desc\": \"Light, Dark, or follow your device\",\n        \"game_length\": \"Game length\",\n        \"game_length_desc\": \"Points to win - win by 2\",\n        \"auto_timer\": \"Auto timer\",\n        \"auto_timer_desc\": \"Start timer on first rally\",\n        \"off\": \"Off\",\n        \"on\": \"On\",\n        \"settings_title\": \"Settings\",\n        \"server_score\": \"Server Score\",\n        \"receiver_score\": \"Receiver Score\",\n        \"server_num\": \"Server #\",\n        \"footer_score\": \"Score\",\n        \"footer_status\": \"Status\",\n        \"timer_title\": \"Start \/ Pause Timer\",\n        \"theme_toggle_aria\": \"Toggle theme\",\n        \"settings_aria\": \"Settings\",\n        \"reset_aria\": \"Reset game\",\n        \"lang_aria\": \"Language\"\n      },\n      \"zh-HK\": {\n        \"title\": \"\u5339\u514b\u7403\u8a08\u5206\u677f\",\n        \"servingIndicatorA\": \"A \u968a\u958b\u7403\",\n        \"servingIndicatorB\": \"B \u968a\u958b\u7403\",\n        \"teamA_serving\": \"A \u968a\uff08\u958b\u7403\uff09\",\n        \"teamA_receiving\": \"A \u968a\uff08\u63a5\u6ce2\uff09\",\n        \"teamB_serving\": \"B \u968a\uff08\u958b\u7403\uff09\",\n        \"teamB_receiving\": \"B \u968a\uff08\u63a5\u6ce2\uff09\",\n        \"msg_point\": \"\u5f97\u5206\uff01\u958b\u6ce2\u65b9\u8f49\u908a\u3002\",\n        \"msg_fault\": \"\u72af\u898f\uff01\u7b2c\u4e8c\u4f4d\u958b\u7403\u54e1\u4e0a\u5834\u3002\",\n        \"msg_side_out_prefix\": \"\u63db\u908a\uff01\u6ce2\u8f2a\u5230 \",\n        \"msg_game_over_prefix\": \"\u6bd4\u8cfd\u7d50\u675f\uff01\",\n        \"status_default\": \"\u65b0\u4e00\u5c40\u958b\u59cb\uff080-0-2 \u898f\u5247\uff09\",\n        \"status_point\": \"\u5f97\u5206\",\n        \"status_2nd_server\": \"\u7b2c\u4e8c\u4f4d\u958b\u7403\u54e1\",\n        \"status_side_out\": \"\u63db\u908a\",\n        \"status_new_game\": \"\u65b0\u5c40\",\n        \"status_game_over\": \"\u6bd4\u8cfd\u7d50\u675f\",\n        \"toast_win_suffix\": \"\u968a\u8d0f \",\n        \"confirm_reset\": \"\u78ba\u5b9a\u8981\u91cd\u8a2d\u6bd4\u8cfd\uff1f\u76ee\u524d\u5206\u6578\u6703\u88ab\u6e05\u9664\u3002\",\n        \"btn_serving_wins\": \"\u958b\u7403\u65b9\u5f97\u5206\",\n        \"btn_receiving_wins\": \"\u63a5\u6ce2\u65b9\u5f97\u5206\",\n        \"theme_light\": \"\u6dfa\u8272\",\n        \"theme_auto\": \"\u81ea\u52d5\",\n        \"theme_dark\": \"\u6df1\u8272\",\n        \"theme_label\": \"\u4e3b\u984c\",\n        \"theme_desc\": \"\u6dfa\u8272\u3001\u6df1\u8272\uff0c\u6216\u8ddf\u88dd\u7f6e\u8a2d\u5b9a\",\n        \"game_length\": \"\u5c40\u5206\",\n        \"game_length_desc\": \"\u52dd\u5206 - \u9808\u8d0f\u5169\u5206\",\n        \"auto_timer\": \"\u81ea\u52d5\u8a08\u6642\",\n        \"auto_timer_desc\": \"\u7b2c\u4e00\u6b21\u5f97\u5206\u6642\u958b\u59cb\u8a08\u6642\",\n        \"off\": \"\u95dc\",\n        \"on\": \"\u958b\",\n        \"settings_title\": \"\u8a2d\u5b9a\",\n        \"server_score\": \"\u958b\u6ce2\u65b9\u5206\u6578\",\n        \"receiver_score\": \"\u63a5\u6ce2\u65b9\u5206\u6578\",\n        \"server_num\": \"\u958b\u6ce2\u54e1 #\",\n        \"footer_score\": \"\u6bd4\u5206\",\n        \"footer_status\": \"\u72c0\u614b\",\n        \"timer_title\": \"\u958b\u59cb\uff0f\u66ab\u505c\u8a08\u6642\",\n        \"theme_toggle_aria\": \"\u5207\u63db\u4e3b\u984c\",\n        \"settings_aria\": \"\u8a2d\u5b9a\",\n        \"reset_aria\": \"\u91cd\u8a2d\u6bd4\u8cfd\",\n        \"lang_aria\": \"\u8a9e\u8a00\"\n      }\n    };<\/p>\n<p>    var currentLang = \"en\";\n    function t(key) {\n      return (STRINGS[currentLang] && STRINGS[currentLang][key]) ||\n             (STRINGS.en && STRINGS.en[key]) ||\n             key;\n    }\n    function applyLang() {\n      document.documentElement.setAttribute(\"lang\", currentLang);\n      var els = document.querySelectorAll(\"[data-i18n]\");\n      for (var i = 0; i < els.length; i++) {\n        var key = els[i].getAttribute(\"data-i18n\");\n        var val = t(key);\n        if (val) els[i].innerText = val;\n      }\n      var ariaMap = {\n        \"timer-pill\": \"timer_title\",\n        \"theme-toggle\": \"theme_toggle_aria\",\n        \"settings-btn\": \"settings_aria\",\n        \"reset-btn\": \"reset_aria\",\n        \"lang-toggle\": \"lang_aria\"\n      };\n      for (var id in ariaMap) {\n        var el = document.getElementById(id);\n        if (el) el.setAttribute(\"aria-label\", t(ariaMap[id]));\n      }\n      var tp = document.getElementById(\"timer-pill\");\n      if (tp) tp.setAttribute(\"title\", t(\"timer_title\"));\n      var langBtns = document.querySelectorAll(\"#lang-toggle .lang-btn\");\n      for (var j = 0; j < langBtns.length; j++) {\n        langBtns[j].classList.toggle(\"active\", langBtns[j].dataset.lang === currentLang);\n      }\n      if (typeof updateDisplay === \"function\") updateDisplay();\n    }\n    function setLang(lang) {\n      if (SUPPORTED_LANGS.indexOf(lang) === -1) return;\n      currentLang = lang;\n      try { localStorage.setItem(\"pickleball-lang\", lang); } catch (e) {}\n      applyLang();\n    }\n\n    \/\/ Game State\n    var teamAScore = 0;\n    var teamBScore = 0;\n    var servingTeam = \"A\";\n    var serverNumber = 2;\n    var gameOver = false;\n    var targetScore = 11;\n\n    var timerInterval = null;\n    var secondsElapsed = 0;\n    var isTimerRunning = false;\n    var autoTimer = true;\n    var themeMode = \"auto\";\n\n    function pad(n) { return n < 10 ? \"0\" + n : \"\" + n; }\n    function formatTime(totalSeconds) {\n      return pad(Math.floor(totalSeconds \/ 60)) + \":\" + pad(totalSeconds % 60);\n    }\n    function updateTimerDisplay() {\n      document.getElementById(\"timer-display\").innerText = formatTime(secondsElapsed);\n      var pill = document.getElementById(\"timer-pill\");\n      if (pill) pill.classList.toggle(\"is-running\", isTimerRunning);\n    }\n    function startTimer() {\n      if (!isTimerRunning &#038;&#038; !gameOver) {\n        isTimerRunning = true;\n        if (timerInterval) clearInterval(timerInterval);\n        timerInterval = setInterval(function () {\n          secondsElapsed++;\n          updateTimerDisplay();\n        }, 1000);\n        updateTimerDisplay();\n      }\n    }\n    function stopTimer() {\n      if (isTimerRunning) {\n        isTimerRunning = false;\n        if (timerInterval) { clearInterval(timerInterval); timerInterval = null; }\n        updateTimerDisplay();\n      }\n    }\n    function toggleTimer() {\n      if (isTimerRunning) stopTimer(); else startTimer();\n    }\n    function resetTimer() {\n      stopTimer();\n      secondsElapsed = 0;\n      updateTimerDisplay();\n    }\n\n    function bumpScore(el) {\n      el.classList.remove(\"bump\");\n      void el.offsetWidth;\n      el.classList.add(\"bump\");\n    }\n\n    function updateDisplay(message, shortStatus) {\n      var serverScore = servingTeam === \"A\" ? teamAScore : teamBScore;\n      var receiverScore = servingTeam === \"A\" ? teamBScore : teamAScore;\n      var scoreStr = serverScore + \"-\" + receiverScore + \"-\" + serverNumber;\n\n      document.getElementById(\"main-score\").innerText = scoreStr;\n      document.getElementById(\"footer-score\").innerText = scoreStr;\n      document.getElementById(\"team-a-score\").innerText = teamAScore;\n      document.getElementById(\"team-b-score\").innerText = teamBScore;\n\n      var teamABox = document.getElementById(\"team-a-box\");\n      var teamBBox = document.getElementById(\"team-b-box\");\n      var teamALabel = document.getElementById(\"team-a-label\");\n      var teamBLabel = document.getElementById(\"team-b-label\");\n      var indicator = document.getElementById(\"serving-indicator-text\");\n\n      if (servingTeam === \"A\") {\n        teamABox.classList.add(\"is-serving\");\n        teamBBox.classList.remove(\"is-serving\");\n        teamALabel.innerText = t(\"teamA_serving\");\n        teamBLabel.innerText = t(\"teamB_receiving\");\n        indicator.innerText = t(\"servingIndicatorA\");\n      } else {\n        teamBBox.classList.add(\"is-serving\");\n        teamABox.classList.remove(\"is-serving\");\n        teamBLabel.innerText = t(\"teamB_serving\");\n        teamALabel.innerText = t(\"teamA_receiving\");\n        indicator.innerText = t(\"servingIndicatorB\");\n      }\n\n      if (message) document.getElementById(\"status-text\").innerText = message;\n      if (shortStatus) document.getElementById(\"footer-status\").innerText = shortStatus;\n    }\n\n    function serverWins() {\n      if (gameOver) return;\n      if (autoTimer &#038;&#038; !isTimerRunning &#038;&#038; secondsElapsed === 0) startTimer();\n      var ms = document.getElementById(\"main-score\");\n      var ts = document.getElementById(servingTeam === \"A\" ? \"team-a-score\" : \"team-b-score\");\n      if (servingTeam === \"A\") teamAScore++; else teamBScore++;\n      bumpScore(ms);\n      bumpScore(ts);\n      updateDisplay(t(\"msg_point\"), t(\"status_point\"));\n      checkWin();\n    }\n\n    function receiverWins() {\n      if (gameOver) return;\n      if (autoTimer &#038;&#038; !isTimerRunning &#038;&#038; secondsElapsed === 0) startTimer();\n      var ms = document.getElementById(\"main-score\");\n      bumpScore(ms);\n      if (serverNumber === 1) {\n        serverNumber = 2;\n        updateDisplay(t(\"msg_fault\"), t(\"status_2nd_server\"));\n      } else {\n        servingTeam = servingTeam === \"A\" ? \"B\" : \"A\";\n        serverNumber = 1;\n        updateDisplay(t(\"msg_side_out_prefix\") + servingTeam + \".\", t(\"status_side_out\"));\n      }\n      checkWin();\n    }\n\n    function checkWin() {\n      var aWins = teamAScore >= targetScore && teamAScore - teamBScore >= 2;\n      var bWins = teamBScore >= targetScore && teamBScore - teamAScore >= 2;\n      if (aWins || bWins) {\n        gameOver = true;\n        stopTimer();\n        var winner = aWins ? \"A\" : \"B\";\n        var timeStr = formatTime(secondsElapsed);\n        var toastWinner;\n        if (currentLang === \"zh-HK\") {\n          toastWinner = winner + t(\"toast_win_suffix\") + teamAScore + \"-\" + teamBScore;\n        } else {\n          toastWinner = \"Team \" + winner + t(\"toast_win_suffix\") + teamAScore + \"-\" + teamBScore;\n        }\n        updateDisplay(t(\"msg_game_over_prefix\") + winner + \" (\" + timeStr + \")\", t(\"status_game_over\"));\n        var dot = document.getElementById(\"status-dot\");\n        if (dot) dot.classList.add(\"over\");\n        showToast(toastWinner);\n        document.getElementById(\"btn-win\").disabled = true;\n        document.getElementById(\"btn-lose\").disabled = true;\n      }\n    }<\/p>\n<p>    function resetGame() {\n      teamAScore = 0;\n      teamBScore = 0;\n      servingTeam = \"A\";\n      serverNumber = 2;\n      gameOver = false;\n      resetTimer();\n      var dot = document.getElementById(\"status-dot\");\n      if (dot) dot.classList.remove(\"over\");\n      document.getElementById(\"btn-win\").disabled = false;\n      document.getElementById(\"btn-lose\").disabled = false;\n      updateDisplay(t(\"status_default\"), t(\"status_new_game\"));\n    }<\/p>\n<p>    function showToast(msg) {\n      var tEl = document.getElementById(\"toast\");\n      if (!tEl) return;\n      tEl.innerText = msg;\n      tEl.classList.add(\"show\");\n      if (showToast._t) clearTimeout(showToast._t);\n      showToast._t = setTimeout(function () { tEl.classList.remove(\"show\"); }, 2200);\n    }<\/p>\n<p>    function applyTheme() {\n      var html = document.documentElement;\n      if (themeMode === \"light\") html.setAttribute(\"data-theme\", \"light\");\n      else if (themeMode === \"dark\") html.setAttribute(\"data-theme\", \"dark\");\n      else html.removeAttribute(\"data-theme\");\n      var btns = document.querySelectorAll(\"#theme-seg button\");\n      for (var i = 0; i < btns.length; i++) {\n        btns[i].classList.toggle(\"on\", btns[i].dataset.mode === themeMode);\n      }\n    }\n    function quickToggleTheme() {\n      if (themeMode === \"auto\") themeMode = \"dark\";\n      else if (themeMode === \"dark\") themeMode = \"light\";\n      else themeMode = \"dark\";\n      applyTheme();\n    }\n\n    function openSheet() {\n      document.getElementById(\"sheet-overlay\").classList.add(\"open\");\n      document.getElementById(\"sheet\").style.transform = \"translateX(-50%) translateY(0)\";\n      var tBtns = document.querySelectorAll(\"#theme-seg button\");\n      for (var i = 0; i < tBtns.length; i++) {\n        tBtns[i].classList.toggle(\"on\", tBtns[i].dataset.mode === themeMode);\n      }\n      var tgBtns = document.querySelectorAll(\"#target-seg button\");\n      for (var j = 0; j < tgBtns.length; j++) {\n        tgBtns[j].classList.toggle(\"on\", parseInt(tgBtns[j].dataset.target, 10) === targetScore);\n      }\n      var atBtns = document.querySelectorAll(\"#auto-timer-seg button\");\n      for (var k = 0; k < atBtns.length; k++) {\n        atBtns[k].classList.toggle(\"on\", atBtns[k].dataset.on === String(autoTimer));\n      }\n    }\n    function closeSheet() {\n      document.getElementById(\"sheet-overlay\").classList.remove(\"open\");\n      document.getElementById(\"sheet\").style.transform = \"translateX(-50%) translateY(100%)\";\n    }\n\n    function init() {\n      \/\/ Load saved language preference\n      try {\n        var savedLang = localStorage.getItem(\"pickleball-lang\");\n        if (savedLang &#038;&#038; SUPPORTED_LANGS.indexOf(savedLang) !== -1) {\n          currentLang = savedLang;\n        }\n      } catch (e) {}\n\n      \/\/ Load saved settings\n      try {\n        var saved = localStorage.getItem(\"pickleball-settings\");\n        if (saved) {\n          var s = JSON.parse(saved);\n          if (s.themeMode) themeMode = s.themeMode;\n          if (s.targetScore) targetScore = s.targetScore;\n          if (typeof s.autoTimer === \"boolean\") autoTimer = s.autoTimer;\n        }\n      } catch (e) {}\n\n      \/\/ Pre-paint theme\n      if (themeMode === \"light\") document.documentElement.setAttribute(\"data-theme\", \"light\");\n      else if (themeMode === \"dark\") document.documentElement.setAttribute(\"data-theme\", \"dark\");\n      else {\n        var prefersDark = window.matchMedia &#038;&#038; window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n        if (!prefersDark) document.documentElement.setAttribute(\"data-theme\", \"light\");\n      }\n\n      applyLang();\n\n      document.getElementById(\"btn-win\").addEventListener(\"click\", serverWins);\n      document.getElementById(\"btn-lose\").addEventListener(\"click\", receiverWins);\n      document.getElementById(\"timer-pill\").addEventListener(\"click\", toggleTimer);\n      document.getElementById(\"reset-btn\").addEventListener(\"click\", function () {\n        if (teamAScore === 0 &#038;&#038; teamBScore === 0) { resetGame(); return; }\n        if (confirm(t(\"confirm_reset\"))) resetGame();\n      });\n      document.getElementById(\"theme-toggle\").addEventListener(\"click\", function () {\n        quickToggleTheme();\n        saveSettings();\n      });\n      document.getElementById(\"settings-btn\").addEventListener(\"click\", openSheet);\n      document.getElementById(\"sheet-overlay\").addEventListener(\"click\", closeSheet);\n\n      \/\/ Language toggle\n      var langBtns = document.querySelectorAll(\"#lang-toggle .lang-btn\");\n      for (var li = 0; li < langBtns.length; li++) {\n        langBtns[li].addEventListener(\"click\", function (e) {\n          setLang(e.currentTarget.dataset.lang);\n        });\n      }\n\n      \/\/ Theme segmented\n      var themeBtns = document.querySelectorAll(\"#theme-seg button\");\n      for (var i = 0; i < themeBtns.length; i++) {\n        themeBtns[i].addEventListener(\"click\", function (e) {\n          themeMode = e.target.dataset.mode;\n          applyTheme();\n          saveSettings();\n        });\n      }\n\n      \/\/ Target score segmented\n      var targetBtns = document.querySelectorAll(\"#target-seg button\");\n      for (var j = 0; j < targetBtns.length; j++) {\n        targetBtns[j].addEventListener(\"click\", function (e) {\n          targetScore = parseInt(e.target.dataset.target, 10);\n          var btns = document.querySelectorAll(\"#target-seg button\");\n          for (var m = 0; m < btns.length; m++) btns[m].classList.toggle(\"on\", btns[m] === e.target);\n          saveSettings();\n        });\n      }\n\n      \/\/ Auto timer segmented\n      var autoBtns = document.querySelectorAll(\"#auto-timer-seg button\");\n      for (var k = 0; k < autoBtns.length; k++) {\n        autoBtns[k].addEventListener(\"click\", function (e) {\n          autoTimer = e.target.dataset.on === \"true\";\n          var btns = document.querySelectorAll(\"#auto-timer-seg button\");\n          for (var n = 0; n < btns.length; n++) btns[n].classList.toggle(\"on\", btns[n] === e.target);\n          saveSettings();\n        });\n      }\n\n      \/\/ Keyboard shortcuts\n      document.addEventListener(\"keydown\", function (e) {\n        if (e.target &#038;&#038; e.target.tagName === \"INPUT\") return;\n        if (e.key === \"w\" || e.key === \"W\") serverWins();\n        else if (e.key === \"l\" || e.key === \"L\") receiverWins();\n        else if (e.key === \" \") { e.preventDefault(); toggleTimer(); }\n        else if (e.key === \"Escape\") closeSheet();\n      });\n\n      \/\/ Pause timer when tab hidden\n      document.addEventListener(\"visibilitychange\", function () {\n        if (document.hidden &#038;&#038; isTimerRunning) stopTimer();\n      });\n\n      resetGame();\n    }\n\n    function saveSettings() {\n      try {\n        localStorage.setItem(\"pickleball-settings\", JSON.stringify({\n          themeMode: themeMode,\n          targetScore: targetScore,\n          autoTimer: autoTimer\n        }));\n      } catch (e) {}\n    }\n\n    if (document.readyState === \"loading\") {\n      document.addEventListener(\"DOMContentLoaded\", init);\n    } else {\n      init();\n    }\n  <\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pickleball Score Tracker Back to comparetiger.com Pickl [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"parent":0,"menu_order":998,"comment_status":"closed","ping_status":"closed","template":"","meta":{"googlesitekit_rrm_CAowrrDCDA:productID":"","_gspb_post_css":"","footnotes":""},"class_list":["post-13535","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/comparetiger.com\/index.php?rest_route=\/wp\/v2\/pages\/13535","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/comparetiger.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/comparetiger.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/comparetiger.com\/index.php?rest_route=\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/comparetiger.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=13535"}],"version-history":[{"count":11,"href":"https:\/\/comparetiger.com\/index.php?rest_route=\/wp\/v2\/pages\/13535\/revisions"}],"predecessor-version":[{"id":13546,"href":"https:\/\/comparetiger.com\/index.php?rest_route=\/wp\/v2\/pages\/13535\/revisions\/13546"}],"wp:attachment":[{"href":"https:\/\/comparetiger.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13535"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}