/* ══════════════════════════════════════════════════════════════════════
   05 流光描边 · 可移植层（零依赖、零图片、零字体）
   ──────────────────────────────────────────────────────────────────
   一句话：9 个【静止】的彩色光斑铺在卡上，一个【旋转的锥形窗口】把光斑
   切成一条 1px 的弧；弧内侧再叠一层同色内发光，外面再叠一层模糊的bloom。

   为什么不是"整圈 conic 在转"：
     转的只有窗口（--beam-angle），色斑一动不动。所以是「光在边框里流」，
     不是「彩虹在绕圈」。整圈转的观感是"卡在变彩色"，不是"光在走"。

   三条硬前提（缺一条就静默失效，不报错）：
     ① @property --beam-angle 必须注册成 <angle> 且 inherits:true —— 没注册
        的话 0deg→360deg 是【离散翻转】，光卡死在原地。
     ② mask-composite 标准值与 -webkit- 值【不同名】：intersect↔source-in、
        exclude↔xor。只写一边，另一边浏览器会把三层遮罩解成实心色块。
     ③ 宿主必须 overflow:hidden + border-radius + isolation:isolate。
        没有 isolate，bloom 的 z-index:3 会跑到卡片外面去。

   使用：
     <div class="beam" data-on data-palette="colorful">…内容…</div>
   纯 CSS 就够了（默认 colorful / dark / 1px / 1.96s）。要状态机、圆角探测、
   离屏暂停、换色再叠 js/beam.js。
   ══════════════════════════════════════════════════════════════════════ */

@property --beam-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: true;            /* ⚠ 必须 true：角度定义在宿主上，伪元素靠继承拿 */
}

@property --beam-op {
  syntax: "<number>";
  initial-value: 0;
  inherits: true;            /* 同上：淡入淡出写在宿主，三层伪元素共享 */
}

