﻿{"id":10361,"date":"2026-08-07T09:32:48","date_gmt":"2026-08-07T01:32:48","guid":{"rendered":"https:\/\/www.dzrgw.cn\/?p=10361"},"modified":"2026-08-17T13:54:35","modified_gmt":"2026-08-17T05:54:35","slug":"%e6%97%b6%e9%97%b4%e4%b9%8b%e8%bd%ae","status":"publish","type":"post","link":"https:\/\/www.dzrgw.cn\/?p=10361","title":{"rendered":"\u65f6\u95f4\u4e4b\u8f6e"},"content":{"rendered":"\n<!-- \u65f6\u95f4\u4e4b\u8f6e + \u82f1\u6587 Widget\uff08\u91cd\u6784\u7248\uff09 -->\n<style>\n    .timewheel-wrapper {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        justify-content: center;\n        width: 100%;\n        max-width: 480px;\n        margin: 0 auto;\n        background: transparent !important;\n        font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;\n    }\n\n    .timewheel-block {\n        width: 100%;\n        aspect-ratio: 1\/1;\n        background: transparent !important;\n        overflow: visible;\n    }\n    .timewheel-block canvas {\n        display: block;\n        width: 100%;\n        height: 100%;\n        background: transparent !important;\n    }\n\n    \/* Widget \u5bb9\u5668\uff1a\u80cc\u666f\u4ec5\u5305\u88f9\u5185\u5bb9\uff0c\u5bbd\u5ea6\u81ea\u9002\u5e94 *\/\n    .timewidget-container {\n        display: inline-block;\n        margin-top: 16px;\n        padding: 10px 18px;\n        background: rgba(10, 14, 22, 0.7);\n        border-radius: 30px;\n        border: 1px solid rgba(255, 255, 255, 0.08);\n        backdrop-filter: blur(4px);\n        text-align: center;\n        font-size: 14px;\n        color: #e8edf5;\n        line-height: 1.7;\n        max-width: 90%;\n        box-sizing: border-box;\n    }\n\n    \/* \u7b2c\u4e00\u884c\uff1aTime in Beijing: + \u65f6\u95f4 *\/\n    .timewidget-container .first-line {\n        font-size: 15px;\n        white-space: nowrap;\n        line-height: 1.5;\n    }\n    .timewidget-container .first-line .label-link {\n        color: #9bb7d4;\n        font-weight: 400;\n        text-decoration: none;\n    }\n    .timewidget-container .first-line .label-link:hover {\n        text-decoration: underline;\n    }\n    .timewidget-container .first-line .time-display {\n        font-weight: 600;\n        font-size: 18px;\n        color: #f5d06a;\n        margin-left: 4px;\n    }\n\n    \/* \u540e\u7eed\u884c\uff1a\u65e5\u671f\u3001\u65e5\u51fa\u65e5\u843d\u7b49 *\/\n    .timewidget-container .info-lines {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        gap: 4px;\n        margin-top: 6px;\n    }\n    .timewidget-container .info-lines .date-line {\n        font-size: 14px;\n        color: rgba(255,255,255,0.7);\n        line-height: 1.5;\n    }\n    .timewidget-container .info-lines .sun-line {\n        font-size: 13px;\n        color: rgba(255,255,255,0.5);\n        line-height: 1.6;\n    }\n\n    \/* Time.is \u539f\u59cb widget span\uff1a\u9ed8\u8ba4\u9690\u85cf\uff0c\u540c\u6b65\u6210\u529f\u540e\u663e\u793a\u5e76\u9690\u85cf\u672c\u5730\u8ba1\u7b97\u5185\u5bb9 *\/\n\n\n    \/* \u5907\u7528\u6837\u5f0f\uff08\u82f1\u6587\uff09 *\/\n    .fallback-time {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        gap: 4px;\n    }\n    .fallback-time .time-line {\n        font-size: 18px;\n        font-weight: 600;\n        color: #f5d06a;\n    }\n    .fallback-time .date-line {\n        font-size: 14px;\n        color: rgba(255,255,255,0.7);\n    }\n    .fallback-time .sun-line {\n        font-size: 13px;\n        color: rgba(255,255,255,0.5);\n    }\n\n    \/* ========== \u672c\u5730 Fallback \u6a21\u5f0f\u6837\u5f0f ========== *\/\n\n    \/* Fallback \u72b6\u6001\u6307\u793a\u5fbd\u7ae0 *\/\n    .fallback-badge {\n        display: inline-flex;\n        align-items: center;\n        gap: 5px;\n        margin-top: 6px;\n        padding: 3px 10px;\n        border-radius: 12px;\n        background: rgba(255,255,255,0.04);\n        border: 1px solid rgba(255,255,255,0.06);\n        font-size: 11px;\n        color: rgba(255,255,255,0.35);\n        letter-spacing: 0.3px;\n        transition: opacity 0.4s ease;\n    }\n    .fallback-badge::before {\n        content: '';\n        width: 6px;\n        height: 6px;\n        border-radius: 50%;\n        background: rgba(155,183,212,0.5);\n        box-shadow: 0 0 4px rgba(155,183,212,0.3);\n    }\n\n    \/* Fallback \u6a21\u5f0f\u4e0b\u7684\u6807\u7b7e\u94fe\u63a5\u6837\u5f0f\u8c03\u6574 *\/\n    .timewidget-container.fallback-mode .label-link {\n        color: rgba(155,183,212,0.6);\n    }\n\n    \/* Fallback \u6a21\u5f0f\u4e0b\u65f6\u95f4\u6570\u5b57\u5fae\u5fae\u964d\u4f4e\u4eae\u5ea6\uff0c\u533a\u5206\u4e8e\u5728\u7ebf\u6a21\u5f0f *\/\n    .timewidget-container.fallback-mode .time-display {\n        color: #e8c860;\n    }\n\n    \/* Fallback \u6a21\u5f0f\u4e0b\u7684\u65e5\u51fa\u65e5\u843d\u884c *\/\n    .timewidget-container .info-lines .sun-line.fallback-sun {\n        color: rgba(255,255,255,0.4);\n        font-style: italic;\n    }\n\n    \/* ========== \u6eda\u52a8\u52a8\u6001\u6548\u679c ========== *\/\n\n    \/* \u5165\u573a\u52a8\u753b\uff1a\u521d\u59cb\u72b6\u6001\uff08\u9690\u85cf + \u7f29\u5c0f\uff09 *\/\n    .timewheel-wrapper {\n        opacity: 0;\n        transform: scale(0.85) translateY(30px);\n        transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),\n                    transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);\n        will-change: opacity, transform;\n    }\n    .timewheel-wrapper.in-view {\n        opacity: 1;\n        transform: scale(1) translateY(0);\n    }\n\n    \/* \u79fb\u52a8\u7aef\uff1a\u51cf\u5c11\u5165\u573a\u4f4d\u79fb\u5e45\u5ea6\uff0c\u907f\u514d\u5c0f\u5c4f\u4e0a\u8fc7\u5ea6\u52a8\u6548 *\/\n    @media (max-width: 768px) {\n        .timewheel-wrapper {\n            transform: scale(0.92) translateY(16px);\n        }\n    }\n\n    \/* \u5706\u73af\u89c6\u5dee\u65cb\u8f6c\u5c42\uff08\u5305\u88f9 canvas\uff0c\u72ec\u7acb\u4e8e\u5165\u573a\u52a8\u753b\uff09 *\/\n    .timewheel-block .parallax-layer {\n        width: 100%;\n        height: 100%;\n        transition: transform 0.1s linear;\n        will-change: transform;\n    }\n    \/* \u79fb\u52a8\u7aef\uff1a\u7981\u7528 transition\uff0c\u7531 JS rAF \u76f4\u63a5\u9a71\u52a8\uff0c\u907f\u514d\u53cc\u5c42\u52a8\u753b\u53e0\u52a0\u5361\u987f *\/\n    @media (max-width: 768px) {\n        .timewheel-block .parallax-layer {\n            transition: none;\n        }\n    }\n\n    \/* ========== \u65b0\u589e\uff1a\u591a\u5c42\u6df1\u5ea6\u89c6\u5dee ========== *\/\n\n    \/* \u80cc\u666f\u5149\u6655\u88c5\u9970\u5c42\uff08\u6700\u8fdc\u5c42\uff0c\u6eda\u52a8\u901f\u7387\u6700\u6162\uff09 *\/\n    .timewheel-bg-glow {\n        position: absolute;\n        inset: -15%;\n        pointer-events: none;\n        z-index: -1;\n        will-change: transform;\n        \/* \u5f84\u5411\u5149\u6655 *\/\n        background:\n            radial-gradient(ellipse 60% 50% at 30% 40%, rgba(232,168,56,0.06) 0%, transparent 70%),\n            radial-gradient(ellipse 50% 60% at 70% 60%, rgba(107,76,154,0.05) 0%, transparent 70%),\n            radial-gradient(ellipse 80% 80% at 50% 50%, rgba(74,107,138,0.04) 0%, transparent 80%);\n    }\n\n    \/* \u80cc\u666f\u5149\u6655\u4e2d\u7684\u88c5\u9970\u7c92\u5b50 *\/\n    .timewheel-bg-glow::before,\n    .timewheel-bg-glow::after {\n        content: '';\n        position: absolute;\n        border-radius: 50%;\n        opacity: 0.4;\n    }\n    .timewheel-bg-glow::before {\n        width: 6px; height: 6px;\n        top: 18%; left: 12%;\n        background: rgba(245,208,106,0.5);\n        box-shadow:\n            60px 30px 0 1px rgba(155,183,212,0.3),\n            120px -10px 0 0.5px rgba(232,168,56,0.4),\n            -20px 80px 0 1.5px rgba(184,158,219,0.3);\n    }\n    .timewheel-bg-glow::after {\n        width: 4px; height: 4px;\n        bottom: 22%; right: 15%;\n        background: rgba(155,183,212,0.4);\n        box-shadow:\n            -40px -20px 0 1px rgba(245,208,106,0.3),\n            30px 40px 0 0.5px rgba(107,76,154,0.35),\n            -70px 10px 0 2px rgba(232,168,56,0.2);\n    }\n\n    \/* \u4e3a wrapper \u6dfb\u52a0 3D \u900f\u89c6\u4e0a\u4e0b\u6587 *\/\n    .timewheel-wrapper {\n        perspective: 900px;\n        position: relative;\n    }\n    \/* \u79fb\u52a8\u7aef\uff1a\u964d\u4f4e\u900f\u89c6\u5f3a\u5ea6\uff0c\u51cf\u5c11 GPU \u8d1f\u62c5 *\/\n    @media (max-width: 768px) {\n        .timewheel-wrapper {\n            perspective: 1200px;\n        }\n    }\n\n    \/* \u5706\u73af 3D \u503e\u659c\u5c42\uff08\u5d4c\u5957\u5728 parallax-layer \u5185\uff09 *\/\n    .timewheel-block .tilt-layer {\n        width: 100%;\n        height: 100%;\n        transform-style: preserve-3d;\n        transition: transform 0.15s ease-out;\n        will-change: transform;\n    }\n\n    \/* Widget \u524d\u666f\u89c6\u5dee\u5305\u88f9\u5c42\uff08\u6bd4\u5706\u73af\u79fb\u52a8\u66f4\u5feb\uff0c\u4ea7\u751f\u201c\u5728\u524d\u9762\u201d\u7684\u611f\u89c9\uff09 *\/\n    .widget-parallax-layer {\n        will-change: transform;\n        transition: transform 0.1s linear;\n    }\n    \/* \u79fb\u52a8\u7aef\uff1a\u7981\u7528 transition\uff0c\u7531 JS \u76f4\u63a5\u9a71\u52a8 *\/\n    @media (max-width: 768px) {\n        .widget-parallax-layer {\n            transition: none;\n        }\n    }\n\n    \/* \u51cf\u5f31\u52a8\u753b\u504f\u597d\uff1a\u7981\u7528\u65b0\u589e\u89c6\u5dee\u5c42 *\/\n    @media (prefers-reduced-motion: reduce) {\n        .timewheel-bg-glow,\n        .timewheel-block .tilt-layer {\n            transform: none !important;\n        }\n    }\n\n    \/* Widget \u5ef6\u8fdf\u6de1\u5165 *\/\n    .timewidget-container {\n        opacity: 0;\n        transform: translateY(12px);\n        transition: opacity 0.6s ease 0.4s,\n                    transform 0.6s ease 0.4s;\n    }\n    .timewheel-wrapper.in-view .timewidget-container {\n        opacity: 1;\n        transform: translateY(0);\n    }\n\n    \/* \u6eda\u52a8\u79bb\u5f00\u65f6\u7684\u8f7b\u5fae\u6de1\u51fa\uff08\u53ef\u9009\uff0c\u589e\u52a0\u5c42\u6b21\u611f\uff09 *\/\n    .timewheel-wrapper.out-view {\n        opacity: 0.3;\n        transform: scale(0.92) translateY(-10px);\n    }\n\n    \/* \u5c0a\u91cd\u7528\u6237\u51cf\u5f31\u52a8\u753b\u504f\u597d *\/\n    @media (prefers-reduced-motion: reduce) {\n        .timewheel-wrapper,\n        .timewidget-container,\n        .timewheel-block .parallax-layer,\n        .timewheel-bg-glow,\n        .timewheel-block .tilt-layer,\n        .widget-parallax-layer {\n            transition: none !important;\n            opacity: 1 !important;\n            transform: none !important;\n        }\n    }\n\n    \/* ========== \u79fb\u52a8\u7aef\u663e\u793a\u9002\u914d ========== *\/\n    @media (max-width: 768px) {\n        \/* \u6574\u4f53\u5bb9\u5668\uff1a\u7f29\u5c0f\u6700\u5927\u5bbd\u5ea6\uff0c\u51cf\u5c11\u8fb9\u8ddd *\/\n        .timewheel-wrapper {\n            max-width: 100%;\n            padding: 0 12px;\n        }\n\n        \/* Widget \u5bb9\u5668\uff1a\u7d27\u51d1\u5e03\u5c40 *\/\n        .timewidget-container {\n            margin-top: 12px;\n            padding: 8px 14px;\n            border-radius: 24px;\n            max-width: 95%;\n            font-size: 13px;\n            line-height: 1.6;\n        }\n\n        \/* \u884c\u95f4\u8ddd\u7d27\u51d1\uff1a\u624b\u673a\u5c4f\u5e55\u5c0f\uff0c\u51cf\u5c11\u5782\u76f4\u7a7a\u767d *\/\n        .timewidget-container .first-line {\n            line-height: 1.4;\n        }\n        .timewidget-container .info-lines {\n            gap: 2px;\n            margin-top: 4px;\n        }\n        .timewidget-container .info-lines .date-line {\n            line-height: 1.4;\n        }\n        .timewidget-container .info-lines .sun-line {\n            line-height: 1.5;\n        }\n        .fallback-time {\n            gap: 2px;\n        }\n\n        \/* \u7b2c\u4e00\u884c\uff1a\u7f29\u5c0f\u6807\u7b7e\u548c\u65f6\u95f4\u5b57\u4f53 *\/\n        .timewidget-container .first-line {\n            font-size: 13px;\n            white-space: normal;  \/* \u5141\u8bb8\u6362\u884c\uff0c\u907f\u514d\u5c0f\u5c4f\u6ea2\u51fa *\/\n        }\n        .timewidget-container .first-line .time-display {\n            font-size: 18px;\n        }\n\n        \/* \u540e\u7eed\u884c\uff1a\u7f29\u5c0f\u5b57\u4f53 *\/\n        .timewidget-container .info-lines .date-line {\n            font-size: 13px;\n        }\n        .timewidget-container .info-lines .sun-line {\n            font-size: 12px;\n        }\n\n        \/* Time.is \u539f\u59cb widget \u5185\u5bb9\uff1a\u7f29\u5c0f\u5b57\u4f53 *\/\n\n        \/* \u5907\u7528\u6837\u5f0f\uff1a\u7f29\u5c0f *\/\n        .fallback-time .time-line {\n            font-size: 18px;\n        }\n        .fallback-time .date-line {\n            font-size: 13px;\n        }\n        .fallback-time .sun-line {\n            font-size: 12px;\n        }\n    }\n\n    \/* ========== \u5c0f\u5c4f\u624b\u673a\u4e13\u9879\uff08\u2264 375px\uff0c\u5982 iPhone SE\uff09 ========== *\/\n    @media (max-width: 375px) {\n        .timewidget-container {\n            padding: 6px 10px;\n            border-radius: 20px;\n            font-size: 12px;\n            line-height: 1.5;\n        }\n        .timewidget-container .first-line {\n            font-size: 12px;\n            line-height: 1.3;\n        }\n        .timewidget-container .first-line .time-display {\n            font-size: 16px;\n        }\n        .timewidget-container .info-lines {\n            gap: 1px;\n            margin-top: 3px;\n        }\n        .timewidget-container .info-lines .date-line {\n            font-size: 12px;\n            line-height: 1.3;\n        }\n        .timewidget-container .info-lines .sun-line {\n            font-size: 11px;\n            line-height: 1.4;\n        }\n        .fallback-time {\n            gap: 1px;\n        }\n        .fallback-time .time-line {\n            font-size: 16px;\n        }\n        .fallback-time .date-line {\n            font-size: 12px;\n        }\n        .fallback-time .sun-line {\n            font-size: 11px;\n        }\n    }\n\n    \/* ========== \u5e73\u677f\u7ad6\u5c4f\u9002\u914d\uff08769px\u20131024px + portrait\uff09 ========== *\/\n    @media (min-width: 769px) and (max-width: 1024px) and (orientation: portrait) {\n        \/* \u6574\u4f53\u5bb9\u5668\uff1a\u6269\u5927\u6700\u5927\u5bbd\u5ea6\uff0c\u5145\u5206\u5229\u7528\u7ad6\u5c4f\u5bbd\u5ea6 *\/\n        .timewheel-wrapper {\n            max-width: 600px;\n            padding: 24px 20px;\n        }\n\n        \/* \u5706\u73af\u533a\u57df\uff1a\u5229\u7528\u7ad6\u5c4f\u9ad8\u5ea6\u4f18\u52bf\uff0c\u9002\u5ea6\u653e\u5927 *\/\n        .timewheel-block {\n            width: min(80vw, 55vh, 520px);\n            aspect-ratio: 1\/1;\n        }\n\n        \/* Widget \u5bb9\u5668\uff1a\u5e73\u677f\u89c2\u770b\u8ddd\u79bb\u8f83\u8fdc\uff0c\u5b57\u4f53\u548c\u884c\u8ddd\u6574\u4f53\u653e\u5927 *\/\n        .timewidget-container {\n            margin-top: 20px;\n            padding: 14px 24px;\n            border-radius: 28px;\n            max-width: 85%;\n            font-size: 15px;\n            line-height: 1.8;\n        }\n\n        \/* \u884c\u95f4\u8ddd\u5bbd\u677e\uff1a\u5e73\u677f\u5c4f\u5e55\u5927\uff0c\u589e\u52a0\u5782\u76f4\u547c\u5438\u611f *\/\n        .timewidget-container .first-line {\n            line-height: 1.6;\n        }\n        .timewidget-container .info-lines {\n            gap: 6px;\n            margin-top: 8px;\n        }\n        .timewidget-container .info-lines .date-line {\n            line-height: 1.6;\n        }\n        .timewidget-container .info-lines .sun-line {\n            line-height: 1.7;\n        }\n        .fallback-time {\n            gap: 6px;\n        }\n\n        \/* \u7b2c\u4e00\u884c\uff1a\u4fdd\u6301\u4e0d\u6362\u884c\uff08\u7ad6\u5c4f\u5bbd\u5ea6\u8db3\u591f\uff09 *\/\n        .timewidget-container .first-line {\n            font-size: 16px;\n            white-space: nowrap;\n        }\n        .timewidget-container .first-line .time-display {\n            font-size: 24px;\n        }\n\n        \/* \u540e\u7eed\u884c\uff1a\u5e73\u677f\u5b57\u4f53\u653e\u5927 *\/\n        .timewidget-container .info-lines .date-line {\n            font-size: 15px;\n        }\n        .timewidget-container .info-lines .sun-line {\n            font-size: 13px;\n        }\n\n        \/* Time.is \u539f\u59cb widget \u5185\u5bb9 *\/\n\n        \/* \u5907\u7528\u6837\u5f0f *\/\n        .fallback-time .time-line {\n            font-size: 24px;\n        }\n        .fallback-time .date-line {\n            font-size: 15px;\n        }\n        .fallback-time .sun-line {\n            font-size: 13px;\n        }\n\n        \/* \u80cc\u666f\u5149\u6655\uff1a\u9002\u5ea6\u6269\u5c55\u8986\u76d6\u66f4\u5927\u7684\u5706\u73af *\/\n        .timewheel-bg-glow {\n            inset: -12%;\n        }\n\n        \/* \u5165\u573a\u52a8\u753b\uff1a\u7ad6\u5c4f\u4fdd\u6301\u4e0a\u4e0b\u6ed1\u5165\uff0c\u5e45\u5ea6\u9002\u4e2d *\/\n        .timewheel-wrapper {\n            transform: scale(0.9) translateY(24px);\n        }\n        .timewheel-wrapper.in-view {\n            transform: scale(1) translateY(0);\n        }\n    }\n\n    \/* ========== \u5927\u5e73\u677f\u7ad6\u5c4f\uff08> 1024px + portrait\uff0c\u5982 iPad Pro 12.9\" \u7ad6\u5c4f\uff09 ========== *\/\n    @media (min-width: 1025px) and (orientation: portrait) {\n        .timewheel-wrapper {\n            max-width: 640px;\n            padding: 32px 24px;\n        }\n\n        .timewheel-block {\n            width: min(75vw, 50vh, 560px);\n        }\n\n        .timewidget-container {\n            margin-top: 24px;\n            padding: 16px 28px;\n            border-radius: 30px;\n            max-width: 80%;\n            font-size: 16px;\n            line-height: 1.85;\n        }\n\n        .timewidget-container .first-line {\n            font-size: 17px;\n            line-height: 1.6;\n        }\n        .timewidget-container .first-line .time-display {\n            font-size: 26px;\n        }\n\n        .timewidget-container .info-lines {\n            gap: 7px;\n            margin-top: 9px;\n        }\n        .timewidget-container .info-lines .date-line {\n            font-size: 16px;\n            line-height: 1.65;\n        }\n        .timewidget-container .info-lines .sun-line {\n            font-size: 14px;\n            line-height: 1.7;\n        }\n\n        .fallback-time {\n            gap: 7px;\n        }\n        .fallback-time .time-line {\n            font-size: 26px;\n        }\n        .fallback-time .date-line {\n            font-size: 16px;\n        }\n        .fallback-time .sun-line {\n            font-size: 14px;\n        }\n    }\n\n    \/* ========== \u5e73\u677f\u6a2a\u5c4f\u9002\u914d\uff08769px\u20131366px + landscape + \u89e6\u6478\u8bbe\u5907\uff09 ========== *\/\n    @media (min-width: 769px) and (max-width: 1366px) and (orientation: landscape) and (pointer: coarse) {\n        \/* \u6574\u4f53\u5e03\u5c40\uff1a\u5de6\u53f3\u5e76\u6392\uff08\u5706\u73af\u5728\u5de6\uff0c\u65f6\u949f\u4fe1\u606f\u5728\u53f3\uff09 *\/\n        .timewheel-wrapper {\n            flex-direction: row;\n            align-items: center;\n            justify-content: center;\n            max-width: 900px;\n            gap: 32px;\n            min-height: 60vh;\n        }\n\n        \/* \u5706\u73af\u533a\u57df\uff1a\u7ea6\u675f\u5c3a\u5bf8\uff0c\u907f\u514d\u6491\u7206\u89c6\u53e3\u9ad8\u5ea6 *\/\n        .timewheel-block {\n            flex: 0 0 auto;\n            width: min(55vw, 52vh, 420px);\n            aspect-ratio: 1\/1;\n        }\n\n        \/* Widget \u533a\u57df\uff1a\u53f3\u4fa7\u5c45\u4e2d\uff0c\u5782\u76f4\u6392\u5217 *\/\n        .widget-parallax-layer {\n            flex: 0 0 auto;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n        }\n\n        .timewidget-container {\n            margin-top: 0;\n            padding: 14px 24px;\n            border-radius: 20px;\n            max-width: 340px;\n            text-align: center;\n            font-size: 15px;\n            line-height: 1.75;\n        }\n\n        \/* \u7b2c\u4e00\u884c\uff1a\u6062\u590d\u4e0d\u6362\u884c\uff08\u6a2a\u5c4f\u7a7a\u95f4\u5145\u8db3\uff09 *\/\n        .timewidget-container .first-line {\n            font-size: 16px;\n            white-space: nowrap;\n            line-height: 1.5;\n        }\n        .timewidget-container .first-line .time-display {\n            font-size: 22px;\n        }\n\n        \/* \u540e\u7eed\u884c\uff1a\u6a2a\u5c4f\u9ad8\u5ea6\u6709\u9650\uff0c\u884c\u8ddd\u9002\u4e2d *\/\n        .timewidget-container .info-lines {\n            gap: 5px;\n            margin-top: 6px;\n        }\n        .timewidget-container .info-lines .date-line {\n            font-size: 15px;\n            line-height: 1.55;\n        }\n        .timewidget-container .info-lines .sun-line {\n            font-size: 13px;\n            line-height: 1.6;\n        }\n\n        \/* Time.is \u539f\u59cb widget \u5185\u5bb9 *\/\n\n        \/* \u5907\u7528\u6837\u5f0f *\/\n        .fallback-time {\n            gap: 5px;\n        }\n        .fallback-time .time-line {\n            font-size: 22px;\n        }\n        .fallback-time .date-line {\n            font-size: 15px;\n        }\n        .fallback-time .sun-line {\n            font-size: 13px;\n        }\n\n        \/* \u80cc\u666f\u5149\u6655\uff1a\u6269\u5927\u8303\u56f4\u4ee5\u8986\u76d6\u6a2a\u5411\u5e03\u5c40 *\/\n        .timewheel-bg-glow {\n            inset: -20% -10%;\n        }\n\n        \/* \u89c6\u5dee\u5f3a\u5ea6\u7565\u5fae\u964d\u4f4e\uff08\u6a2a\u5c4f\u6eda\u52a8\u8ddd\u79bb\u77ed\uff09 *\/\n        .timewheel-block .parallax-layer {\n            transition: transform 0.12s linear;\n        }\n\n        \/* \u5165\u573a\u52a8\u753b\uff1a\u6a2a\u5c4f\u65f6\u4ece\u5de6\u53f3\u4e24\u4fa7\u6ed1\u5165\u800c\u975e\u4e0a\u4e0b *\/\n        .timewheel-wrapper {\n            transform: scale(0.9) translateY(0);\n        }\n        .timewheel-wrapper.in-view {\n            transform: scale(1) translateY(0);\n        }\n    }\n\n    \/* \u5927\u5e73\u677f\u6a2a\u5c4f\uff08> 1366px\uff0c\u5982 iPad Pro 12.9\" \u6a2a\u5c4f\uff0c\u4ec5\u89e6\u6478\u8bbe\u5907\uff09 *\/\n    @media (min-width: 1367px) and (orientation: landscape) and (max-height: 900px) and (pointer: coarse) {\n        .timewheel-wrapper {\n            flex-direction: row;\n            align-items: center;\n            justify-content: center;\n            max-width: 1000px;\n            gap: 48px;\n            min-height: 70vh;\n        }\n\n        .timewheel-block {\n            width: min(50vw, 60vh, 480px);\n        }\n\n        .widget-parallax-layer {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n        }\n\n        .timewidget-container {\n            margin-top: 0;\n            padding: 16px 28px;\n            border-radius: 22px;\n            max-width: 360px;\n            font-size: 16px;\n            line-height: 1.8;\n        }\n\n        .timewidget-container .first-line {\n            font-size: 17px;\n            line-height: 1.55;\n        }\n        .timewidget-container .first-line .time-display {\n            font-size: 24px;\n        }\n\n        .timewidget-container .info-lines {\n            gap: 6px;\n            margin-top: 8px;\n        }\n        .timewidget-container .info-lines .date-line {\n            font-size: 16px;\n            line-height: 1.6;\n        }\n        .timewidget-container .info-lines .sun-line {\n            font-size: 14px;\n            line-height: 1.65;\n        }\n\n        .fallback-time {\n            gap: 6px;\n        }\n        .fallback-time .time-line {\n            font-size: 24px;\n        }\n        .fallback-time .date-line {\n            font-size: 16px;\n        }\n        .fallback-time .sun-line {\n            font-size: 14px;\n        }\n    }\n\n    \/* ========== \u79fb\u52a8\u7aef\u4e13\u9879\u4f18\u5316 ========== *\/\n    @media (max-width: 768px) {\n        \/* \u51cf\u5c11 will-change \u5c42\u6570\uff0c\u964d\u4f4e\u5185\u5b58\u5360\u7528 *\/\n        .timewheel-bg-glow {\n            will-change: auto;\n        }\n        .timewheel-block .tilt-layer {\n            will-change: auto;\n        }\n\n        \/* \u80cc\u666f\u5149\u6655\u5c42\u7b80\u5316\uff1a\u79fb\u52a8\u7aef\u53ea\u4fdd\u7559\u4e3b\u5149\u6655\uff0c\u53bb\u6389\u7c92\u5b50\u88c5\u9970 *\/\n        .timewheel-bg-glow::before,\n        .timewheel-bg-glow::after {\n            display: none;\n        }\n\n        \/* \u7f29\u5c0f\u80cc\u666f\u5149\u6655\u8303\u56f4\uff0c\u907f\u514d\u5c0f\u5c4f\u4e0a\u8fc7\u5ea6\u7ed8\u5236 *\/\n        .timewheel-bg-glow {\n            inset: -8%;\n        }\n    }\n<\/style>\n\n<div class=\"timewheel-wrapper\">\n    <!-- \u80cc\u666f\u5149\u6655\u88c5\u9970\u5c42\uff08\u6700\u8fdc\u89c6\u5dee\u5c42\uff09 -->\n    <div class=\"timewheel-bg-glow\" id=\"bgGlowLayer\"><\/div>\n\n    <!-- \u5706\u73af\uff08\u5305\u88f9\u89c6\u5dee\u5c42 + 3D \u503e\u659c\u5c42\uff09 -->\n    <div class=\"timewheel-block\">\n        <div class=\"parallax-layer\" id=\"parallaxLayer\">\n            <div class=\"tilt-layer\" id=\"tiltLayer\">\n                <canvas id=\"wheelCanvas\" width=\"500\" height=\"500\"><\/canvas>\n            <\/div>\n        <\/div>\n    <\/div>\n\n  <!-- \u4e0b\u65b9 Widget\uff08\u82f1\u6587\u7248\uff0c\u5305\u88f9\u524d\u666f\u89c6\u5dee\u5c42\uff09 -->\n<div class=\"widget-parallax-layer\" id=\"widgetParallaxLayer\">\n<div class=\"timewidget-container\">\n    <!-- Time.is \u5b98\u65b9 widget \u4ee3\u7801\uff08\u4e25\u683c\u6309\u5b98\u65b9\u683c\u5f0f\uff0c\u5305\u88f9\u5728\u72ec\u7acb\u5bb9\u5668\u4e2d\u907f\u514d\u6837\u5f0f\u5e72\u6270\uff09 -->\n    <a href=\"https:\/\/time.is\/Beijing\" id=\"time_is_link\" rel=\"nofollow\" style=\"font-size:16px\">Time in Beijing:<\/a>\n    <span id=\"Beijing_z43d\" style=\"font-size:16px\"><\/span>\n    <script src=\"\/\/widget.time.is\/en.js\"><\/script>\n    <script>time_is_widget.init({Beijing_z43d:{template:\"TIME<br>DATE<br>SUN\", date_format:\"dayname, dnum monthname, year, week\", sun_format:\"Sunrise: srhour:srminute Sunset: sshour:ssminute<br>Day length: dlhoursh dlminutesm\", coords:\"39.9075000,116.3972300\"}});<\/script>\n    <\/div>\n    <!-- \u672c\u5730 fallback \u663e\u793a\u533a\uff08Time.is \u53ef\u7528\u65f6\u9690\u85cf\uff09 -->\n    <div id=\"localDisplay\">\n        <div class=\"first-line\">\n            <span class=\"time-display\" id=\"customTimeDisplay\">&#8211;:&#8211;:&#8211;<\/span>\n        <\/div>\n        <div id=\"widgetExtra\" class=\"info-lines\"><\/div>\n    <\/div>\n    <script>\n        \/\/ ========== \u6838\u5fc3\u72b6\u6001 ==========\n        let timeOffset = 0;\n        let clockStarted = false;\n        let widgetSynced = false;\n        let sunData = null;   \/\/ {sunrise, sunset, dayLength}\n        let widgetDateStr = null;  \/\/ \u540c\u6b65\u6210\u529f\u540e\u5b58\u50a8 Time.is \u7684\u539f\u59cb\u65e5\u671f\u884c\uff08\u542b\u5468\u6570\uff09\n\n        const pad = n => String(n).padStart(2, '0');\n\n        \/\/ ========== \u672c\u5730\u81ea\u8d70\u65f6\u949f ==========\n        function getDisplayTime(now) {\n            const d = new Date(now.getTime() + timeOffset);\n            return {\n                timeStr: `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`,\n                date: d\n            };\n        }\n\n        \/** ISO 8601 \u5468\u6570\u8ba1\u7b97\uff08\u4e0e Time.is \u4e00\u81f4\uff09 *\/\n        function getWeekNumber(date) {\n            const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n            const dayNum = d.getUTCDay() || 7;\n            d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n            const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n            return Math.ceil((((d - yearStart) \/ 86400000) + 1) \/ 7);\n        }\n\n        \/** \u66f4\u65b0\u65f6\u949f\u663e\u793a\uff08\u539f tick\uff0c\u91cd\u547d\u540d\u4ee5\u533a\u5206\u5706\u73af\u52a8\u753b\u5e27\uff09 *\/\n        function updateClockDisplay() {\n            \/\/ Time.is \u5df2\u63a5\u7ba1\u663e\u793a\u65f6\uff0c\u8df3\u8fc7\u672c\u5730\u66f4\u65b0\uff08\u907f\u514d\u5199\u5165\u5df2\u9690\u85cf\u7684 DOM\uff09\n            if (widgetSynced) return;\n\n            const now = new Date();\n            const disp = getDisplayTime(now);\n\n            \/\/ \u66f4\u65b0\u65f6\u95f4\n            document.getElementById('customTimeDisplay').textContent = disp.timeStr;\n\n            \/\/ \u65e5\u671f\u884c\uff1a\u672c\u5730\u8ba1\u7b97\uff08\u683c\u5f0f\u4e0e Time.is \u5b98\u65b9\u4e00\u81f4\uff09\n            const weekdays = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];\n            const months = ['January','February','March','April','May','June','July','August','September','October','November','December'];\n            const weekdayName = weekdays[disp.date.getDay()];\n            const monthName = months[disp.date.getMonth()];\n            const dateStr = `${weekdayName}, ${disp.date.getDate()} ${monthName}, ${disp.date.getFullYear()}, week ${getWeekNumber(disp.date)}`;\n\n            \/\/ \u6784\u5efa HTML\n            let extraHtml = `<div class=\"date-line\">${dateStr}<\/div>`;\n            if (sunData) {\n                extraHtml += `<div class=\"sun-line\">${sunData.sunrise} ${sunData.sunset}<br>${sunData.dayLength}<\/div>`;\n            }\n            document.getElementById('widgetExtra').innerHTML = extraHtml;\n        }\n\n        function startLocalClock() {\n            if (clockStarted) return;\n            clockStarted = true;\n            updateClockDisplay();\n            setInterval(updateClockDisplay, 1000);\n        }\n\n        \/\/ ========== \u4ece widget span \u63d0\u53d6\u6570\u636e ==========\n        \/**\n         * \u5c1d\u8bd5\u4ece\u9690\u85cf\u7684 Time.is span \u4e2d\u540c\u6b65\u6570\u636e\u3002\n         * @returns {boolean} \u662f\u5426\u6210\u529f\u540c\u6b65\n         *\/\n        function syncFromWidget() {\n            if (widgetSynced) return true;\n\n            const span = document.getElementById('Beijing_z43d');\n            if (!span) return false;\n\n            \/\/ \u4f7f\u7528 innerText \u800c\u975e textContent\uff1a\n            \/\/ widget \u6a21\u677f\u7528 <br> \u5206\u9694\u5404\u884c\uff0ctextContent \u4f1a\u4e22\u5931\u6362\u884c\u4fe1\u606f\uff0c\n            \/\/ innerText \u4f1a\u6b63\u786e\u5c06 <br> \u8f6c\u4e3a \\n\n            const text = span.innerText || span.textContent || '';\n            if (!text || text.trim() === '' || text.includes('undefined')) return false;\n\n            \/\/ widget \u6e32\u67d3\u540e\u7684\u6587\u672c\u7ed3\u6784\uff08\u7531 template \u51b3\u5b9a\uff09\uff1a\n            \/\/ line[0] = \"09:23:47\"                    (TIME)\n            \/\/ line[1] = \"Thursday, 13 August, 2026, week 33\"  (DATE)\n            \/\/ line[2] = \"Sunrise: 05:24 Sunset: 19:15\"       (SUN line 1)\n            \/\/ line[3] = \"Day length: 13h 51m\"                (SUN line 2)\n            const lines = text.split(\/\\n\/).map(s => s.trim()).filter(s => s);\n            if (lines.length < 2) return false;\n\n            \/\/ ---- \u63d0\u53d6\u65f6\u95f4 ----\n            const timeText = lines[0].trim();\n            const timeParts = timeText.match(\/(\\d{1,2}):(\\d{1,2}):(\\d{1,2})\/);\n            if (!timeParts) return false;\n\n            const widgetHour = parseInt(timeParts[1], 10);\n            const widgetMin = parseInt(timeParts[2], 10);\n            const widgetSec = parseInt(timeParts[3], 10);\n\n            const now = new Date();\n            const widgetTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(),\n                                        widgetHour, widgetMin, widgetSec);\n\n            timeOffset = widgetTime.getTime() - now.getTime();\n            widgetSynced = true;\n\n            \/\/ ---- \u63d0\u53d6\u65e5\u671f\u884c\uff08line[1]\uff0c\u542b\u5468\u51e0\u3001\u5e74\u6708\u65e5\u3001\u5468\u6b21\uff09----\n            widgetDateStr = lines[1].trim();\n\n            \/\/ ---- \u6838\u5fc3\uff1a\u663e\u793a Time.is \u539f\u59cb\u5185\u5bb9\uff0c\u9690\u85cf\u672c\u5730 fallback ----\n            const localDisplay = document.getElementById('localDisplay');\n            if (localDisplay) localDisplay.style.display = 'none';\n\n            \/\/ ---- \u63d0\u53d6\u65e5\u51fa\u65e5\u843d\uff08line[2] \u548c line[3]\uff09----\n            if (lines.length >= 4) {\n                const sunLine = lines[2];\n                const lenLine = lines[3];\n\n                const srMatch = sunLine.match(\/Sunrise:\\s*(\\d{1,2}:\\d{2})\/i);\n                const ssMatch = sunLine.match(\/Sunset:\\s*(\\d{1,2}:\\d{2})\/i);\n\n                if (srMatch && ssMatch) {\n                    sunData = {\n                        sunrise: `Sunrise: ${srMatch[1]}`,\n                        sunset:  `Sunset: ${ssMatch[1]}`,\n                        dayLength: lenLine\n                    };\n                }\n            }\n\n            updateClockDisplay();\n            console.log(`\u2705 \u5df2\u4e0e Time.is \u540c\u6b65 | \u504f\u79fb\u91cf: ${(timeOffset\/1000).toFixed(3)} \u79d2`);\n            if (sunData) console.log('\u2705 \u65e5\u51fa\u65e5\u843d\u5df2\u540c\u6b65:', sunData);\n            return true;\n        }\n\n        \/\/ ========== \u521d\u59cb\u5316 widget \u540c\u6b65\uff08MutationObserver \u76d1\u542c span \u5185\u5bb9\u53d8\u5316\uff09 ==========\n        function initWidget() {\n            const span = document.getElementById('Beijing_z43d');\n            if (!span) return;\n\n            \/\/ \u5148\u5c1d\u8bd5\u7acb\u5373\u540c\u6b65\uff08widget \u53ef\u80fd\u5df2\u6e32\u67d3\u5b8c\u6210\uff09\n            if (syncFromWidget()) return;\n\n            const observer = new MutationObserver(() => {\n                if (syncFromWidget()) {\n                    observer.disconnect();\n                }\n            });\n\n            observer.observe(span, {\n                childList: true,\n                subtree: true,\n                characterData: true\n            });\n\n            \/\/ \u515c\u5e95\uff1a\u82e5 Observer \u672a\u89e6\u53d1\uff08\u5982 widget \u76f4\u63a5\u66ff\u6362\u6574\u4e2a span\uff09\uff0c\u7528\u4e00\u6b21\u6027\u5ef6\u8fdf\u68c0\u67e5\n            setTimeout(() => {\n                if (!widgetSynced) syncFromWidget();\n            }, 3000);\n        }\n\n        \/\/ ========== \u542f\u52a8 ==========\n        startLocalClock();  \/\/ \u7acb\u5373\u8d70\u8d77\u6765\n        initWidget();       \/\/ \u7acb\u5373\u8bbe\u7f6e MutationObserver\uff08widget \u5df2\u5728\u4e0a\u65b9\u76f4\u63a5\u521d\u59cb\u5316\uff09\n\n        \/\/ ========== \u672c\u5730\u65e5\u51fa\u65e5\u843d\u8ba1\u7b97\uff08\u5317\u4eac\u5750\u6807\uff0cNOAA \u7b97\u6cd5\uff09 ==========\n        \/**\n         * \u57fa\u4e8e NOAA \u592a\u9633\u8ba1\u7b97\u7b97\u6cd5\u7684\u65e5\u51fa\u65e5\u843d\u8ba1\u7b97\n         * \u4f7f\u7528\u5112\u7565\u65e5\u3001\u592a\u9633\u8d64\u7eac\u89d2\u3001\u5747\u65f6\u5dee\u7b49\u5b8c\u6574\u5929\u6587\u516c\u5f0f\n         * \u7cbe\u5ea6\u53ef\u8fbe \u00b11 \u5206\u949f\u4ee5\u5185\n         *\/\n        function calcSunTimes(date) {\n            const lat = 39.9075;   \/\/ \u5317\u4eac\u7eac\u5ea6\n            const lon = 116.3972;  \/\/ \u5317\u4eac\u7ecf\u5ea6\n            const tz = 8;          \/\/ UTC+8\n\n            const rad = Math.PI \/ 180;\n\n            \/\/ \u5112\u7565\u65e5\u8ba1\u7b97\n            function toJulianDay(y, m, d) {\n                if (m <= 2) { y -= 1; m += 12; }\n                const A = Math.floor(y \/ 100);\n                const B = 2 - A + Math.floor(A \/ 4);\n                return Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + d + B - 1524.5;\n            }\n\n            const jd = toJulianDay(date.getFullYear(), date.getMonth() + 1, date.getDate());\n            const T = (jd - 2451545.0) \/ 36525.0;  \/\/ \u5112\u7565\u4e16\u7eaa\u6570\n\n            \/\/ \u592a\u9633\u51e0\u4f55\u5e73\u9ec4\u7ecf\uff08\u5ea6\uff0c0-360\uff09\n            let L0 = (280.46646 + T * (36000.76983 + T * 0.0003032)) % 360;\n            if (L0 < 0) L0 += 360;\n            const L0rad = L0 * rad;\n\n            \/\/ \u592a\u9633\u51e0\u4f55\u5e73\u8fd1\u70b9\u89d2\uff08\u5ea6\uff09\n            const M = 357.52911 + T * (35999.05029 - T * 0.0001537);\n            const Mrad = M * rad;\n\n            \/\/ \u5730\u7403\u8f68\u9053\u504f\u5fc3\u7387\n            const e = 0.016708634 - T * (0.000042037 + T * 0.0000001267);\n\n            \/\/ \u592a\u9633\u4e2d\u5fc3\u5dee\uff08\u5ea6\uff09\n            const C = Math.sin(Mrad) * (1.914602 - T * (0.004817 + T * 0.000014))\n                    + Math.sin(2 * Mrad) * (0.019993 - T * 0.000101)\n                    + Math.sin(3 * Mrad) * 0.000289;\n\n            \/\/ \u592a\u9633\u771f\u9ec4\u7ecf\uff08\u5ea6\uff09\n            const trueLong = L0 + C;\n\n            \/\/ \u592a\u9633\u89c6\u9ec4\u7ecf\uff08\u5ea6\uff0c\u542b\u7ae0\u52a8\u4fee\u6b63\uff09\n            const omega = 125.04 - 1934.136 * T;\n            const omegaRad = omega * rad;\n            const apparentLong = trueLong - 0.00569 - 0.00478 * Math.sin(omegaRad);\n            const apparentLongRad = apparentLong * rad;\n\n            \/\/ \u9ec4\u9053\u5e73\u5747\u503e\u89d2\uff08\u5ea6\uff09\n            const meanObliq = 23 + (26 + (21.448 - T * (46.815 + T * (0.00059 - T * 0.001813))) \/ 60) \/ 60;\n\n            \/\/ \u9ec4\u9053\u503e\u89d2\u4fee\u6b63\uff08\u5ea6\uff09\n            const obliqCorr = meanObliq + 0.00256 * Math.cos(omegaRad);\n            const obliqCorrRad = obliqCorr * rad;\n\n            \/\/ \u592a\u9633\u8d64\u7eac\u89d2\uff08\u5f27\u5ea6\uff09\n            const declination = Math.asin(Math.sin(obliqCorrRad) * Math.sin(apparentLongRad));\n\n            \/\/ \u5747\u65f6\u5dee\uff08\u5206\u949f\uff09\n            const varY = Math.tan(obliqCorrRad \/ 2) * Math.tan(obliqCorrRad \/ 2);\n            const EoT = 4 * (\n                varY * Math.sin(2 * L0rad)\n                - 2 * e * Math.sin(Mrad)\n                + 4 * e * varY * Math.sin(Mrad) * Math.cos(2 * L0rad)\n                - 0.5 * varY * varY * Math.sin(4 * L0rad)\n                - 1.25 * e * e * Math.sin(2 * Mrad)\n            ) * 180 \/ Math.PI;\n\n            \/\/ \u65e5\u51fa\u65e5\u843d\u65f6\u89d2\uff08\u5ea6\uff0c\u542b\u5927\u6c14\u6298\u5c04\u4fee\u6b63 90.833\u00b0\uff09\n            const zenith = 90.833 * rad;\n            const latRad = lat * rad;\n\n            const cosHA = (Math.cos(zenith) - Math.sin(latRad) * Math.sin(declination))\n                        \/ (Math.cos(latRad) * Math.cos(declination));\n\n            if (cosHA > 1 || cosHA < -1) return null;  \/\/ \u6781\u663c\/\u6781\u591c\n\n            const HA = Math.acos(cosHA) \/ rad;  \/\/ \u5ea6\n\n            \/\/ \u65e5\u51fa\u65e5\u843d\u65f6\u95f4\uff08UTC \u5206\u949f\u6570\uff09\n            const sunriseMinUTC = 720 - 4 * (lon + HA) - EoT;\n            const sunsetMinUTC  = 720 - 4 * (lon - HA) - EoT;\n\n            \/\/ \u8f6c\u6362\u4e3a\u672c\u5730\u65f6\u95f4\uff08UTC+8\uff09\n            const sunriseMinLocal = sunriseMinUTC + tz * 60;\n            const sunsetMinLocal  = sunsetMinUTC  + tz * 60;\n\n            \/\/ \u8f6c\u4e3a HH:MM \u683c\u5f0f\n            function toHM(totalMinutes) {\n                let h = Math.floor(totalMinutes \/ 60);\n                let m = Math.round(totalMinutes % 60);\n                if (m === 60) { h++; m = 0; }\n                if (h >= 24) h -= 24;\n                if (h < 0) h += 24;\n                return `${pad(h)}:${pad(m)}`;\n            }\n\n            \/\/ \u65e5\u7167\u65f6\u957f\n            const dayLenMin = 2 * HA * 4;  \/\/ \u6bcf\u5ea6\u5bf9\u5e94 4 \u5206\u949f\n            const dlH = Math.floor(dayLenMin \/ 60);\n            const dlM = Math.round(dayLenMin % 60);\n\n            return {\n                sunrise: `Sunrise: ${toHM(sunriseMinLocal)}`,\n                sunset: `Sunset: ${toHM(sunsetMinLocal)}`,\n                dayLength: `Day length: ${dlH}h ${dlM}m`\n            };\n        }\n\n        \/\/ ========== 5 \u79d2\u515c\u5e95\uff1a\u8fdb\u5165\u672c\u5730 Fallback \u6a21\u5f0f ==========\n        setTimeout(() => {\n            if (!widgetSynced) {\n                console.log('\u26a0\ufe0f Time.is widget \u672a\u54cd\u5e94\uff08\u53ef\u80fd\u88ab\u5899\/adblock\uff09');\n                console.log('\u2192 \u8fdb\u5165\u672c\u5730 Fallback \u6a21\u5f0f');\n\n                \/\/ \u672c\u5730\u8ba1\u7b97\u65e5\u51fa\u65e5\u843d\n                sunData = calcSunTimes(new Date());\n\n                \/\/ \u66f4\u65b0\u6807\u7b7e\u6587\u5b57\uff1a\u53bb\u6389 Time.is \u5f15\u7528\n                const labelLink = document.getElementById('time_is_link');\n                if (labelLink) {\n                    labelLink.textContent = '\u5317\u4eac\u65f6\u95f4:';\n                    labelLink.href = 'https:\/\/time.is\/Beijing';\n                }\n\n                \/\/ \u6dfb\u52a0 fallback \u6a21\u5f0f\u7c7b\n                const container = document.querySelector('.timewidget-container');\n                if (container) {\n                    container.classList.add('fallback-mode');\n                }\n\n                \/\/ \u6dfb\u52a0 fallback \u5fbd\u7ae0\uff08\u63d2\u5165\u5230 widgetExtra \u4e4b\u540e\uff0c\u907f\u514d\u88ab innerHTML \u8986\u76d6\uff09\n                const widgetExtra = document.getElementById('widgetExtra');\n                if (widgetExtra) {\n                    const badge = document.createElement('div');\n                    badge.className = 'fallback-badge';\n                    badge.textContent = '\u672c\u5730\u65f6\u95f4';\n                    widgetExtra.insertAdjacentElement('afterend', badge);\n                }\n\n                updateClockDisplay();\n            }\n        }, 5000);\n    <\/script>\n<\/div>\n<\/div>\n\n<!-- ===== \u5706\u73af\u7ed8\u5236\uff08\u5206\u5c42\u6e32\u67d3\u4f18\u5316\u7248\uff09 ===== -->\n<script>\n    (function() {\n        \/\/ ==================== \u5e38\u91cf\u4e0e\u914d\u7f6e ====================\n        const START = new Date(2026, 1, 4, 4, 1, 51);\n        const END = new Date(2027, 1, 4, 9, 46, 0);\n        const TOTAL_MS = END.getTime() - START.getTime();\n        const TOTAL_SEC = Math.floor(TOTAL_MS \/ 1000);\n\n        const TERMS = {\n            lichun: { name: '\u7acb\u6625', start: new Date(2026, 1, 4, 4, 1, 51), end: new Date(2026, 1, 18, 23, 51, 39), color: 'past' },\n            lixia: { name: '\u7acb\u590f', start: new Date(2026, 4, 5, 19, 48, 27), end: new Date(2026, 4, 21, 8, 36, 28), color: 'past' },\n            liqiu: { name: '\u7acb\u79cb', start: new Date(2026, 7, 7, 19, 42, 26), end: new Date(2026, 7, 23, 10, 18, 31), color: 'present' },\n            lidong: { name: '\u7acb\u51ac', start: new Date(2026, 10, 7, 17, 51, 46), end: new Date(2026, 10, 22, 15, 23, 3), color: 'future' }\n        };\n\n        const COLORS = {\n            past: { main: '#4A6B8A', light: '#9bb7d4', dark: '#2A3F5A', textColor: '#ffffff', shadowColor: 'rgba(0,0,0,0.8)' },\n            present: { main: '#E8A838', light: '#f7d97a', dark: '#C48820', textColor: '#ffffff', shadowColor: 'rgba(0,0,0,0.8)' },\n            future: { main: '#6B4C9A', light: '#b89edb', dark: '#4A2A7A', textColor: '#ffffff', shadowColor: 'rgba(0,0,0,0.8)' }\n        };\n\n        \/\/ ==================== \u5de5\u5177\u51fd\u6570 ====================\n        function getOffsetMs(date) { return date.getTime() - START.getTime(); }\n        function getOffsetSec(date) { return getOffsetMs(date) \/ 1000; }\n        function offsetToAngle(offsetSec) { return (offsetSec \/ TOTAL_SEC) * 2 * Math.PI; }\n        function dateToAngle(date) { return offsetToAngle(getOffsetSec(date)); }\n        function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }\n        function lerp(a, b, t) { return a + (b - a) * t; }\n        function lerpColor(c1, c2, t) {\n            const r = Math.round(lerp(parseInt(c1.slice(1,3),16), parseInt(c2.slice(1,3),16), t));\n            const g = Math.round(lerp(parseInt(c1.slice(3,5),16), parseInt(c2.slice(3,5),16), t));\n            const b = Math.round(lerp(parseInt(c1.slice(5,7),16), parseInt(c2.slice(5,7),16), t));\n            return `#${r.toString(16).padStart(2,'0')}${g.toString(16).padStart(2,'0')}${b.toString(16).padStart(2,'0')}`;\n        }\n\n        function formatTime(date) {\n            return `${String(date.getHours()).padStart(2,'0')}:${String(date.getMinutes()).padStart(2,'0')}:${String(date.getSeconds()).padStart(2,'0')}`;\n        }\n        function formatDateChinese(date) {\n            return `${date.getFullYear()}\u5e74${String(date.getMonth()+1).padStart(2,'0')}\u6708${String(date.getDate()).padStart(2,'0')}\u65e5`;\n        }\n        function formatNumberWithCommas(x) { return x.toString().replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, ','); }\n        function getElapsedSeconds(now) { return Math.floor((now.getTime() - START.getTime()) \/ 1000); }\n\n        \/\/ ==================== Canvas \u521d\u59cb\u5316 ====================\n        const canvas = document.getElementById('wheelCanvas');\n        if (!canvas) return;\n        const ctx = canvas.getContext('2d');\n        const W = 500, H = 500;\n        const CX = W\/2, CY = H\/2;\n        const RADIUS = 230;\n        const INNER_RADIUS = RADIUS * 0.68;\n\n        const termAngles = {};\n        for (const [key, term] of Object.entries(TERMS)) {\n            termAngles[key] = { start: dateToAngle(term.start), end: dateToAngle(term.end) };\n        }\n\n        \/\/ roundRect polyfill\n        if (!CanvasRenderingContext2D.prototype.roundRect) {\n            CanvasRenderingContext2D.prototype.roundRect = function(x,y,w,h,r) {\n                this.moveTo(x+r, y);\n                this.arcTo(x+w, y, x+w, y+h, r);\n                this.arcTo(x+w, y+h, x, y+h, r);\n                this.arcTo(x, y+h, x, y, r);\n                this.arcTo(x, y, x+w, y, r);\n                return this;\n            };\n        }\n\n        function getNow() { return new Date(); }\n\n        \/\/ ==================== \u9759\u6001\u5c42\uff1a\u79bb\u5c4f Canvas\uff08\u53ea\u7ed8\u5236\u4e00\u6b21\uff09 ====================\n        const staticCanvas = document.createElement('canvas');\n        staticCanvas.width = W;\n        staticCanvas.height = H;\n        const sCtx = staticCanvas.getContext('2d');\n\n        \/** \u5c06\u6240\u6709\u4e0d\u53d8\u7684\u5185\u5bb9\u7ed8\u5236\u5230\u79bb\u5c4f Canvas *\/\n        function renderStaticLayer() {\n            sCtx.clearRect(0, 0, W, H);\n            drawBackgroundRing(sCtx);\n            for (const [key, term] of Object.entries(TERMS)) {\n                drawTermSector(sCtx, key, term);\n            }\n            for (const [key, term] of Object.entries(TERMS)) {\n                drawTermName(sCtx, key, term);\n            }\n            for (const [key, term] of Object.entries(TERMS)) {\n                drawTermTimeLabels(sCtx, key, term);\n            }\n            drawInnerRing(sCtx);\n        }\n\n        \/\/ ==================== \u9759\u6001\u7ed8\u5236\u51fd\u6570\uff08\u63a5\u6536 context \u53c2\u6570\uff09 ====================\n        function drawBackgroundRing(c) {\n            const outer = RADIUS, inner = INNER_RADIUS;\n            const segments = 180;\n            for (let i=0; i<segments; i++) {\n                const t1 = i\/segments, t2 = (i+1)\/segments;\n                const a1 = t1*2*Math.PI, a2 = t2*2*Math.PI;\n                const color = getRingColor(t1);\n                c.beginPath();\n                c.arc(CX, CY, outer, a1, a2);\n                c.arc(CX, CY, inner, a2, a1, true);\n                c.closePath();\n                c.fillStyle = color;\n                c.fill();\n            }\n            const edgeGrad = c.createRadialGradient(CX, CY, inner, CX, CY, outer);\n            edgeGrad.addColorStop(0, 'rgba(0,0,0,0)');\n            edgeGrad.addColorStop(0.5, 'rgba(0,0,0,0)');\n            edgeGrad.addColorStop(0.85, 'rgba(0,0,0,0.15)');\n            edgeGrad.addColorStop(1, 'rgba(0,0,0,0.25)');\n            c.fillStyle = edgeGrad;\n            c.beginPath();\n            c.arc(CX, CY, outer, 0, 2*Math.PI);\n            c.fill();\n            const innerGlow = c.createRadialGradient(CX, CY, inner*0.8, CX, CY, inner*1.1);\n            innerGlow.addColorStop(0, 'rgba(0,0,0,0.5)');\n            innerGlow.addColorStop(1, 'rgba(0,0,0,0)');\n            c.fillStyle = innerGlow;\n            c.beginPath();\n            c.arc(CX, CY, inner*1.1, 0, 2*Math.PI);\n            c.fill();\n        }\n\n        function getRingColor(t) {\n            const past1 = '#3b4f6e', past2 = '#5f7a9a', present1 = '#e8a838', present2 = '#f5c75a', future1 = '#6b4c9a', future2 = '#a07bc9';\n            let color;\n            if (t < 0.04) { const p = t\/0.04; color = lerpColor('#2a3a4a', past1, p); }\n            else if (t < 0.15) { const p = (t-0.04)\/0.11; color = lerpColor(past1, past2, p); }\n            else if (t < 0.29) { const p = (t-0.15)\/0.14; color = lerpColor(past2, '#8a9aaa', p); }\n            else if (t < 0.42) { const p = (t-0.29)\/0.13; color = lerpColor('#8a9aaa', '#c0a87a', p); }\n            else if (t < 0.54) { const p = (t-0.42)\/0.12; color = lerpColor('#c0a87a', present1, p); }\n            else if (t < 0.68) { const p = (t-0.54)\/0.14; color = lerpColor(present1, '#b09080', p); }\n            else if (t < 0.79) { const p = (t-0.68)\/0.11; color = lerpColor('#b09080', future1, p); }\n            else if (t < 0.92) { const p = (t-0.79)\/0.13; color = lerpColor(future1, future2, p); }\n            else { const p = (t-0.92)\/0.08; color = lerpColor(future2, '#2a2a3a', p); }\n            return color;\n        }\n\n        function drawTermSector(c, key, term) {\n            const { start, end } = termAngles[key];\n            const colors = COLORS[term.color];\n            const outer = RADIUS - 2, inner = INNER_RADIUS + 2;\n            const grad = c.createRadialGradient(CX, CY, inner, CX, CY, outer);\n            grad.addColorStop(0, colors.dark);\n            grad.addColorStop(0.3, colors.main);\n            grad.addColorStop(0.7, colors.light);\n            grad.addColorStop(1, colors.main);\n            c.beginPath();\n            c.arc(CX, CY, outer, start, end);\n            c.arc(CX, CY, inner, end, start, true);\n            c.closePath();\n            c.fillStyle = grad;\n            c.fill();\n            c.shadowColor = 'rgba(0,0,0,0.15)';\n            c.shadowBlur = 15;\n            c.strokeStyle = colors.light;\n            c.lineWidth = 1.5;\n            c.globalAlpha = 0.3;\n            c.stroke();\n            c.shadowBlur = 0;\n            c.globalAlpha = 1;\n            c.beginPath();\n            c.arc(CX, CY, outer, start, end);\n            c.strokeStyle = 'rgba(255,255,255,0.08)';\n            c.lineWidth = 0.5;\n            c.stroke();\n            c.beginPath();\n            c.arc(CX, CY, inner, start, end);\n            c.strokeStyle = 'rgba(255,255,255,0.05)';\n            c.lineWidth = 0.5;\n            c.stroke();\n            for (const a of [start, end]) {\n                c.beginPath();\n                c.moveTo(CX + Math.cos(a)*inner, CY + Math.sin(a)*inner);\n                c.lineTo(CX + Math.cos(a)*outer, CY + Math.sin(a)*outer);\n                c.strokeStyle = 'rgba(255,255,255,0.05)';\n                c.lineWidth = 0.5;\n                c.stroke();\n            }\n        }\n\n        function drawTermName(c, key, term) {\n            const { start, end } = termAngles[key];\n            const mid = (start+end)\/2;\n            const radius = RADIUS * 0.82;\n            const x = CX + Math.cos(mid)*radius, y = CY + Math.sin(mid)*radius;\n            const colors = COLORS[term.color];\n            c.font = '600 20px \"Inter\",\"Segoe UI\",sans-serif';\n            c.textAlign = 'center';\n            c.textBaseline = 'middle';\n            c.shadowColor = colors.shadowColor;\n            c.shadowBlur = 8;\n            c.fillStyle = colors.textColor;\n            c.fillText(term.name, x, y);\n            c.shadowBlur = 0;\n        }\n\n        function drawTermTimeLabels(c, key, term) {\n            const { start, end } = termAngles[key];\n            const colors = COLORS[term.color];\n            const outerR = RADIUS - 6, innerR = RADIUS * 0.7;\n            drawRadialTimeLabel(c, start, term.start, colors, outerR, innerR);\n            drawRadialTimeLabel(c, end, term.end, colors, outerR, innerR);\n        }\n\n        function drawRadialTimeLabel(c, angle, dateObj, colors, outerR, innerR) {\n            const dateStr = formatDateChinese(dateObj);\n            const timeStr = formatTime(dateObj);\n            const fontSize = 8, lineHeight = 10;\n            const radius = (outerR + innerR)\/2 + 4;\n            const x = CX + Math.cos(angle)*radius, y = CY + Math.sin(angle)*radius;\n            c.save();\n            c.translate(x, y);\n            c.rotate(angle);\n            c.font = `${fontSize}px \"Inter\",monospace`;\n            c.textAlign = 'center';\n            c.textBaseline = 'middle';\n            c.shadowColor = 'rgba(0,0,0,0.9)';\n            c.shadowBlur = 6;\n            c.fillStyle = colors.textColor;\n            c.fillText(dateStr, 0, -lineHeight\/2);\n            c.fillText(timeStr, 0, lineHeight\/2);\n            c.shadowBlur = 0;\n            c.restore();\n        }\n\n        function drawInnerRing(c) {\n            const r = INNER_RADIUS;\n            c.beginPath();\n            c.arc(CX, CY, r, 0, 2*Math.PI);\n            c.strokeStyle = 'rgba(255,255,255,0.04)';\n            c.lineWidth = 1;\n            c.stroke();\n            for (let i=0; i<72; i++) {\n                const angle = (i\/72)*2*Math.PI;\n                const dotR = (i%6===0) ? 4 : 2;\n                const dx = CX + Math.cos(angle)*(r-6), dy = CY + Math.sin(angle)*(r-6);\n                c.beginPath();\n                c.arc(dx, dy, dotR, 0, 2*Math.PI);\n                c.fillStyle = (i%6===0) ? 'rgba(255,255,255,0.06)' : 'rgba(255,255,255,0.02)';\n                c.fill();\n            }\n        }\n\n        \/\/ ==================== \u52a8\u6001\u5c42\uff1a\u7cbe\u7075\u7f13\u5b58 + \u810f\u5e27\u68c0\u6d4b ====================\n\n        \/\/ ---------- \u9884\u6e32\u67d3\uff1a\u6807\u8bb0\u7cbe\u7075\uff08\u5f62\u72b6\u6c38\u8fdc\u4e0d\u53d8\uff0c\u53ea\u6709\u4f4d\u7f6e\u53d8\uff09 ----------\n        const MARKER_SIZE = 96;  \/\/ \u8db3\u591f\u5bb9\u7eb3 46px \u534a\u5f84\u7684\u53d1\u5149\n        const markerSprite = document.createElement('canvas');\n        markerSprite.width = MARKER_SIZE;\n        markerSprite.height = MARKER_SIZE;\n        (function renderMarkerSprite() {\n            const mc = markerSprite.getContext('2d');\n            const half = MARKER_SIZE \/ 2;\n\n            \/\/ \u5916\u53d1\u5149\n            const glow = mc.createRadialGradient(half, half, 0, half, half, 46);\n            glow.addColorStop(0, 'rgba(255,215,100,0.35)');\n            glow.addColorStop(0.3, 'rgba(255,215,100,0.12)');\n            glow.addColorStop(1, 'rgba(255,215,100,0)');\n            mc.fillStyle = glow;\n            mc.beginPath();\n            mc.arc(half, half, 46, 0, 2*Math.PI);\n            mc.fill();\n\n            \/\/ \u865a\u7ebf\u5706\u73af\n            mc.beginPath();\n            mc.arc(half, half, 18, 0, 2*Math.PI);\n            mc.strokeStyle = 'rgba(255,215,100,0.3)';\n            mc.lineWidth = 2;\n            mc.setLineDash([4,6]);\n            mc.stroke();\n            mc.setLineDash([]);\n\n            \/\/ \u4e2d\u5fc3\u6e10\u53d8\u5706\u70b9\n            const grad = mc.createRadialGradient(half, half, 0, half, half, 12);\n            grad.addColorStop(0, '#ffffff');\n            grad.addColorStop(0.3, '#f5d06a');\n            grad.addColorStop(0.7, '#e8a838');\n            grad.addColorStop(1, 'rgba(232,168,56,0.2)');\n            mc.fillStyle = grad;\n            mc.beginPath();\n            mc.arc(half, half, 12, 0, 2*Math.PI);\n            mc.fill();\n\n            \/\/ \u9ad8\u5149\n            mc.fillStyle = 'rgba(255,255,255,0.6)';\n            mc.beginPath();\n            mc.arc(half-3, half-4, 3.5, 0, 2*Math.PI);\n            mc.fill();\n        })();\n\n        \/\/ ---------- \u9884\u6e32\u67d3\uff1a\u4e2d\u5fc3\u4fe1\u606f\u80cc\u666f\uff08\u534a\u900f\u660e\u5706\uff0c\u6c38\u8fdc\u4e0d\u53d8\uff09 ----------\n        const CENTER_R = RADIUS * 0.45;\n        const CENTER_SIZE = Math.ceil(CENTER_R * 2) + 2;\n        const centerBgSprite = document.createElement('canvas');\n        centerBgSprite.width = CENTER_SIZE;\n        centerBgSprite.height = CENTER_SIZE;\n        (function renderCenterBg() {\n            const cc = centerBgSprite.getContext('2d');\n            const half = CENTER_SIZE \/ 2;\n            const grad = cc.createRadialGradient(half, half, 0, half, half, CENTER_R);\n            grad.addColorStop(0, 'rgba(10,14,22,0.75)');\n            grad.addColorStop(0.7, 'rgba(10,14,22,0.85)');\n            grad.addColorStop(1, 'rgba(10,14,22,0.92)');\n            cc.fillStyle = grad;\n            cc.beginPath();\n            cc.arc(half, half, CENTER_R, 0, 2*Math.PI);\n            cc.fill();\n            cc.strokeStyle = 'rgba(255,255,255,0.04)';\n            cc.lineWidth = 0.5;\n            cc.beginPath();\n            cc.arc(half, half, CENTER_R, 0, 2*Math.PI);\n            cc.stroke();\n        })();\n\n        \/\/ ---------- \u6587\u672c\u7f13\u5b58\uff1a\u907f\u514d\u6bcf\u5e27\u91cd\u590d\u683c\u5f0f\u5316 ----------\n        const TOTAL_STR = formatNumberWithCommas(TOTAL_SEC);  \/\/ \u5e38\u91cf\uff0c\u53ea\u7b97\u4e00\u6b21\n        let cachedSecond = -1;        \/\/ \u4e0a\u4e00\u6b21\u6e32\u67d3\u7684\u79d2\u6570\n        let cachedTimeStr = '';       \/\/ \u6807\u8bb0\u5916\u7f18\u65f6\u95f4\u6807\u7b7e\n        let cachedElapsedStr = '';    \/\/ \u5df2\u8fc7\u79d2\u6570\n        let cachedDateStr = '';       \/\/ \u65e5\u671f\uff08\u6bcf\u5929\u624d\u53d8\u4e00\u6b21\uff09\n        let cachedPctStr = '';        \/\/ \u8fdb\u5ea6\u767e\u5206\u6bd4\n        let cachedDayKey = '';        \/\/ \u7528\u4e8e\u68c0\u6d4b\u65e5\u671f\u5207\u6362\n\n        \/** \u5f53\u79d2\u6570\u53d8\u5316\u65f6\uff0c\u6279\u91cf\u66f4\u65b0\u6240\u6709\u7f13\u5b58\u5b57\u7b26\u4e32 *\/\n        function refreshTextCache(now) {\n            const sec = now.getSeconds();\n            if (sec === cachedSecond) return false;  \/\/ \u672a\u53d8\u5316\uff0c\u8df3\u8fc7\n            cachedSecond = sec;\n\n            cachedTimeStr = formatTime(now);\n            const elapsed = Math.min(getElapsedSeconds(now), TOTAL_SEC);\n            cachedElapsedStr = formatNumberWithCommas(elapsed);\n\n            const offset = clamp(getOffsetSec(now), 0, TOTAL_SEC);\n            cachedPctStr = `\u8fdb\u5ea6 ${(offset \/ TOTAL_SEC * 100).toFixed(1)}%`;\n\n            \/\/ \u65e5\u671f\u53ea\u5728\u8de8\u5929\u65f6\u66f4\u65b0\n            const dayKey = `${now.getFullYear()}-${now.getMonth()}-${now.getDate()}`;\n            if (dayKey !== cachedDayKey) {\n                cachedDayKey = dayKey;\n                cachedDateStr = formatDateChinese(now);\n            }\n            return true;  \/\/ \u6709\u53d8\u5316\n        }\n\n        \/\/ ---------- \u52a8\u6001\u7ed8\u5236\u51fd\u6570 ----------\n\n        \/** \u7ed8\u5236\u5f53\u524d\u65f6\u95f4\u6807\u8bb0\uff08\u8d34\u7cbe\u7075\u56fe + \u8fde\u7ebf + \u65f6\u95f4\u6807\u7b7e\uff09 *\/\n        function drawCurrentMarker(c, now) {\n            const offset = getOffsetSec(now);\n            const clamped = clamp(offset, 0, TOTAL_SEC);\n            const angle = offsetToAngle(clamped);\n            const radius = RADIUS * 0.78;\n            const x = CX + Math.cos(angle)*radius;\n            const y = CY + Math.sin(angle)*radius;\n\n            \/\/ \u5706\u5fc3\u5230\u6807\u8bb0\u7684\u865a\u7ebf\uff08\u5148\u753b\u7ebf\uff0c\u540e\u9762\u4e2d\u5fc3\u80cc\u666f\u4f1a\u8986\u76d6\u5185\u4fa7\uff09\n            c.beginPath();\n            c.moveTo(CX, CY);\n            c.lineTo(x, y);\n            c.strokeStyle = 'rgba(255,215,100,0.08)';\n            c.lineWidth = 1;\n            c.setLineDash([3,6]);\n            c.stroke();\n            c.setLineDash([]);\n\n            \/\/ \u8d34\u5165\u9884\u6e32\u67d3\u7684\u6807\u8bb0\u7cbe\u7075\uff08\u4e00\u6b21 drawImage \u66ff\u4ee3 5 \u4e2a arc + 2 \u4e2a\u6e10\u53d8\uff09\n            c.drawImage(markerSprite, x - MARKER_SIZE\/2, y - MARKER_SIZE\/2);\n\n            \/\/ \u5916\u7f18\u65f6\u95f4\u6807\u7b7e\n            c.font = '500 11px \"Inter\",monospace';\n            c.fillStyle = 'rgba(255,215,100,0.7)';\n            c.textAlign = 'center';\n            c.textBaseline = 'bottom';\n            const labelR = RADIUS * 0.92;\n            const lx = CX + Math.cos(angle)*labelR;\n            const ly = CY + Math.sin(angle)*labelR;\n            c.shadowColor = 'rgba(0,0,0,0.6)';\n            c.shadowBlur = 4;\n            c.fillText(cachedTimeStr, lx, ly-2);\n            c.shadowBlur = 0;\n        }\n\n        \/** \u7ed8\u5236\u4e2d\u5fc3\u4fe1\u606f\u9762\u677f\uff08\u8d34\u80cc\u666f\u7cbe\u7075 + \u7f13\u5b58\u6587\u5b57\uff09 *\/\n        function drawCenterInfo(c) {\n            \/\/ \u8d34\u5165\u9884\u6e32\u67d3\u7684\u4e2d\u5fc3\u80cc\u666f\uff08\u4e00\u6b21 drawImage \u66ff\u4ee3\u6e10\u53d8 + arc + stroke\uff09\n            c.drawImage(centerBgSprite, CX - CENTER_SIZE\/2, CY - CENTER_SIZE\/2);\n\n            \/\/ \u603b\u79d2\u6570\uff08\u5e38\u91cf\u5b57\u7b26\u4e32\uff09\n            c.font = '600 22px \"Inter\",monospace';\n            c.fillStyle = '#e8edf5';\n            c.textAlign = 'center';\n            c.textBaseline = 'bottom';\n            c.fillText(TOTAL_STR, CX, CY - 12);\n            c.font = '300 9px \"Inter\",sans-serif';\n            c.fillStyle = 'rgba(255,255,255,0.3)';\n            c.fillText('\u603b\u79d2\u6570', CX + 4, CY - 18);\n\n            \/\/ \u65e5\u671f\n            c.font = '400 11px \"Inter\",sans-serif';\n            c.fillStyle = 'rgba(255,255,255,0.3)';\n            c.fillText(cachedDateStr, CX, CY + 4);\n\n            \/\/ \u5df2\u8fc7\u79d2\u6570\n            c.font = '600 20px \"Inter\",monospace';\n            c.fillStyle = '#f5d06a';\n            c.textBaseline = 'top';\n            c.fillText(cachedElapsedStr, CX, CY + 12);\n            c.font = '300 9px \"Inter\",sans-serif';\n            c.fillStyle = 'rgba(255,255,255,0.3)';\n            c.fillText('\u5df2\u8fc7\u79d2\u6570', CX + 6, CY + 32);\n\n            \/\/ \u8fdb\u5ea6\u767e\u5206\u6bd4\n            c.fillStyle = 'rgba(255,255,255,0.15)';\n            c.fillText(cachedPctStr, CX, CY + 46);\n        }\n\n        \/\/ ==================== \u52a8\u753b\u4e3b\u5faa\u73af\uff08\u810f\u5e27\u68c0\u6d4b\uff09 ====================\n\n        let lastRenderedSecond = -1;\n\n        \/**\n         * \u5706\u73af\u52a8\u753b\u5e27\u3002\n         * \u6838\u5fc3\u4f18\u5316\uff1a\u6807\u8bb0\u5728\u4e00\u5e74\u5185\u6bcf\u79d2\u4ec5\u79fb\u52a8 ~0.00004px\uff0c\n         * \u79d2\u6570\u672a\u53d8\u65f6\u753b\u9762\u5b8c\u5168\u76f8\u540c\uff0c\u76f4\u63a5\u8df3\u8fc7\u7ed8\u5236\u3002\n         *\/\n        function renderWheelFrame() {\n            const now = getNow();\n            const currentSecond = Math.floor(now.getTime() \/ 1000);\n\n            \/\/ \u810f\u5e27\u68c0\u6d4b\uff1a\u79d2\u6570\u672a\u53d8 \u2192 \u753b\u9762\u65e0\u4efb\u4f55\u53d8\u5316\uff0c\u8df3\u8fc7\u672c\u5e27\n            if (currentSecond === lastRenderedSecond) {\n                requestAnimationFrame(renderWheelFrame);\n                return;\n            }\n            lastRenderedSecond = currentSecond;\n\n            \/\/ \u5237\u65b0\u6587\u672c\u7f13\u5b58\n            refreshTextCache(now);\n\n            \/\/ 1. \u6e05\u9664\u53ef\u89c1\u753b\u5e03\n            ctx.clearRect(0, 0, W, H);\n\n            \/\/ 2. \u8d34\u5165\u9759\u6001\u5c42\n            ctx.drawImage(staticCanvas, 0, 0);\n\n            \/\/ 3. \u7ed8\u5236\u52a8\u6001\u90e8\u5206\uff08\u6807\u8bb0 + \u4e2d\u5fc3\u4fe1\u606f\uff09\n            drawCurrentMarker(ctx, now);\n            drawCenterInfo(ctx);\n\n            requestAnimationFrame(renderWheelFrame);\n        }\n\n        \/\/ ==================== \u542f\u52a8 ====================\n        renderStaticLayer();\n\n        if (document.readyState === 'complete') {\n            renderWheelFrame();\n        } else {\n            window.addEventListener('load', renderWheelFrame);\n        }\n\n        \/\/ ==================== \u6eda\u52a8\u52a8\u6001\u6548\u679c\uff08\u5df2\u9002\u914d\u79fb\u52a8\u7aef\uff09 ====================\n        (function initScrollEffects() {\n            const wrapper = document.querySelector('.timewheel-wrapper');\n            const parallaxLayer = document.getElementById('parallaxLayer');\n            const tiltLayer = document.getElementById('tiltLayer');\n            const bgGlowLayer = document.getElementById('bgGlowLayer');\n            const widgetParallaxEl = document.getElementById('widgetParallaxLayer');\n            if (!wrapper) return;\n\n            \/\/ ---------- \u8bbe\u5907\u68c0\u6d4b ----------\n            const isMobile = window.matchMedia('(max-width: 768px)').matches\n                          || \/Android|iPhone|iPad|iPod\/i.test(navigator.userAgent);\n\n            \/\/ \u79fb\u52a8\u7aef\u89c6\u5dee\u5f3a\u5ea6\u7cfb\u6570\uff08\u7f29\u5c0f\u5e45\u5ea6\uff0c\u907f\u514d\u5c0f\u5c4f\u8fc7\u5ea6\u52a8\u6548\uff09\n            const intensity = isMobile ? 0.5 : 1.0;\n\n            \/\/ ---------- 1. \u5165\u573a\/\u79bb\u573a\u68c0\u6d4b\uff08IntersectionObserver + \u515c\u5e95\uff09 ----------\n            const io = new IntersectionObserver((entries) => {\n                for (const entry of entries) {\n                    if (entry.isIntersecting) {\n                        wrapper.classList.add('in-view');\n                        wrapper.classList.remove('out-view');\n                    } else {\n                        wrapper.classList.remove('in-view');\n                        wrapper.classList.add('out-view');\n                    }\n                }\n            }, {\n                threshold: [0, 0.25, 0.5],\n                rootMargin: '0px 0px -10% 0px'\n            });\n            io.observe(wrapper);\n\n            \/\/ \u515c\u5e95\uff1a\u82e5 IntersectionObserver \u672a\u89e6\u53d1\uff08\u5982 iframe\/\u7279\u6b8a\u5bb9\u5668\u73af\u5883\uff09\uff0c\n            \/\/ 300ms \u540e\u5f3a\u5236\u663e\u793a\uff0c\u907f\u514d\u7ec4\u4ef6\u6c38\u8fdc\u4e0d\u53ef\u89c1\n            setTimeout(() => {\n                if (!wrapper.classList.contains('in-view')) {\n                    wrapper.classList.add('in-view');\n                    wrapper.classList.remove('out-view');\n                }\n            }, 300);\n\n            \/\/ Widget \u6de1\u5165\u515c\u5e95\uff08\u540c\u6837\u4f9d\u8d56 in-view \u89e6\u53d1\uff09\n            setTimeout(() => {\n                const widgetContainer = document.querySelector('.timewidget-container');\n                if (widgetContainer && !wrapper.classList.contains('in-view')) {\n                    widgetContainer.style.opacity = '1';\n                    widgetContainer.style.transform = 'translateY(0)';\n                }\n            }, 800);\n\n            \/\/ ---------- 2. \u591a\u5c42\u89c6\u5dee\uff08\u6eda\u52a8\u9a71\u52a8\uff09 ----------\n            if (!parallaxLayer) return;\n\n            let rafPending = false;\n            let isComponentVisible = true;  \/\/ \u7528\u4e8e rAF \u5faa\u73af\u4e2d\u8df3\u8fc7\u4e0d\u53ef\u89c1\u65f6\u7684\u8ba1\u7b97\n\n            \/**\n             * \u591a\u5c42\u89c6\u5dee\u66f4\u65b0\uff08\u684c\u9762\u7aef\uff09\uff1a\n             *   \u80cc\u666f\u5149\u6655\u5c42   \u2192 \u901f\u7387 0.35x\uff08\u6700\u8fdc\uff0c\u79fb\u52a8\u6700\u6162\uff09\n             *   \u5706\u73af\u4e3b\u4f53\u5c42   \u2192 \u901f\u7387 1.0x\uff08\u57fa\u51c6\u5c42\uff09\n             *   Widget \u524d\u666f\u5c42 \u2192 \u901f\u7387 1.5x\uff08\u6700\u8fd1\uff0c\u79fb\u52a8\u6700\u5feb\uff09\n             *   3D \u503e\u659c\u5c42     \u2192 \u6eda\u52a8\u4ea7\u751f perspective rotateX\n             *\n             * \u79fb\u52a8\u7aef\u4f18\u5316\uff1a\n             *   - \u6240\u6709\u5e45\u5ea6\u4e58\u4ee5 intensity (0.5)\uff0c\u51cf\u5c11\u52a8\u6548\u5e45\u5ea6\n             *   - \u53bb\u6389 3D \u503e\u659c\u5c42\uff08\u51cf\u5c11 GPU \u5408\u6210\u5c42\uff09\n             *   - \u4f7f\u7528 rAF \u5faa\u73af\u66ff\u4ee3 scroll \u4e8b\u4ef6\uff08\u517c\u5bb9 iOS \u60ef\u6027\u6eda\u52a8\uff09\n             *\/\n            function updateParallax() {\n                rafPending = false;\n\n                const rect = wrapper.getBoundingClientRect();\n                const viewportH = window.innerHeight;\n\n                \/\/ \u7ec4\u4ef6\u4e2d\u5fc3\u76f8\u5bf9\u4e8e\u89c6\u53e3\u4e2d\u5fc3\u7684\u504f\u79fb\u6bd4\u4f8b\uff08-1 ~ 1\uff09\n                const center = rect.top + rect.height \/ 2;\n                const offset = (center - viewportH \/ 2) \/ (viewportH \/ 2);\n                const clampedOffset = Math.max(-1, Math.min(1, offset));\n\n                \/\/ --- \u5706\u73af\u4e3b\u4f53\u5c42 ---\n                const rotateDeg = clampedOffset * 4 * intensity;\n                const scale = 1 - Math.abs(clampedOffset) * 0.04 * intensity;\n                const translateY = clampedOffset * -8 * intensity;\n                parallaxLayer.style.transform =\n                    `rotate(${rotateDeg}deg) scale(${scale}) translateY(${translateY}px)`;\n\n                \/\/ --- 3D \u503e\u659c\u5c42\uff08\u4ec5\u684c\u9762\u7aef\uff09 ---\n                if (tiltLayer && !isMobile) {\n                    const rotateX = clampedOffset * -6;\n                    const rotateZ = clampedOffset * 1.5;\n                    tiltLayer.style.transform =\n                        `rotateX(${rotateX}deg) rotateZ(${rotateZ}deg)`;\n                }\n\n                \/\/ --- \u80cc\u666f\u5149\u6655\u5c42 ---\n                if (bgGlowLayer) {\n                    const bgY = clampedOffset * 25 * intensity;\n                    const bgScale = 1 + Math.abs(clampedOffset) * 0.06 * intensity;\n                    bgGlowLayer.style.transform =\n                        `translateY(${bgY}px) scale(${bgScale})`;\n                }\n\n                \/\/ --- Widget \u524d\u666f\u5c42 ---\n                if (widgetParallaxEl) {\n                    const widgetY = clampedOffset * -14 * intensity;\n                    widgetParallaxEl.style.transform = `translateY(${widgetY}px)`;\n                }\n            }\n\n            \/\/ ---------- \u79fb\u52a8\u7aef\uff1a\u4f7f\u7528 rAF \u5faa\u73af\u66ff\u4ee3 scroll \u4e8b\u4ef6 ----------\n            \/\/ iOS Safari \u5728\u60ef\u6027\u6eda\u52a8\u671f\u95f4\u4e0d\u89e6\u53d1 scroll \u4e8b\u4ef6\uff0c\n            \/\/ \u4f7f\u7528\u6301\u7eed rAF \u5faa\u73af\u68c0\u6d4b\u6eda\u52a8\u4f4d\u7f6e\u53d8\u5316\uff0c\u786e\u4fdd\u89c6\u5dee\u5e73\u6ed1\u66f4\u65b0\u3002\n            if (isMobile) {\n                let lastKnownScrollY = window.pageYOffset;\n\n                function mobileLoop() {\n                    const currentScrollY = window.pageYOffset;\n\n                    \/\/ \u53ea\u5728\u6eda\u52a8\u4f4d\u7f6e\u53d8\u5316\u6216\u7ec4\u4ef6\u53ef\u89c1\u65f6\u624d\u66f4\u65b0\n                    if (currentScrollY !== lastKnownScrollY && isComponentVisible) {\n                        lastKnownScrollY = currentScrollY;\n                        updateParallax();\n                    }\n\n                    requestAnimationFrame(mobileLoop);\n                }\n                requestAnimationFrame(mobileLoop);\n\n                \/\/ \u66f4\u65b0\u7ec4\u4ef6\u53ef\u89c1\u6027\uff08\u907f\u514d\u4e0d\u53ef\u89c1\u65f6\u6d6a\u8d39 rAF \u8ba1\u7b97\uff09\n                const visObserver = new IntersectionObserver((entries) => {\n                    isComponentVisible = entries[0].isIntersecting;\n                }, { threshold: 0 });\n                visObserver.observe(wrapper);\n\n            } else {\n                \/\/ ---------- \u684c\u9762\u7aef\uff1ascroll \u4e8b\u4ef6 + rAF \u8282\u6d41 ----------\n                window.addEventListener('scroll', () => {\n                    if (!rafPending) {\n                        rafPending = true;\n                        requestAnimationFrame(updateParallax);\n                    }\n                }, { passive: true });\n            }\n\n            \/\/ ---------- \u79fb\u52a8\u7aef\uff1avisualViewport \u76d1\u542c\uff08\u5730\u5740\u680f\u6536\u7f29\/\u5c55\u5f00\uff09 ----------\n            \/\/ iOS\/Android \u6d4f\u89c8\u5668\u5730\u5740\u680f\u6536\u7f29\u65f6 innerHeight \u53d8\u5316\uff0c\n            \/\/ \u901a\u8fc7 visualViewport \u76d1\u542c\u91cd\u65b0\u8ba1\u7b97\u89c6\u5dee\u4f4d\u7f6e\u3002\n            if (isMobile && window.visualViewport) {\n                window.visualViewport.addEventListener('resize', () => {\n                    updateParallax();\n                }, { passive: true });\n            }\n\n            \/\/ ---------- \u79fb\u52a8\u7aef\uff1atouch \u89e6\u6478\u5fae\u89c6\u5dee\uff08\u8865\u5145\u6eda\u52a8\u89c6\u5dee\uff09 ----------\n            \/\/ \u5728\u5706\u73af\u4e0a\u89e6\u6478\u65f6\u4ea7\u751f\u8f7b\u5fae\u504f\u79fb\uff0c\u589e\u52a0\u4e92\u52a8\u611f\u3002\n            \/\/ \u6ce8\u610f\uff1a\u4e0d\u80fd\u76f4\u63a5\u8ffd\u52a0 transform\uff0c\u5426\u5219\u6bcf\u6b21 touchmove \u4f1a\u7d2f\u79ef\u53e0\u52a0\u3002\n            \/\/ \u6b63\u786e\u505a\u6cd5\uff1a\u5148\u8ba1\u7b97\u57fa\u7840 transform\uff0c\u518d\u5728\u5176\u540e\u8ffd\u52a0\u5fae\u504f\u79fb\u3002\n            if (isMobile && parallaxLayer) {\n                let touchStartX = 0, touchStartY = 0;\n                let baseTransform = '';  \/\/ \u7f13\u5b58\u57fa\u7840 transform\uff0c\u907f\u514d\u7d2f\u79ef\n\n                wrapper.addEventListener('touchstart', (e) => {\n                    const touch = e.touches[0];\n                    touchStartX = touch.clientX;\n                    touchStartY = touch.clientY;\n                    \/\/ \u8bb0\u5f55\u89e6\u6478\u5f00\u59cb\u65f6\u7684\u57fa\u7840 transform\n                    baseTransform = parallaxLayer.style.transform || '';\n                }, { passive: true });\n\n                wrapper.addEventListener('touchmove', (e) => {\n                    const touch = e.touches[0];\n                    const dx = (touch.clientX - touchStartX) \/ window.innerWidth;\n                    const dy = (touch.clientY - touchStartY) \/ window.innerHeight;\n\n                    \/\/ \u5fae\u5c0f\u7684\u504f\u79fb\uff08\u6700\u591a \u00b13px\uff09\uff0c\u4e0d\u5f71\u54cd\u6eda\u52a8\u64cd\u4f5c\n                    const microX = dx * 3;\n                    const microY = dy * 3;\n\n                    \/\/ \u57fa\u4e8e\u7f13\u5b58\u7684\u57fa\u7840 transform \u8ffd\u52a0\u5fae\u504f\u79fb\uff08\u800c\u975e\u7d2f\u79ef\uff09\n                    parallaxLayer.style.transform =\n                        `${baseTransform} translate(${microX}px, ${microY}px)`;\n                }, { passive: true });\n\n                wrapper.addEventListener('touchend', () => {\n                    \/\/ \u89e6\u6478\u7ed3\u675f\u540e\u56de\u5f39\uff1a\u79fb\u9664\u5fae\u89c6\u5dee\uff0c\u91cd\u65b0\u8ba1\u7b97\u57fa\u7840\u4f4d\u7f6e\n                    updateParallax();\n                }, { passive: true });\n            }\n\n            \/\/ \u521d\u59cb\u5316\u65f6\u4e5f\u6267\u884c\u4e00\u6b21\uff08\u5904\u7406\u9875\u9762\u52a0\u8f7d\u65f6\u5df2\u5728\u89c6\u53e3\u5185\u7684\u60c5\u51b5\uff09\n            updateParallax();\n        })();\n    })();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Time in Beijing: &#8211;:&#8211;:&#8211;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10361","post","type-post","status-publish","format-standard","hentry","category-notes"],"_links":{"self":[{"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=\/wp\/v2\/posts\/10361","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10361"}],"version-history":[{"count":33,"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=\/wp\/v2\/posts\/10361\/revisions"}],"predecessor-version":[{"id":10436,"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=\/wp\/v2\/posts\/10361\/revisions\/10436"}],"wp:attachment":[{"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dzrgw.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}