马一丁

Repair the PDF generation process

@@ -4501,418 +4501,91 @@ document.documentElement.classList.add('js-ready'); @@ -4501,418 +4501,91 @@ document.documentElement.classList.add('js-ready');
4501 /* ========== Theme Button Web Component ========== */ 4501 /* ========== Theme Button Web Component ========== */
4502 (() => { 4502 (() => {
4503 const themeButtonFunc = (root, initTheme, changeTheme) => { 4503 const themeButtonFunc = (root, initTheme, changeTheme) => {
4504 - const $ = (s) => {  
4505 - let dom = root.querySelectorAll(s);  
4506 - return dom.length == 1 ? dom[0] : dom;  
4507 - };  
4508 - let mainButton = $(".main-button");  
4509 - let daytimeBackground = $(".daytime-background");  
4510 - let cloud = $(".cloud");  
4511 - let cloudList = $(".cloud-son");  
4512 - let cloudLight = $(".cloud-light");  
4513 - let components = $(".components");  
4514 - let moon = $(".moon");  
4515 - let stars = $(".stars");  
4516 - let star = $(".star");  
4517 - let isMoved = false;  
4518 - let isClicked = false;  
4519 -  
4520 - components.onclick = () => {  
4521 - if (isMoved) {  
4522 - mainButton.style.transform = "translateX(0)";  
4523 - mainButton.style.backgroundColor = "rgba(255, 195, 35,1)";  
4524 - mainButton.style.boxShadow = "3em 3em 5em rgba(0, 0, 0, 0.5), inset -3em -5em 3em -3em rgba(0, 0, 0, 0.5), inset 4em 5em 2em -2em rgba(255, 230, 80,1)";  
4525 - daytimeBackground[0].style.transform = "translateX(0)";  
4526 - daytimeBackground[1].style.transform = "translateX(0)";  
4527 - daytimeBackground[2].style.transform = "translateX(0)";  
4528 - cloud.style.transform = "translateY(10em)";  
4529 - cloudLight.style.transform = "translateY(10em)";  
4530 - components.style.backgroundColor = "rgba(70, 133, 192,1)";  
4531 - moon[0].style.opacity = "0";  
4532 - moon[1].style.opacity = "0";  
4533 - moon[2].style.opacity = "0";  
4534 - stars.style.transform = "translateY(-125em)";  
4535 - stars.style.opacity = "0";  
4536 - changeTheme("light");  
4537 - } else {  
4538 - mainButton.style.transform = "translateX(110em)";  
4539 - mainButton.style.backgroundColor = "rgba(195, 200,210,1)";  
4540 - mainButton.style.boxShadow = "3em 3em 5em rgba(0, 0, 0, 0.5), inset -3em -5em 3em -3em rgba(0, 0, 0, 0.5), inset 4em 5em 2em -2em rgba(255, 255, 210,1)";  
4541 - daytimeBackground[0].style.transform = "translateX(110em)";  
4542 - daytimeBackground[1].style.transform = "translateX(80em)";  
4543 - daytimeBackground[2].style.transform = "translateX(50em)";  
4544 - cloud.style.transform = "translateY(80em)";  
4545 - cloudLight.style.transform = "translateY(80em)";  
4546 - components.style.backgroundColor = "rgba(25,30,50,1)";  
4547 - moon[0].style.opacity = "1";  
4548 - moon[1].style.opacity = "1";  
4549 - moon[2].style.opacity = "1";  
4550 - stars.style.transform = "translateY(-62.5em)";  
4551 - stars.style.opacity = "1";  
4552 - changeTheme("dark");  
4553 - }  
4554 - isClicked = true;  
4555 - setTimeout(function () { isClicked = false; }, 500);  
4556 - isMoved = !isMoved;  
4557 - };  
4558 -  
4559 - mainButton.addEventListener("mousemove", function () {  
4560 - if (isClicked) return;  
4561 - if (isMoved) {  
4562 - mainButton.style.transform = "translateX(100em)";  
4563 - daytimeBackground[0].style.transform = "translateX(100em)";  
4564 - daytimeBackground[1].style.transform = "translateX(73em)";  
4565 - daytimeBackground[2].style.transform = "translateX(46em)";  
4566 - star[0].style.top = "10em"; star[0].style.left = "36em";  
4567 - star[1].style.top = "40em"; star[1].style.left = "87em";  
4568 - star[2].style.top = "26em"; star[2].style.left = "16em";  
4569 - star[3].style.top = "38em"; star[3].style.left = "63em";  
4570 - star[4].style.top = "20.5em"; star[4].style.left = "72em";  
4571 - star[5].style.top = "51.5em"; star[5].style.left = "35em";  
4572 - } else {  
4573 - mainButton.style.transform = "translateX(10em)";  
4574 - daytimeBackground[0].style.transform = "translateX(10em)";  
4575 - daytimeBackground[1].style.transform = "translateX(7em)";  
4576 - daytimeBackground[2].style.transform = "translateX(4em)";  
4577 - cloudList[0].style.right = "-24em"; cloudList[0].style.bottom = "10em";  
4578 - cloudList[1].style.right = "-12em"; cloudList[1].style.bottom = "-27em";  
4579 - cloudList[2].style.right = "17em"; cloudList[2].style.bottom = "-43em";  
4580 - cloudList[3].style.right = "46em"; cloudList[3].style.bottom = "-39em";  
4581 - cloudList[4].style.right = "70em"; cloudList[4].style.bottom = "-65em";  
4582 - cloudList[5].style.right = "109em"; cloudList[5].style.bottom = "-54em";  
4583 - cloudList[6].style.right = "-23em"; cloudList[6].style.bottom = "10em";  
4584 - cloudList[7].style.right = "-11em"; cloudList[7].style.bottom = "-26em";  
4585 - cloudList[8].style.right = "18em"; cloudList[8].style.bottom = "-42em";  
4586 - cloudList[9].style.right = "47em"; cloudList[9].style.bottom = "-38em";  
4587 - cloudList[10].style.right = "74em"; cloudList[10].style.bottom = "-64em";  
4588 - cloudList[11].style.right = "110em"; cloudList[11].style.bottom = "-55em"; 4504 + const checkbox = root.querySelector('.theme-checkbox');
  4505 + // 初始化状态
  4506 + if (initTheme === 'dark') {
  4507 + checkbox.checked = true;
4589 } 4508 }
  4509 + checkbox.addEventListener('change', (e) => {
  4510 + const isDark = e.target.checked;
  4511 + changeTheme(isDark ? 'dark' : 'light');
4590 }); 4512 });
4591 -  
4592 - mainButton.addEventListener("mouseout", function () {  
4593 - if (isClicked) return;  
4594 - if (isMoved) {  
4595 - mainButton.style.transform = "translateX(110em)";  
4596 - daytimeBackground[0].style.transform = "translateX(110em)";  
4597 - daytimeBackground[1].style.transform = "translateX(80em)";  
4598 - daytimeBackground[2].style.transform = "translateX(50em)";  
4599 - star[0].style.top = "11em"; star[0].style.left = "39em";  
4600 - star[1].style.top = "39em"; star[1].style.left = "91em";  
4601 - star[2].style.top = "26em"; star[2].style.left = "19em";  
4602 - star[3].style.top = "37em"; star[3].style.left = "66em";  
4603 - star[4].style.top = "21em"; star[4].style.left = "75em";  
4604 - star[5].style.top = "51em"; star[5].style.left = "38em";  
4605 - } else {  
4606 - mainButton.style.transform = "translateX(0em)";  
4607 - daytimeBackground[0].style.transform = "translateX(0em)";  
4608 - daytimeBackground[1].style.transform = "translateX(0em)";  
4609 - daytimeBackground[2].style.transform = "translateX(0em)";  
4610 - cloudList[0].style.right = "-20em"; cloudList[0].style.bottom = "10em";  
4611 - cloudList[1].style.right = "-10em"; cloudList[1].style.bottom = "-25em";  
4612 - cloudList[2].style.right = "20em"; cloudList[2].style.bottom = "-40em";  
4613 - cloudList[3].style.right = "50em"; cloudList[3].style.bottom = "-35em";  
4614 - cloudList[4].style.right = "75em"; cloudList[4].style.bottom = "-60em";  
4615 - cloudList[5].style.right = "110em"; cloudList[5].style.bottom = "-50em";  
4616 - cloudList[6].style.right = "-20em"; cloudList[6].style.bottom = "10em";  
4617 - cloudList[7].style.right = "-10em"; cloudList[7].style.bottom = "-25em";  
4618 - cloudList[8].style.right = "20em"; cloudList[8].style.bottom = "-40em";  
4619 - cloudList[9].style.right = "50em"; cloudList[9].style.bottom = "-35em";  
4620 - cloudList[10].style.right = "75em"; cloudList[10].style.bottom = "-60em";  
4621 - cloudList[11].style.right = "110em"; cloudList[11].style.bottom = "-50em";  
4622 - }  
4623 - });  
4624 -  
4625 - const getRandomDirection = () => ["2em", "-2em"][Math.floor(Math.random() * 2)];  
4626 - const moveElementRandomly = (element) => {  
4627 - element.style.transform = `translate(${getRandomDirection()}, ${getRandomDirection()})`;  
4628 - };  
4629 - const cloudSons = root.querySelectorAll(".cloud-son");  
4630 - setInterval(() => { cloudSons.forEach(moveElementRandomly); }, 1000);  
4631 -  
4632 - if (initTheme === "dark") {  
4633 - components.onclick();  
4634 - }  
4635 }; 4513 };
4636 4514
4637 class ThemeButton extends HTMLElement { 4515 class ThemeButton extends HTMLElement {
4638 constructor() { super(); } 4516 constructor() { super(); }
4639 connectedCallback() { 4517 connectedCallback() {
4640 const initTheme = this.getAttribute("value") || "light"; 4518 const initTheme = this.getAttribute("value") || "light";
4641 - const size = +this.getAttribute("size") || 3; 4519 + const size = +this.getAttribute("size") || 1.5;
  4520 +
4642 const shadow = this.attachShadow({ mode: "closed" }); 4521 const shadow = this.attachShadow({ mode: "closed" });
4643 const container = document.createElement("div"); 4522 const container = document.createElement("div");
4644 container.setAttribute("class", "container"); 4523 container.setAttribute("class", "container");
4645 - // font-size 控制整个组件的缩放比例  
4646 - // size 参数默认为 3,此时 font-size = 1px,组件实际尺寸为 180px x 70px  
4647 - // size = 1.5 时,font-size = 0.5px,组件缩小到 90px x 35px  
4648 - container.setAttribute("style", `font-size: ${(size / 3).toFixed(2)}px`); 4524 + container.style.fontSize = `${size * 10}px`;
4649 4525
4650 - /**  
4651 - * 日夜切换按钮的 DOM 结构  
4652 - *  
4653 - * 层级关系:  
4654 - * .components (胶囊形主容器)  
4655 - * ├── .main-button (可移动的太阳/月亮圆球)  
4656 - * │ ├── .moon (环形山1 - 右上小)  
4657 - * │ ├── .moon (环形山2 - 左侧大)  
4658 - * │ └── .moon (环形山3 - 右下小)  
4659 - * ├── .daytime-background (光晕层1 - 最亮)  
4660 - * ├── .daytime-background (光晕层2 - 中等)  
4661 - * ├── .daytime-background (光晕层3 - 最淡)  
4662 - * ├── .cloud (主云朵容器)  
4663 - * │ └── .cloud-son x 6 (6个白色圆形组成云朵)  
4664 - * ├── .cloud-light (浅色云朵容器,增加层次感)  
4665 - * │ └── .cloud-son x 6 (6个半透明圆形)  
4666 - * └── .stars (星星容器)  
4667 - * ├── .star.big x 2 (2颗大星星)  
4668 - * │ └── .star-son x 4 (4个角组成四角星)  
4669 - * ├── .star.medium x 2 (2颗中星星)  
4670 - * │ └── .star-son x 4  
4671 - * └── .star.small x 2 (2颗小星星)  
4672 - * └── .star-son x 4  
4673 - */  
4674 container.innerHTML = [ 4526 container.innerHTML = [
4675 - // ========== 主容器开始 ==========  
4676 - '<div class="components">',  
4677 -  
4678 - // ========== 太阳/月亮按钮 ==========  
4679 - // 白天显示为金黄色太阳,夜晚变为灰白色月亮  
4680 - // 通过 JS 控制 translateX 实现左右移动  
4681 - '<div class="main-button">',  
4682 - // 三个月亮环形山(白天时 opacity:0 隐藏,夜晚时显示)  
4683 - '<div class="moon"></div>', // 环形山1:右上角,小尺寸  
4684 - '<div class="moon"></div>', // 环形山2:左侧,大尺寸  
4685 - '<div class="moon"></div>', // 环形山3:右下角,小尺寸  
4686 - '</div>',  
4687 -  
4688 - // ========== 太阳光晕效果 ==========  
4689 - // 三层同心圆,透明度递减,模拟太阳的光晕扩散  
4690 - // 随太阳一起移动(通过 JS 控制 translateX)  
4691 - '<div class="daytime-background"></div>', // 光晕层1:110em,20%不透明度  
4692 - '<div class="daytime-background"></div>', // 光晕层2:135em,10%不透明度  
4693 - '<div class="daytime-background"></div>', // 光晕层3:160em,5%不透明度  
4694 -  
4695 - // ========== 主云朵层 ==========  
4696 - // 白天可见,夜晚通过 translateY(80em) 移出视野  
4697 - '<div class="cloud">',  
4698 - // 6个白色圆形,通过不同位置和大小组合成云朵形状  
4699 - // CSS 使用 nth-child(6n+x) 选择器为每个云朵设置不同位置  
4700 - '<div class="cloud-son"></div>', // 云朵1:right:-20em, bottom:10em, 50x50em  
4701 - '<div class="cloud-son"></div>', // 云朵2:right:-10em, bottom:-25em, 60x60em  
4702 - '<div class="cloud-son"></div>', // 云朵3:right:20em, bottom:-40em, 60x60em  
4703 - '<div class="cloud-son"></div>', // 云朵4:right:50em, bottom:-35em, 60x60em  
4704 - '<div class="cloud-son"></div>', // 云朵5:right:75em, bottom:-60em, 75x75em  
4705 - '<div class="cloud-son"></div>', // 云朵6:right:110em, bottom:-50em, 60x60em  
4706 - '</div>',  
4707 -  
4708 - // ========== 浅色云朵层 ==========  
4709 - // opacity:0.5 的半透明云朵,增加层次感和立体感  
4710 - '<div class="cloud-light">',  
4711 - '<div class="cloud-son"></div>',  
4712 - '<div class="cloud-son"></div>',  
4713 - '<div class="cloud-son"></div>',  
4714 - '<div class="cloud-son"></div>',  
4715 - '<div class="cloud-son"></div>',  
4716 - '<div class="cloud-son"></div>',  
4717 - '</div>',  
4718 -  
4719 - // ========== 星星容器 ==========  
4720 - // 白天通过 translateY(-125em) 隐藏在上方  
4721 - // 夜晚通过 translateY(-62.5em) 移入视野  
4722 - '<div class="stars">',  
4723 -  
4724 - // 大星星 x 2(--size: 7.5em)  
4725 - // 每颗星星由4个 .star-son 组成四角星形状  
4726 - '<div class="star big">', // 星星1:top:11em, left:39em, 动画周期3.5s  
4727 - '<div class="star-son"></div>', // 左上角  
4728 - '<div class="star-son"></div>', // 右上角  
4729 - '<div class="star-son"></div>', // 左下角  
4730 - '<div class="star-son"></div>', // 右下角  
4731 - '</div>',  
4732 - '<div class="star big">', // 星星2:top:39em, left:91em, 动画周期4.1s  
4733 - '<div class="star-son"></div>',  
4734 - '<div class="star-son"></div>',  
4735 - '<div class="star-son"></div>',  
4736 - '<div class="star-son"></div>',  
4737 - '</div>',  
4738 -  
4739 - // 中星星 x 2(--size: 5em)  
4740 - '<div class="star medium">', // 星星3:top:26em, left:19em, 动画周期4.9s  
4741 - '<div class="star-son"></div>',  
4742 - '<div class="star-son"></div>',  
4743 - '<div class="star-son"></div>',  
4744 - '<div class="star-son"></div>',  
4745 - '</div>',  
4746 - '<div class="star medium">', // 星星4:top:37em, left:66em, 动画周期5.3s  
4747 - '<div class="star-son"></div>',  
4748 - '<div class="star-son"></div>',  
4749 - '<div class="star-son"></div>',  
4750 - '<div class="star-son"></div>',  
4751 - '</div>',  
4752 -  
4753 - // 小星星 x 2(--size: 3em)  
4754 - '<div class="star small">', // 星星5:top:21em, left:75em, 动画周期3s  
4755 - '<div class="star-son"></div>',  
4756 - '<div class="star-son"></div>',  
4757 - '<div class="star-son"></div>',  
4758 - '<div class="star-son"></div>',  
4759 - '</div>',  
4760 - '<div class="star small">', // 星星6:top:51em, left:38em, 动画周期2.2s  
4761 - '<div class="star-son"></div>',  
4762 - '<div class="star-son"></div>',  
4763 - '<div class="star-son"></div>',  
4764 - '<div class="star-son"></div>',  
4765 - '</div>',  
4766 -  
4767 - '</div>', // .stars 结束  
4768 -  
4769 - '</div>' // .components 结束 4527 + '<div class="toggle-wrapper">',
  4528 + ' <input type="checkbox" class="theme-checkbox" id="theme-toggle-input">',
  4529 + ' <label for="theme-toggle-input" class="toggle-label">',
  4530 + ' <div class="toggle-background">',
  4531 + ' <div class="stars">',
  4532 + ' <span class="star"></span>',
  4533 + ' <span class="star"></span>',
  4534 + ' <span class="star"></span>',
  4535 + ' <span class="star"></span>',
  4536 + ' </div>',
  4537 + ' <div class="clouds">',
  4538 + ' <span class="cloud"></span>',
  4539 + ' <span class="cloud"></span>',
  4540 + ' </div>',
  4541 + ' </div>',
  4542 + ' <div class="toggle-circle">',
  4543 + ' <div class="moon-crater"></div>',
  4544 + ' <div class="moon-crater"></div>',
  4545 + ' <div class="moon-crater"></div>',
  4546 + ' </div>',
  4547 + ' </label>',
  4548 + '</div>'
4770 ].join(''); 4549 ].join('');
  4550 +
4771 const style = document.createElement("style"); 4551 const style = document.createElement("style");
4772 - /**  
4773 - * 日夜切换按钮组件的完整 CSS 样式  
4774 - *  
4775 - * 组件结构:  
4776 - * - .container: 最外层容器,控制整体尺寸和定位  
4777 - * - .components: 按钮主体(胶囊形状),包含所有内部元素  
4778 - * - .main-button: 可移动的圆形按钮(太阳/月亮)  
4779 - * - .moon: 月亮上的环形山(3个灰色圆形)  
4780 - * - .daytime-background: 太阳光晕效果(3层渐变圆形)  
4781 - * - .cloud / .cloud-light: 白天的云朵容器  
4782 - * - .cloud-son: 单个云朵(白色圆形)  
4783 - * - .stars: 夜晚的星星容器  
4784 - * - .star: 单颗星星(由4个 .star-son 组成四角星形状)  
4785 - */  
4786 style.textContent = [ 4552 style.textContent = [
4787 - // ========== 全局重置 ==========  
4788 - // 清除默认边距,设置统一过渡动画,禁用移动端点击高亮  
4789 - "* { margin: 0; padding: 0; transition: 0.7s; -webkit-tap-highlight-color: rgba(0,0,0,0); }",  
4790 -  
4791 - // ========== 最外层容器 ==========  
4792 - // position: relative - 在文档流中正常显示,作为内部 absolute 元素的定位参考  
4793 - // width/height: 180em x 70em - 按钮整体尺寸(em 单位可通过 font-size 缩放)  
4794 - // display: inline-block - 行内块元素,便于在 header 中排列  
4795 - // vertical-align: bottom - 底部对齐  
4796 - // transform: translate3d(0,0,0) - 开启 GPU 加速,提升动画性能  
4797 - ".container { position: relative; width: 180em; height: 70em; display: inline-block; vertical-align: bottom; transform: translate3d(0, 0, 0); }",  
4798 -  
4799 - // ========== 按钮主体(胶囊形状) ==========  
4800 - // position: absolute - 相对于 .container 绝对定位  
4801 - // background-color: rgba(70,133,192,1) - 白天的蓝色天空背景  
4802 - // border-radius: 100em - 超大圆角形成胶囊形状  
4803 - // box-shadow: inset ... - 内阴影增加立体感  
4804 - // overflow: hidden - 隐藏超出边界的元素(云朵、光晕等)  
4805 - // transition-timing-function: cubic-bezier(0,0.5,1,1) - 自定义缓动曲线  
4806 - // cursor: pointer - 鼠标悬停显示手型  
4807 - ".components { position: absolute; top: 0; left: 0; width: 180em; height: 70em; background-color: rgba(70, 133, 192, 1); border-radius: 100em; box-shadow: inset 0 0 5em 3em rgba(0, 0, 0, 0.5); overflow: hidden; transition: 0.7s; transition-timing-function: cubic-bezier(0, 0.5, 1, 1); cursor: pointer; }",  
4808 -  
4809 - // ========== 可移动的圆形按钮(太阳/月亮) ==========  
4810 - // margin: 7.5em 0 0 7.5em - 初始位置在左侧(白天/太阳状态)  
4811 - // width/height: 55em - 圆形按钮直径  
4812 - // background-color: rgba(255,195,35,1) - 太阳的金黄色  
4813 - // border-radius: 50% - 完美圆形  
4814 - // box-shadow - 三层阴影:外阴影(立体感) + 内阴影(暗部) + 内高光(亮部)  
4815 - // transition: 1.0s - 切换动画时长  
4816 - // cubic-bezier(0.56,1.35,0.52,1.00) - 弹性缓动效果(超过终点后回弹)  
4817 - ".main-button { margin: 7.5em 0 0 7.5em; width: 55em; height: 55em; background-color: rgba(255, 195, 35, 1); border-radius: 50%; box-shadow: 3em 3em 5em rgba(0, 0, 0, 0.5), inset -3em -5em 3em -3em rgba(0, 0, 0, 0.5), inset 4em 5em 2em -2em rgba(255, 230, 80, 1); transition: 1.0s; transition-timing-function: cubic-bezier(0.56, 1.35, 0.52, 1.00); }",  
4818 -  
4819 - // ========== 月亮环形山 ==========  
4820 - // 三个灰色圆形模拟月球表面的环形山  
4821 - // opacity: 0 - 白天时隐藏,切换到夜晚时显示  
4822 - // box-shadow: inset ... - 内阴影增加凹陷效果  
4823 - ".moon { position: absolute; background-color: rgba(150, 160, 180, 1); box-shadow: inset 0em 0em 1em 1em rgba(0, 0, 0, 0.3); border-radius: 50%; transition: 0.5s; opacity: 0; }",  
4824 - // 三个环形山的不同位置和大小  
4825 - ".moon:nth-child(1) { top: 7.5em; left: 25em; width: 12.5em; height: 12.5em; }", // 右上角小环形山  
4826 - ".moon:nth-child(2) { top: 20em; left: 7.5em; width: 20em; height: 20em; }", // 左侧大环形山  
4827 - ".moon:nth-child(3) { top: 32.5em; left: 32.5em; width: 12.5em; height: 12.5em; }", // 右下角小环形山  
4828 -  
4829 - // ========== 太阳光晕效果 ==========  
4830 - // 三层半透明白色圆形,模拟太阳的光晕扩散效果  
4831 - // 随太阳移动,z-index 为负值确保在太阳后面  
4832 - ".daytime-background { position: absolute; border-radius: 50%; transition: 1.0s; transition-timing-function: cubic-bezier(0.56, 1.35, 0.52, 1.00); }",  
4833 - // 第一层光晕:最亮,20%不透明度  
4834 - ".daytime-background:nth-child(2) { top: -20em; left: -20em; width: 110em; height: 110em; background-color: rgba(255, 255, 255, 0.2); z-index: -2; }",  
4835 - // 第二层光晕:中等亮度,10%不透明度  
4836 - ".daytime-background:nth-child(3) { top: -32.5em; left: -17.5em; width: 135em; height: 135em; background-color: rgba(255, 255, 255, 0.1); z-index: -3; }",  
4837 - // 第三层光晕:最淡,5%不透明度  
4838 - ".daytime-background:nth-child(4) { top: -45em; left: -15em; width: 160em; height: 160em; background-color: rgba(255, 255, 255, 0.05); z-index: -4; }",  
4839 -  
4840 - // ========== 云朵容器 ==========  
4841 - // transform: translateY(10em) - 白天时云朵可见位置  
4842 - // 切换到夜晚时 translateY(80em) 将云朵移出视野  
4843 - ".cloud, .cloud-light { transform: translateY(10em); transition: 1.0s; transition-timing-function: cubic-bezier(0.56, 1.35, 0.52, 1.00); }",  
4844 -  
4845 - // ========== 单个云朵 ==========  
4846 - // 白色圆形,通过不同位置组合形成云朵形状  
4847 - // transition: transform 6s - 云朵随机飘动动画较慢(6秒)  
4848 - // right/bottom 1s - 位置变化动画较快(1秒)  
4849 - ".cloud-son { position: absolute; background-color: #fff; border-radius: 50%; z-index: -1; transition: transform 6s, right 1s, bottom 1s; }",  
4850 - // 6个云朵的不同位置和大小(使用 6n+x 选择器循环应用)  
4851 - ".cloud-son:nth-child(6n+1) { right: -20em; bottom: 10em; width: 50em; height: 50em; }",  
4852 - ".cloud-son:nth-child(6n+2) { right: -10em; bottom: -25em; width: 60em; height: 60em; }",  
4853 - ".cloud-son:nth-child(6n+3) { right: 20em; bottom: -40em; width: 60em; height: 60em; }",  
4854 - ".cloud-son:nth-child(6n+4) { right: 50em; bottom: -35em; width: 60em; height: 60em; }",  
4855 - ".cloud-son:nth-child(6n+5) { right: 75em; bottom: -60em; width: 75em; height: 75em; }",  
4856 - ".cloud-son:nth-child(6n+6) { right: 110em; bottom: -50em; width: 60em; height: 60em; }",  
4857 - // 主云朵层  
4858 - ".cloud { z-index: -2; }",  
4859 - // 浅色云朵层(半透明,增加层次感)  
4860 - ".cloud-light { position: absolute; right: 0em; bottom: 25em; opacity: 0.5; z-index: -3; }",  
4861 -  
4862 - // ========== 星星容器 ==========  
4863 - // transform: translateY(-125em) - 白天时星星在视野外上方  
4864 - // 切换到夜晚时 translateY(-62.5em) 将星星移入视野  
4865 - ".stars { transform: translateY(-125em); z-index: -2; transition: 1.0s; transition-timing-function: cubic-bezier(0.56, 1.35, 0.52, 1.00); }",  
4866 -  
4867 - // ========== 星星尺寸变量 ==========  
4868 - // 使用 CSS 变量定义三种星星大小  
4869 - ".big { --size: 7.5em; }", // 大星星  
4870 - ".medium { --size: 5em; }", // 中星星  
4871 - ".small { --size: 3em; }", // 小星星  
4872 -  
4873 - // ========== 单颗星星 ==========  
4874 - // 星星尺寸为 2 * --size(因为由4个角组成)  
4875 - ".star { position: absolute; width: calc(2*var(--size)); height: calc(2*var(--size)); }",  
4876 - // 6颗星星的不同位置和闪烁动画时长(错开闪烁节奏)  
4877 - ".star:nth-child(1) { top: 11em; left: 39em; animation-name: star; animation-duration: 3.5s; }",  
4878 - ".star:nth-child(2) { top: 39em; left: 91em; animation-name: star; animation-duration: 4.1s; }",  
4879 - ".star:nth-child(3) { top: 26em; left: 19em; animation-name: star; animation-duration: 4.9s; }",  
4880 - ".star:nth-child(4) { top: 37em; left: 66em; animation-name: star; animation-duration: 5.3s; }",  
4881 - ".star:nth-child(5) { top: 21em; left: 75em; animation-name: star; animation-duration: 3s; }",  
4882 - ".star:nth-child(6) { top: 51em; left: 38em; animation-name: star; animation-duration: 2.2s; }",  
4883 -  
4884 - // ========== 星星闪烁动画 ==========  
4885 - // 0-20%: 缩小到0(消失)  
4886 - // 20-100%: 恢复原大小(显示)  
4887 - // 配合 animation-direction: alternate 实现来回闪烁  
4888 - "@keyframes star { 0%, 20% { transform: scale(0); } 20%, 100% { transform: scale(1); } }",  
4889 -  
4890 - // ========== 星星角(组成四角星形状) ==========  
4891 - // 每颗星星由4个 .star-son 组成,分别是四个角  
4892 - ".star-son { float: left; }",  
4893 - // 四个角的位置变量(用于 radial-gradient 定位)  
4894 - ".star-son:nth-child(1) { --pos: left 0; }", // 左上角  
4895 - ".star-son:nth-child(2) { --pos: right 0; }", // 右上角  
4896 - ".star-son:nth-child(3) { --pos: 0 bottom; }", // 左下角  
4897 - ".star-son:nth-child(4) { --pos: right bottom; }", // 右下角  
4898 - // 使用 radial-gradient 创建四分之一圆形,组合成四角星  
4899 - // 原理:在角落位置创建透明圆形,圆形外是白色,形成尖角效果  
4900 - ".star-son { width: var(--size); height: var(--size); background-image: radial-gradient(circle var(--size) at var(--pos), transparent var(--size), #fff); }",  
4901 -  
4902 - // ========== 星星动画属性 ==========  
4903 - // animation-iteration-count: infinite - 无限循环  
4904 - // animation-direction: alternate - 正反交替播放  
4905 - // animation-timing-function: linear - 线性匀速  
4906 - ".star { transform: scale(1); transition-timing-function: cubic-bezier(0.56, 1.35, 0.52, 1.00); transition: 1s; animation-iteration-count: infinite; animation-direction: alternate; animation-timing-function: linear; }",  
4907 -  
4908 - // ========== 星星闪烁状态 ==========  
4909 - // 用于 JS 控制的闪烁状态类  
4910 - ".twinkle { transform: scale(0); }"  
4911 - ].join(" ");  
4912 - const changeTheme = (detail) => { 4553 + '* { box-sizing: border-box; margin: 0; padding: 0; }',
  4554 + '.container { display: inline-block; position: relative; width: 5.4em; height: 2.6em; vertical-align: middle; }',
  4555 + '.toggle-wrapper { width: 100%; height: 100%; }',
  4556 + '.theme-checkbox { display: none; }',
  4557 + '.toggle-label { display: block; width: 100%; height: 100%; border-radius: 2.6em; background-color: #87CEEB; cursor: pointer; position: relative; overflow: hidden; transition: background-color 0.5s ease; box-shadow: inset 0 0.1em 0.3em rgba(0,0,0,0.2); }',
  4558 + '.theme-checkbox:checked + .toggle-label { background-color: #1F2937; }',
  4559 + '.toggle-circle { position: absolute; top: 0.2em; left: 0.2em; width: 2.2em; height: 2.2em; border-radius: 50%; background-color: #FFD700; box-shadow: 0 0.1em 0.2em rgba(0,0,0,0.3); transition: transform 0.5s cubic-bezier(0.4, 0.0, 0.2, 1), background-color 0.5s ease; z-index: 2; }',
  4560 + '.theme-checkbox:checked + .toggle-label .toggle-circle { transform: translateX(2.8em); background-color: #F3F4F6; box-shadow: inset -0.2em -0.2em 0.2em rgba(0,0,0,0.1), 0 0.1em 0.2em rgba(255,255,255,0.2); }',
  4561 + '.moon-crater { position: absolute; background-color: rgba(200, 200, 200, 0.6); border-radius: 50%; opacity: 0; transition: opacity 0.3s ease; }',
  4562 + '.theme-checkbox:checked + .toggle-label .toggle-circle .moon-crater { opacity: 1; }',
  4563 + '.moon-crater:nth-child(1) { width: 0.6em; height: 0.6em; top: 0.4em; left: 0.8em; }',
  4564 + '.moon-crater:nth-child(2) { width: 0.4em; height: 0.4em; top: 1.2em; left: 0.4em; }',
  4565 + '.moon-crater:nth-child(3) { width: 0.3em; height: 0.3em; top: 1.4em; left: 1.2em; }',
  4566 + '.toggle-background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }',
  4567 + '.clouds { position: absolute; width: 100%; height: 100%; transition: transform 0.5s ease, opacity 0.5s ease; opacity: 1; }',
  4568 + '.theme-checkbox:checked + .toggle-label .clouds { transform: translateY(100%); opacity: 0; }',
  4569 + '.cloud { position: absolute; background-color: #fff; border-radius: 2em; opacity: 0.9; }',
  4570 + '.cloud::before { content: ""; position: absolute; top: -40%; left: 15%; width: 50%; height: 100%; background-color: inherit; border-radius: 50%; }',
  4571 + '.cloud::after { content: ""; position: absolute; top: -55%; left: 45%; width: 50%; height: 120%; background-color: inherit; border-radius: 50%; }',
  4572 + '.cloud:nth-child(1) { width: 1.4em; height: 0.5em; top: 0.8em; right: 1.0em; }',
  4573 + '.cloud:nth-child(2) { width: 1.0em; height: 0.4em; top: 1.6em; right: 2.0em; opacity: 0.7; }',
  4574 + '.stars { position: absolute; width: 100%; height: 100%; transition: transform 0.5s ease, opacity 0.5s ease; transform: translateY(-100%); opacity: 0; }',
  4575 + '.theme-checkbox:checked + .toggle-label .stars { transform: translateY(0); opacity: 1; }',
  4576 + '.star { position: absolute; background-color: #FFF; border-radius: 50%; width: 0.15em; height: 0.15em; box-shadow: 0 0 0.2em #FFF; animation: twinkle 2s infinite ease-in-out; }',
  4577 + '.star:nth-child(1) { top: 0.6em; left: 1.0em; animation-delay: 0s; }',
  4578 + '.star:nth-child(2) { top: 1.6em; left: 1.8em; width: 0.1em; height: 0.1em; animation-delay: 0.5s; }',
  4579 + '.star:nth-child(3) { top: 0.8em; left: 2.4em; width: 0.12em; height: 0.12em; animation-delay: 1s; }',
  4580 + '.star:nth-child(4) { top: 1.8em; left: 0.8em; width: 0.08em; height: 0.08em; animation-delay: 1.5s; }',
  4581 + '@keyframes twinkle { 0%, 100% { opacity: 0.4; transform: scale(0.8); } 50% { opacity: 1; transform: scale(1.2); } }'
  4582 + ].join(' ');
  4583 +
  4584 + const changeThemeWrapper = (detail) => {
4913 this.dispatchEvent(new CustomEvent("change", { detail })); 4585 this.dispatchEvent(new CustomEvent("change", { detail }));
4914 }; 4586 };
4915 - themeButtonFunc(container, initTheme, changeTheme); 4587 +
  4588 + themeButtonFunc(container, initTheme, changeThemeWrapper);
4916 shadow.appendChild(style); 4589 shadow.appendChild(style);
4917 shadow.appendChild(container); 4590 shadow.appendChild(container);
4918 } 4591 }
@@ -1000,6 +1000,133 @@ body {{ @@ -1000,6 +1000,133 @@ body {{
1000 background: white !important; 1000 background: white !important;
1001 }} 1001 }}
1002 1002
  1003 +/* ========== 修复 WeasyPrint CSS 变量渐变兼容性问题 ========== */
  1004 +/* WeasyPrint 不支持在 linear-gradient 中使用 var(),需要用静态值覆盖 */
  1005 +
  1006 +/* 覆盖按钮渐变 */
  1007 +.action-btn {{
  1008 + background: linear-gradient(135deg, #4a90e2 0%, #17a2b8 100%) !important;
  1009 +}}
  1010 +
  1011 +/* 覆盖进度条渐变 */
  1012 +.export-progress::after {{
  1013 + background: linear-gradient(90deg, #4a90e2, #17a2b8) !important;
  1014 +}}
  1015 +
  1016 +/* 覆盖 PEST 卡片标题渐变 */
  1017 +.pest-card__title {{
  1018 + background: linear-gradient(135deg, #8e44ad, #2980b9) !important;
  1019 + -webkit-background-clip: text !important;
  1020 + -webkit-text-fill-color: transparent !important;
  1021 + background-clip: text !important;
  1022 +}}
  1023 +
  1024 +/* 覆盖 PEST 条带指示器渐变 */
  1025 +.pest-strip__indicator.political {{
  1026 + background: linear-gradient(180deg, #8e44ad, rgba(142,68,173,0.8)) !important;
  1027 +}}
  1028 +.pest-strip__indicator.economic {{
  1029 + background: linear-gradient(180deg, #16a085, rgba(22,160,133,0.8)) !important;
  1030 +}}
  1031 +.pest-strip__indicator.social {{
  1032 + background: linear-gradient(180deg, #e84393, rgba(232,67,147,0.8)) !important;
  1033 +}}
  1034 +.pest-strip__indicator.technological {{
  1035 + background: linear-gradient(180deg, #2980b9, rgba(41,128,185,0.8)) !important;
  1036 +}}
  1037 +
  1038 +/* 覆盖 PEST 条带背景(原来使用 var(--pest-strip-*-bg),包含渐变和变量) */
  1039 +.pest-strip {{
  1040 + background: #ffffff !important;
  1041 +}}
  1042 +.pest-strip.political {{
  1043 + background: linear-gradient(90deg, rgba(142,68,173,0.08), rgba(255,255,255,0.85)), #ffffff !important;
  1044 + border-color: rgba(142,68,173,0.4) !important;
  1045 +}}
  1046 +.pest-strip.economic {{
  1047 + background: linear-gradient(90deg, rgba(22,160,133,0.08), rgba(255,255,255,0.85)), #ffffff !important;
  1048 + border-color: rgba(22,160,133,0.4) !important;
  1049 +}}
  1050 +.pest-strip.social {{
  1051 + background: linear-gradient(90deg, rgba(232,67,147,0.08), rgba(255,255,255,0.85)), #ffffff !important;
  1052 + border-color: rgba(232,67,147,0.4) !important;
  1053 +}}
  1054 +.pest-strip.technological {{
  1055 + background: linear-gradient(90deg, rgba(41,128,185,0.08), rgba(255,255,255,0.85)), #ffffff !important;
  1056 + border-color: rgba(41,128,185,0.4) !important;
  1057 +}}
  1058 +
  1059 +/* 覆盖 SWOT 卡片背景(原来使用 var(--swot-card-bg),包含渐变和变量) */
  1060 +.swot-card {{
  1061 + background: linear-gradient(135deg, rgba(76,132,255,0.04), rgba(28,127,110,0.06)), #ffffff !important;
  1062 +}}
  1063 +
  1064 +/* 覆盖 SWOT 单元格背景(原来使用 var(--swot-cell-*-bg),包含渐变和变量) */
  1065 +.swot-cell {{
  1066 + background: linear-gradient(135deg, rgba(255,255,255,0.9), rgba(255,255,255,0.5)) !important;
  1067 +}}
  1068 +.swot-cell.strength {{
  1069 + background: linear-gradient(135deg, rgba(28,127,110,0.07), rgba(255,255,255,0.78)), #ffffff !important;
  1070 + border-color: rgba(28,127,110,0.35) !important;
  1071 +}}
  1072 +.swot-cell.weakness {{
  1073 + background: linear-gradient(135deg, rgba(192,57,43,0.07), rgba(255,255,255,0.78)), #ffffff !important;
  1074 + border-color: rgba(192,57,43,0.35) !important;
  1075 +}}
  1076 +.swot-cell.opportunity {{
  1077 + background: linear-gradient(135deg, rgba(31,90,179,0.07), rgba(255,255,255,0.78)), #ffffff !important;
  1078 + border-color: rgba(31,90,179,0.35) !important;
  1079 +}}
  1080 +.swot-cell.threat {{
  1081 + background: linear-gradient(135deg, rgba(179,107,22,0.07), rgba(255,255,255,0.78)), #ffffff !important;
  1082 + border-color: rgba(179,107,22,0.35) !important;
  1083 +}}
  1084 +
  1085 +/* 覆盖 SWOT 图例项和药丸(使用静态颜色) */
  1086 +.swot-legend__item.strength, .swot-pill.strength {{
  1087 + background: #1c7f6e !important;
  1088 +}}
  1089 +.swot-legend__item.weakness, .swot-pill.weakness {{
  1090 + background: #c0392b !important;
  1091 +}}
  1092 +.swot-legend__item.opportunity, .swot-pill.opportunity {{
  1093 + background: #1f5ab3 !important;
  1094 +}}
  1095 +.swot-legend__item.threat, .swot-pill.threat {{
  1096 + background: #b36b16 !important;
  1097 +}}
  1098 +
  1099 +/* 覆盖其他使用 var() 的元素 */
  1100 +.swot-item {{
  1101 + background: rgba(255,255,255,0.92) !important;
  1102 +}}
  1103 +.swot-tag {{
  1104 + background: rgba(0,0,0,0.04) !important;
  1105 +}}
  1106 +.swot-empty {{
  1107 + border-color: #e0e0e0 !important;
  1108 +}}
  1109 +
  1110 +/* 覆盖 PEST 卡片背景 */
  1111 +.pest-card {{
  1112 + background: linear-gradient(145deg, rgba(142,68,173,0.03), rgba(22,160,133,0.04)), #ffffff !important;
  1113 +}}
  1114 +
  1115 +/* 覆盖图表卡片错误状态渐变 */
  1116 +.chart-card.chart-card--error {{
  1117 + background: linear-gradient(135deg, rgba(0,0,0,0.015), rgba(0,0,0,0.04)) !important;
  1118 +}}
  1119 +
  1120 +/* 覆盖词云徽章渐变 */
  1121 +.wordcloud-badge {{
  1122 + background: linear-gradient(135deg, rgba(74, 144, 226, 0.14) 0%, rgba(74, 144, 226, 0.24) 100%) !important;
  1123 +}}
  1124 +
  1125 +/* 覆盖英雄区域渐变 */
  1126 +.hero-section {{
  1127 + background: linear-gradient(135deg, rgba(0,123,255,0.1), rgba(23,162,184,0.1)) !important;
  1128 +}}
  1129 +
1003 /* SVG图表容器样式 */ 1130 /* SVG图表容器样式 */
1004 .chart-svg-container {{ 1131 .chart-svg-container {{
1005 width: 100%; 1132 width: 100%;