/* ── 可调参数（宿主可局部覆盖；改配色只动 --beam-c1…c9） ───────────── */
.beam {
  --beam-radius: 16px;
  --beam-width: 1px;
  --beam-duration: 1.96s;
  --beam-scale: 1;                /* 色斑 px 尺寸的缩放；小控件必须调小 */
  --beam-strength: 1;             /* 0–1 总强度 */
  /* 内发光只贴在边缘这么宽的一条里。原站写死 28px，那是按 122px 高的卡调的；
     控件变矮（40px 的按钮）时 28px 会把整块都算成"边缘"，整张脸被糊亮。
     所以取 min(28px, 23%)：大卡封顶 28px，小控件按比例自己收。 */
  --beam-edge-band: min(28px, 23%);
  --beam-blur: 8px;               /* bloom 的模糊半径；>8 更柔、<8 更锐 */

  /* 色斑颜色，写成 "R G B" 三元组，好让两个层用同一份数据配不同 alpha */
  --beam-c1: 255 50 100;
  --beam-c2: 40 140 255;
  --beam-c3: 50 200 80;
  --beam-c4: 30 185 170;
  --beam-c5: 100 70 255;
  --beam-c6: 40 140 255;
  --beam-c7: 255 120 40;
  --beam-c8: 240 50 180;
  --beam-c9: 180 40 240;
  --beam-inner-alpha: .45;        /* 内发光那层的 alpha（mono 会压到 .225） */

  /* 三层各自的透明度（暗底 md 档的实测值） */
  --beam-stroke: .26;
  --beam-inner: .42;
  --beam-bloom: .24;

  /* 色相漂移：同一位置的颜色也在慢慢走，这是"色散"错觉的另一半 */
  --beam-hue-base: 0deg;
  --beam-hue-range: 30deg;
  --beam-hue-duration: 12s;
  --beam-brightness: 1.3;
  --beam-saturate: 1.2;

  --beam-shade: rgba(255, 255, 255, .27);   /* 内层 inset 白光 */

  /* ── 几何：9 个色斑（所有配色共用同一套位置/尺寸） ──────────────
     · 位置用 %（跟着卡走），尺寸用 px（光的物理大小，不该跟着拉长）
     · 内层 = 同色、尺寸 ×0.9、alpha 换成 --beam-inner-alpha
     ① 70×40 @ 33% -7.4%（贴着上边，红） */
  --beam-b1: radial-gradient(ellipse calc(70px * var(--beam-scale)) calc(40px * var(--beam-scale)) at 33% -7.4%, rgb(var(--beam-c1)), transparent);
  --beam-b2: radial-gradient(ellipse calc(60px * var(--beam-scale)) calc(35px * var(--beam-scale)) at 12% -5%, rgb(var(--beam-c2)), transparent);
  --beam-b3: radial-gradient(ellipse calc(40px * var(--beam-scale)) calc(70px * var(--beam-scale)) at 2.1% 68.3%, rgb(var(--beam-c3)), transparent);
  --beam-b4: radial-gradient(ellipse calc(20px * var(--beam-scale)) calc(35px * var(--beam-scale)) at 2.1% 68.3%, rgb(var(--beam-c4)), transparent);
  --beam-b5: radial-gradient(ellipse calc(180px * var(--beam-scale)) calc(32px * var(--beam-scale)) at 74.4% 100%, rgb(var(--beam-c5)), transparent);
  --beam-b6: radial-gradient(ellipse calc(85px * var(--beam-scale)) calc(26px * var(--beam-scale)) at 55% 100%, rgb(var(--beam-c6)), transparent);
  --beam-b7: radial-gradient(ellipse calc(74px * var(--beam-scale)) calc(32px * var(--beam-scale)) at 93.9% 0%, rgb(var(--beam-c7)), transparent);
  --beam-b8: radial-gradient(ellipse calc(26px * var(--beam-scale)) calc(42px * var(--beam-scale)) at 100% 27.1%, rgb(var(--beam-c8)), transparent);
  --beam-b9: radial-gradient(ellipse calc(52px * var(--beam-scale)) calc(48px * var(--beam-scale)) at 100% 27.1%, rgb(var(--beam-c9)), transparent);

  /* 内层：尺寸 ×0.9（63/36、54/32、36/63、18/32、162/29、77/23、67/29、23/38、47/43） */
  --beam-g1: radial-gradient(ellipse calc(63px * var(--beam-scale)) calc(36px * var(--beam-scale)) at 33% -7.4%, rgb(var(--beam-c1) / var(--beam-inner-alpha)), transparent);
  --beam-g2: radial-gradient(ellipse calc(54px * var(--beam-scale)) calc(32px * var(--beam-scale)) at 12% -5%, rgb(var(--beam-c2) / var(--beam-inner-alpha)), transparent);
  --beam-g3: radial-gradient(ellipse calc(36px * var(--beam-scale)) calc(63px * var(--beam-scale)) at 2.1% 68.3%, rgb(var(--beam-c3) / var(--beam-inner-alpha)), transparent);
  --beam-g4: radial-gradient(ellipse calc(18px * var(--beam-scale)) calc(32px * var(--beam-scale)) at 2.1% 68.3%, rgb(var(--beam-c4) / var(--beam-inner-alpha)), transparent);
  --beam-g5: radial-gradient(ellipse calc(162px * var(--beam-scale)) calc(29px * var(--beam-scale)) at 74.4% 100%, rgb(var(--beam-c5) / var(--beam-inner-alpha)), transparent);
  --beam-g6: radial-gradient(ellipse calc(77px * var(--beam-scale)) calc(23px * var(--beam-scale)) at 55% 100%, rgb(var(--beam-c6) / var(--beam-inner-alpha)), transparent);
  --beam-g7: radial-gradient(ellipse calc(67px * var(--beam-scale)) calc(29px * var(--beam-scale)) at 93.9% 0%, rgb(var(--beam-c7) / var(--beam-inner-alpha)), transparent);
  --beam-g8: radial-gradient(ellipse calc(23px * var(--beam-scale)) calc(38px * var(--beam-scale)) at 100% 27.1%, rgb(var(--beam-c8) / var(--beam-inner-alpha)), transparent);
  --beam-g9: radial-gradient(ellipse calc(47px * var(--beam-scale)) calc(43px * var(--beam-scale)) at 100% 27.1%, rgb(var(--beam-c9) / var(--beam-inner-alpha)), transparent);

  --beam-blobs: var(--beam-b1), var(--beam-b2), var(--beam-b3), var(--beam-b4), var(--beam-b5),
                var(--beam-b6), var(--beam-b7), var(--beam-b8), var(--beam-b9);
  --beam-blobs-inner: var(--beam-g1), var(--beam-g2), var(--beam-g3), var(--beam-g4), var(--beam-g5),
                      var(--beam-g6), var(--beam-g7), var(--beam-g8), var(--beam-g9);

  /* ── 锥形窗口：亮的那条弧（0–54% 全透明，66% 最亮，78% 之后又透明） ── */
  --beam-window: conic-gradient(from var(--beam-angle),
      transparent 0%, transparent 30%,
      rgba(255, 255, 255, .1) 36%, rgba(255, 255, 255, .35) 44%,
      #fff 52%, #fff 80%,
      rgba(255, 255, 255, .35) 86%, rgba(255, 255, 255, .1) 92%,
      transparent 95%, transparent 100%);

  /* ── 火花：叠在色斑之上的一层白色斜光，让弧里有明暗而不是一块纯色 ── */
  --beam-spike: conic-gradient(from var(--beam-angle),
      transparent 0%, transparent 54%,
      rgba(255, 255, 255, .1) 57%, rgba(255, 255, 255, .3) 60%,
      rgba(255, 255, 255, .6) 63%, rgba(255, 255, 255, .75) 66%,
      rgba(255, 255, 255, .6) 69%, rgba(255, 255, 255, .3) 72%,
      rgba(255, 255, 255, .1) 75%, transparent 78%, transparent 100%);

  --beam-bloom-spike: conic-gradient(from var(--beam-angle),
      transparent 0%, transparent 58%,
      rgba(255, 255, 255, .03) 62%, rgba(255, 255, 255, .08) 65%,
      rgba(255, 255, 255, .2) 67%, rgba(255, 255, 255, .45) 69%,
      rgba(255, 255, 255, .85) 70%, rgba(255, 255, 255, .85) 70.5%,
      rgba(255, 255, 255, .45) 71.5%, rgba(255, 255, 255, .2) 73%,
      rgba(255, 255, 255, .08) 75%, rgba(255, 255, 255, .03) 78%,
      transparent 82%);

  position: relative;
  border-radius: var(--beam-radius);
  overflow: hidden;               /* 断崖：光完全裁在卡内，不外溢 */
  isolation: isolate;             /* 没有它 bloom 会跑到卡外 */

  /* 动画用【长写】而不是 animation 简写：
     状态从 on 切到 off 时只换 fade 那一条的 name，spin 那条名字不变，
     于是 --beam-angle 继续走、不会跳回 12 点。用简写会整组重算（原站就是
     这样，所以它亮灭一次光会闪回到起点）。 */
  animation-name: beam-spin, beam-fade-in;
  animation-duration: var(--beam-duration), .6s;
  animation-timing-function: linear, ease;
  animation-iteration-count: infinite, 1;
  animation-fill-mode: none, forwards;
  animation-play-state: paused, paused;    /* 灭态一律不跑；fade 停在 0 帧 = 不亮 */
}

/* ── 状态 ────────────────────────────────────────────────────────── */
.beam[data-on] { animation-play-state: running, running; }

.beam[data-off] {
  animation-name: beam-spin, beam-fade-out;
  animation-duration: var(--beam-duration), .5s;   /* 原站：淡入 0.6s / 淡出 0.5s，不是同一个数 */
  animation-play-state: running, running;
}

/* 放在最后：离屏暂停要盖过 [data-on] / [data-off] 的 running。
   伪元素上的色相漂移是【独立动画】，不会被宿主的 play-state 带走，得单独列。 */
.beam[data-paused],
.beam[data-paused]::after,
.beam[data-paused]::before { animation-play-state: paused !important; }

/* ── 第 1 层 · 描边：色斑 × 火花，被「锥形窗口 ∩ 1px 环」裁成一条弧 ── */
.beam[data-on]::after,
.beam[data-off]::after {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;      /* 环宽 = padding，靠 border-box 才不吃掉 2px */
  border-radius: calc(var(--beam-radius) - var(--beam-width));
  padding: var(--beam-width);
  clip-path: inset(0 round var(--beam-radius));
  background: var(--beam-spike), var(--beam-blobs);
  -webkit-mask: var(--beam-window),
                linear-gradient(#fff 0 0) content-box,
                linear-gradient(#fff 0 0);
  -webkit-mask-composite: source-in, xor;
  mask: var(--beam-window),
        linear-gradient(#fff 0 0) content-box,
        linear-gradient(#fff 0 0);
  mask-composite: intersect, exclude;
  opacity: calc(var(--beam-op) * var(--beam-stroke) * var(--beam-strength));
  pointer-events: none;
  z-index: 2;
  animation: beam-hue var(--beam-hue-duration) ease-in-out infinite;
}

/* ── 第 2 层 · 内发光：同色斑 0.45α + 贴边白光，中间 28px 带被掐掉 ── */
.beam[data-on]::before,
.beam[data-off]::before {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  border-radius: var(--beam-radius);
  background: var(--beam-blobs-inner);
  box-shadow: inset 0 0 9px 1px var(--beam-shade);
  -webkit-mask-image: var(--beam-window),
                      linear-gradient(#fff, transparent var(--beam-edge-band),
                        transparent calc(100% - var(--beam-edge-band)), #fff),
                      linear-gradient(to right, #fff, transparent var(--beam-edge-band),
                        transparent calc(100% - var(--beam-edge-band)), #fff);
  -webkit-mask-composite: source-in, source-over;
  mask-image: var(--beam-window),
              linear-gradient(#fff, transparent var(--beam-edge-band),
                transparent calc(100% - var(--beam-edge-band)), #fff),
              linear-gradient(to right, #fff, transparent var(--beam-edge-band),
                transparent calc(100% - var(--beam-edge-band)), #fff);
  mask-composite: intersect, add;
  opacity: calc(var(--beam-op) * var(--beam-inner) * var(--beam-strength));
  pointer-events: none;
  z-index: 1;
  clip-path: inset(0 round var(--beam-radius));
  animation: beam-hue var(--beam-hue-duration) ease-in-out infinite;
}

/* ── 第 3 层 · bloom：更窄更亮的窗口，环遮罩 + 模糊，负责"溢出到卡面上的光" ── */
.beam-bloom {
  display: none;
  position: absolute;
  inset: 0;
  box-sizing: border-box;      /* 环宽 = padding，靠 border-box 才不吃掉 2px */
  border-radius: calc(var(--beam-radius) - var(--beam-width));
  padding: var(--beam-width);
  clip-path: inset(0 round var(--beam-radius));
  background: var(--beam-bloom-spike);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  filter: blur(var(--beam-blur)) brightness(var(--beam-brightness)) saturate(var(--beam-saturate));
  pointer-events: none;
  z-index: 3;
  opacity: 0;
}

.beam[data-on] > .beam-bloom,
.beam[data-off] > .beam-bloom {
  display: block;
  opacity: calc(var(--beam-op) * var(--beam-bloom) * var(--beam-strength));
}

/* ── 尺寸档（原站的 md / sm 不是同一组数） ─────────────────────────
   小控件不只是"色斑要缩小"：面积一小，同样的 0.26 描边会糊成一片雾，
   内发光 .42 会把整块糊亮。原站 sm 档换的是另一组数：
     描边 .26→.46（线要更硬）· 内发光 .42→.24（少内渗）· bloom .24→.38（光晕要更明显）
   一条 data-size="sm" 就同时把色斑缩到 .5。也可以只拿透明度、自己给 scale。 */
.beam[data-size="sm"] {
  --beam-stroke: .46;
  --beam-inner: .24;
  --beam-bloom: .38;
  --beam-scale: .5;
}

/* ── 配色（只换颜色，几何不动；要加自己的只写这 9 行） ───────────── */
.beam[data-palette="mono"] {
  --beam-c1: 180 180 180; --beam-c2: 140 140 140; --beam-c3: 160 160 160;
  --beam-c4: 130 130 130; --beam-c5: 170 170 170; --beam-c6: 150 150 150;
  --beam-c7: 190 190 190; --beam-c8: 145 145 145; --beam-c9: 165 165 165;
  --beam-inner-alpha: .225;
}

.beam[data-palette="ocean"] {
  --beam-c1: 100 80 220; --beam-c2: 60 120 255; --beam-c3: 80 100 200;
  --beam-c4: 50 140 220; --beam-c5: 120 80 255; --beam-c6: 70 130 255;
  --beam-c7: 140 100 240; --beam-c8: 90 110 230; --beam-c9: 130 70 255;
}

.beam[data-palette="sunset"] {
  --beam-c1: 255 80 50; --beam-c2: 255 160 40; --beam-c3: 255 120 60;
  --beam-c4: 255 200 50; --beam-c5: 255 100 80; --beam-c6: 255 180 60;
  --beam-c7: 255 60 60; --beam-c8: 255 140 50; --beam-c9: 255 90 70;
}

.beam[data-palette="forest"] {
  --beam-c1: 46 160 90; --beam-c2: 30 190 120; --beam-c3: 70 180 70;
  --beam-c4: 20 150 130; --beam-c5: 90 200 80; --beam-c6: 40 170 110;
  --beam-c7: 120 210 70; --beam-c8: 35 145 100; --beam-c9: 60 195 140;
}

/* 我们自己两条线：seekme 的紫 / Orée 的沙。这两套是照着品牌色配的，
   落到具体界面还要按底色再校一次 —— 别把这里当结论。 */
.beam[data-palette="violet"] {
  --beam-c1: 255 130 90; --beam-c2: 199 150 255; --beam-c3: 150 110 255;
  --beam-c4: 120 90 240; --beam-c5: 210 120 255; --beam-c6: 170 130 255;
  --beam-c7: 230 100 220; --beam-c8: 255 140 200; --beam-c9: 180 90 255;
}

.beam[data-palette="sand"] {
  --beam-c1: 230 180 140; --beam-c2: 198 154 126; --beam-c3: 180 130 100;
  --beam-c4: 160 140 120; --beam-c5: 220 170 130; --beam-c6: 190 150 120;
  --beam-c7: 240 200 160; --beam-c8: 200 140 110; --beam-c9: 170 120 95;
}

/* ── 浅底预设：不是"调个色"，是一整组数（透明度/白光/饱和全变） ───── */
.beam[data-theme="light"] {
  --beam-stroke: .12;
  --beam-inner: .26;
  --beam-bloom: .34;
  --beam-shade: rgba(0, 0, 0, .14);
  --beam-saturate: 1.5;
  --beam-spike: conic-gradient(from var(--beam-angle),
      transparent 0%, transparent 54%,
      rgba(0, 0, 0, .08) 57%, rgba(0, 0, 0, .2) 60%,
      rgba(0, 0, 0, .4) 63%, rgba(0, 0, 0, .55) 66%,
      rgba(0, 0, 0, .4) 69%, rgba(0, 0, 0, .2) 72%,
      rgba(0, 0, 0, .08) 75%, transparent 78%, transparent 100%);
  --beam-bloom-spike: conic-gradient(from var(--beam-angle),
      transparent 0%, transparent 58%,
      rgba(0, 0, 0, .02) 62%, rgba(0, 0, 0, .08) 65%,
      rgba(0, 0, 0, .2) 67%, rgba(0, 0, 0, .4) 69%,
      rgba(0, 0, 0, .6) 70%, rgba(0, 0, 0, .6) 70.5%,
      rgba(0, 0, 0, .4) 71.5%, rgba(0, 0, 0, .2) 73%,
      rgba(0, 0, 0, .08) 75%, rgba(0, 0, 0, .02) 78%,
      transparent 82%);
}

/* 小控件 + 浅底：原站这一格又是另一组数（描边 .12 / 内发光 .3 / bloom .16 / 饱和 1.8） */
.beam[data-size="sm"][data-theme="light"] {
  --beam-stroke: .12;
  --beam-inner: .3;
  --beam-bloom: .16;
  --beam-saturate: 1.8;
}

/* 静态配色：只关掉色相漂移，旋转与淡入淡出照旧 */
.beam[data-static]::after,
.beam[data-static]::before { animation: none; }

/* ── 关键帧 ──────────────────────────────────────────────────────── */
@keyframes beam-spin { to { --beam-angle: 360deg; } }
@keyframes beam-fade-in { to { --beam-op: 1; } }
@keyframes beam-fade-out { from { --beam-op: 1; } to { --beam-op: 0; } }

@keyframes beam-hue {
  0%, 100% {
    filter: hue-rotate(calc(var(--beam-hue-base) - var(--beam-hue-range)))
            brightness(var(--beam-brightness)) saturate(var(--beam-saturate));
  }
  50% {
    filter: hue-rotate(calc(var(--beam-hue-base) + var(--beam-hue-range)))
            brightness(var(--beam-brightness)) saturate(var(--beam-saturate));
  }
}

/* ── 兜底 ────────────────────────────────────────────────────────── */
/* 遮罩合成不支持时宁可【什么都不画】，也不要画出一整块彩色 —— 
   那是这类效果最常见的线上事故（三层遮罩被解成实心）。 */
@supports not (mask-composite: exclude) and not (-webkit-mask-composite: xor) {
  .beam[data-on]::after, .beam[data-on]::before, .beam[data-on] > .beam-bloom,
  .beam[data-off]::after, .beam[data-off]::before, .beam[data-off] > .beam-bloom {
    content: none;
    display: none;
  }
}

/* 减少动态效果：不是关掉，是【停在一个固定角度】——光还在，但不动。
   产品里若要彻底静音，传 active:false（比"留一条静止的彩边"更保守）。 */
@media (prefers-reduced-motion: reduce) {
  .beam[data-on], .beam[data-off] { animation: none; }
  .beam[data-on] { --beam-angle: 210deg; --beam-op: 1; }
  .beam[data-off] { --beam-angle: 210deg; --beam-op: 0; }
  .beam[data-on]::after, .beam[data-on]::before { animation: none; }
}
