754 lines
19 KiB
CSS
754 lines
19 KiB
CSS
/*
|
||
* 排版系数(必须与 @classhelper/shared 的 ISLAND_TYPE_SCALE 保持一致):
|
||
* title 1.08 / body 0.95 / meta 0.78 / badge 0.76 / pillTitle 0.92 / pillSub 0.74
|
||
*
|
||
* 关键:所有文本尺寸都由 --island-font 通过 calc() 推导,所以「字号」设置一改,
|
||
* 岛内文字立即整体等比缩放(WinIsland 的 font_size 模型),不存在写死的字号。
|
||
*/
|
||
html,
|
||
body,
|
||
#app {
|
||
margin: 0;
|
||
padding: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: transparent;
|
||
overflow: hidden;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
body {
|
||
font-family:
|
||
-apple-system, 'Segoe UI Variable Display', 'Segoe UI', 'Microsoft YaHei', 'PingFang SC',
|
||
'Helvetica Neue', sans-serif;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.island-root {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
background: transparent;
|
||
}
|
||
|
||
/* ---------------------------------------------------------------- 卡片与形状 */
|
||
|
||
.island-root.embedded .island-card {
|
||
left: 0 !important;
|
||
top: 0 !important;
|
||
right: auto !important;
|
||
bottom: auto !important;
|
||
transform: none !important;
|
||
}
|
||
|
||
.island-card {
|
||
position: absolute;
|
||
display: block;
|
||
padding: 0;
|
||
margin: 0;
|
||
border: none;
|
||
background: none;
|
||
color: rgba(255, 255, 255, 0.92);
|
||
font-size: var(--island-font, 13px);
|
||
text-align: left;
|
||
cursor: pointer;
|
||
/* 配色 token(默认:WinIsland 纯黑风格) */
|
||
--wn-bg: #000000;
|
||
--wn-border: rgba(255, 255, 255, 0.118);
|
||
--wn-text-1: rgba(255, 255, 255, 0.92);
|
||
--wn-text-2: rgba(255, 255, 255, 0.72);
|
||
--wn-text-3: rgba(255, 255, 255, 0.58);
|
||
--wn-surface: rgba(255, 255, 255, 0.1);
|
||
--wn-surface-hover: rgba(255, 255, 255, 0.18);
|
||
--wn-divider: rgba(255, 255, 255, 0.09);
|
||
}
|
||
|
||
.island-card[data-style='glass'] {
|
||
/* WinIsland「glass 无 host backdrop」降级色:比纯黑透一点,但保证任何桌面下都不是白底 */
|
||
--wn-bg: rgba(32, 32, 36, 0.804);
|
||
--wn-border: rgba(255, 255, 255, 0.157);
|
||
--wn-surface: rgba(255, 255, 255, 0.14);
|
||
--wn-surface-hover: rgba(255, 255, 255, 0.22);
|
||
}
|
||
|
||
.island-card[data-style='tinted'] {
|
||
--wn-bg: #0b0b0f;
|
||
--wn-border: rgba(255, 255, 255, 0.14);
|
||
}
|
||
|
||
.island-card.hidden-placeholder {
|
||
visibility: hidden;
|
||
}
|
||
.island-card.ci-lesson-card .shape path {
|
||
fill: transparent;
|
||
stroke: none;
|
||
}
|
||
.island-card .ci-fixed-lesson {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
min-width: 0;
|
||
}
|
||
|
||
/* 连续圆角形状:填充 + 1px 描边(描边画在裁切之外,与 WinIsland 一致) */
|
||
.island-card .shape {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
display: block;
|
||
}
|
||
|
||
.island-card .shape path {
|
||
fill: var(--wn-bg);
|
||
stroke: var(--wn-border);
|
||
stroke-width: 1;
|
||
/*
|
||
投影**始终声明**,形态切换只改参数 —— 不要写成"只在 .expanded 上挂 filter"。
|
||
给元素加 / 去 CSS filter 会让 Chromium 新建或销毁它的渲染表面(effect node),
|
||
而首帧的合成可能发生在新表面栅格化完成之前,那一帧会被当作空内容画出去;
|
||
卡片的底色恰恰就画在这个被过滤的元素上(fill 在本元素),于是**开/合的那一瞬间
|
||
底座会闪掉一帧、只剩未过滤的文字层**(用户反馈的"开合时一瞬间的闪动")。
|
||
胶囊态用 0 0 0:硬轮廓投影正好压在路径底下,肉眼等同无投影,与 WinIsland
|
||
"只有展开态有投影"的观感一致。
|
||
*/
|
||
filter: drop-shadow(0 var(--card-shadow-y, 0px) var(--card-shadow-blur, 0px) rgba(0, 0, 0, 0.11));
|
||
}
|
||
|
||
/* 内容层裁切到同一形状内;内部两层(胶囊层 / 展开层)交叉淡入 */
|
||
.island-card .content {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: block;
|
||
clip-path: var(--card-path);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.island-card .layer {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 只有"当前形态"的那一层响应鼠标,避免透明层的按钮被误点 */
|
||
.island-card.pill .pill-layer,
|
||
.island-card.expanded .expanded-layer {
|
||
pointer-events: auto;
|
||
}
|
||
|
||
/* 展开态投影(WinIsland: rgba(0,0,0,.11)、y+2、σ=3 → CSS 0 2px 3px)。
|
||
只改参数、不动 filter 声明本身,理由见上面的 .shape path。 */
|
||
.island-card.expanded .shape path {
|
||
--card-shadow-y: 2px;
|
||
--card-shadow-blur: 3px;
|
||
}
|
||
|
||
/* 状态色:只做"内层微染 + 描边",不外溢(保持桌面干净,也不会有光晕硬边) */
|
||
.island-card.urgent .shape path,
|
||
.island-card.call .shape path {
|
||
stroke: color-mix(in srgb, var(--state-color) 62%, rgba(255, 255, 255, 0.2));
|
||
}
|
||
|
||
.island-card .tint {
|
||
position: absolute;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
}
|
||
|
||
.island-card.urgent .tint {
|
||
opacity: 1;
|
||
background: radial-gradient(120% 90% at 50% 0%, rgba(255, 69, 58, 0.22), transparent 68%);
|
||
}
|
||
|
||
.island-card.call .tint {
|
||
opacity: 1;
|
||
background: radial-gradient(120% 90% at 50% 0%, rgba(255, 159, 10, 0.2), transparent 68%);
|
||
}
|
||
|
||
.island-card[data-style='tinted'] .tint {
|
||
opacity: 1;
|
||
background: linear-gradient(
|
||
135deg,
|
||
color-mix(in srgb, var(--island-accent) 30%, transparent),
|
||
transparent 62%
|
||
);
|
||
}
|
||
|
||
/* ---------------------------------------------------------------- 胶囊(compact) */
|
||
|
||
.pill-layer {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
/* 水平对齐交给 .pill-inner(它固定为胶囊几何,且按停靠方式贴边/居中) */
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
/**
|
||
* 胶囊内容盒:**固定为胶囊自己的宽高与内边距**,不随卡片形变重排。
|
||
*
|
||
* 为什么必须固定:卡片在开合时 268 ⇄ 424 变宽变窄,而中心停靠下卡片的左右边都会动。
|
||
* 内容若跟着卡片宽度走,就会出现"文字先按宽卡片铺开、再随卡片收窄被省略号收回"
|
||
* (用户反馈的"新消息那行字往右跳一下再缩回"),底部也会被收缩的形状裁掉一块。
|
||
* 固定成胶囊几何后:文字在整段动画里位置与省略号都不变,只是随卡片一起淡出/淡入。
|
||
*
|
||
* 贴哪条边与卡片停靠方式一致(左停靠贴左、右停靠贴右、居中则居中对齐)——
|
||
* 这样卡片变宽时内容也不会横移,静止态外观与之前完全一致。
|
||
*/
|
||
.pill-inner {
|
||
display: inline-flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
flex: 0 0 auto;
|
||
gap: calc(var(--island-font, 13px) * 0.62);
|
||
width: var(--island-w, 268px);
|
||
height: 100%;
|
||
padding: 0 calc(var(--island-font, 13px) * 0.78);
|
||
}
|
||
|
||
.island-card[data-anchor='center'] .pill-layer {
|
||
justify-content: center;
|
||
}
|
||
|
||
.island-card[data-anchor='right'] .pill-layer {
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
/**
|
||
* 收回动画(`reason === 'closing'`):胶囊收回过程中**不显示任何胶囊内容**。
|
||
*
|
||
* 这时状态已经在同一帧清空(没有可展示的消息),若照常渲染胶囊层,卡片刚收回就会闪出
|
||
* 一句"新消息 · 点击查看" —— 语义正好相反。这里保留 DOM(宽度固定为 `--island-w`,
|
||
* 内容盒不会重排,符合"开合时胶囊内容不许重排"的约定)只把内容隐藏,
|
||
* 卡片形状照样沿既有弹簧收回,随后由主进程淡出窗口。
|
||
*/
|
||
.island-card.closing .pill-inner {
|
||
opacity: 0;
|
||
}
|
||
|
||
.pill-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 0 0 auto;
|
||
width: calc(var(--island-font, 13px) * 1.24);
|
||
height: calc(var(--island-font, 13px) * 1.24);
|
||
border-radius: 50%;
|
||
background: var(--wn-surface);
|
||
color: var(--wn-text-1);
|
||
}
|
||
|
||
.pill-icon svg {
|
||
width: calc(var(--island-font, 13px) * 0.86);
|
||
height: calc(var(--island-font, 13px) * 0.86);
|
||
}
|
||
|
||
.pill-icon.call {
|
||
color: #ff9f0a;
|
||
}
|
||
|
||
.pill-icon.urgent {
|
||
color: #ff453a;
|
||
}
|
||
|
||
.pill-icon.homework {
|
||
color: var(--island-accent);
|
||
}
|
||
|
||
.pill-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
min-width: 0;
|
||
flex: 1 1 auto;
|
||
gap: 1px;
|
||
}
|
||
|
||
.pill-title {
|
||
font-size: calc(var(--island-font, 13px) * 0.92);
|
||
font-weight: 600;
|
||
line-height: 1.15;
|
||
color: var(--wn-text-1);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.pill-sub {
|
||
font-size: calc(var(--island-font, 13px) * 0.74);
|
||
line-height: 1.15;
|
||
color: var(--wn-text-3);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* 多条消息时把类型做成胶囊小标签(叫人/作业/通知),收起状态也能一眼看出内容构成 */
|
||
.pill-types {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: calc(var(--island-font, 13px) * 0.2);
|
||
flex: 0 0 auto;
|
||
padding-right: calc(var(--island-font, 13px) * 0.2);
|
||
}
|
||
|
||
.pill-type {
|
||
font-size: calc(var(--island-font, 13px) * 0.6);
|
||
line-height: 1.4;
|
||
padding: 0 calc(var(--island-font, 13px) * 0.36);
|
||
border-radius: 999px;
|
||
background: rgba(255, 255, 255, 0.12);
|
||
color: var(--wn-text-2);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.pill-chevron {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
color: rgba(255, 255, 255, 0.34);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.pill-chevron svg {
|
||
width: calc(var(--island-font, 13px) * 0.86);
|
||
height: calc(var(--island-font, 13px) * 0.86);
|
||
}
|
||
|
||
/* ---------------------------------------------------------------- 展开卡(expanded) */
|
||
|
||
.expanded-layer {
|
||
/* 关键:展开层必须纵向排列。此前把 flex-direction 从基类挪到分层时漏了这一条,
|
||
导致展开卡内容横排(标题/元信息/按钮散落,实机可见) */
|
||
flex-direction: column;
|
||
padding: calc(var(--island-font, 13px) * 1.4) calc(var(--island-font, 13px) * 1.6);
|
||
gap: calc(var(--island-font, 13px) * 0.7);
|
||
justify-content: center;
|
||
}
|
||
|
||
/*
|
||
* 多条通知的列表形态。
|
||
*
|
||
* 这里的每个尺寸都必须与 @classhelper/shared 的 `ISLAND_LIST_METRICS` 一一对应:
|
||
* 主进程按那份度量算出**窗口包围盒**(列表比普通展开卡高,窗口不够高会把底部按钮裁掉),
|
||
* 渲染进程按同一份度量排布。改这里就必须改那里,否则会出现"最后一行被切掉"。
|
||
* 选择器一律写成 `.expanded-layer.list-mode ...`(比基类的单类选择器更具体),
|
||
* 免得被后面定义的 `.title` / `.body` 覆盖掉尺寸——那样高度就对不上算出来的值了。
|
||
*/
|
||
.expanded-layer.list-mode {
|
||
/* 高度已经算准,改 flex-start:居中排版一旦有像素级误差会把上下两端同时切掉 */
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.expanded-layer.list-mode .head {
|
||
height: calc(var(--island-font, 13px) * 1.7);
|
||
}
|
||
|
||
.expanded-layer.list-mode .title {
|
||
flex: 0 0 auto;
|
||
display: block;
|
||
height: calc(var(--island-font, 13px) * 1.4);
|
||
line-height: 1.4;
|
||
-webkit-line-clamp: unset;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.expanded-layer.list-mode .body {
|
||
flex: 1 1 auto;
|
||
min-height: 0;
|
||
gap: calc(var(--island-font, 13px) * 0.4);
|
||
justify-content: flex-start;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.head-icon.list {
|
||
background: color-mix(in srgb, var(--island-accent) 20%, transparent);
|
||
color: var(--island-accent);
|
||
}
|
||
|
||
.list-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: calc(var(--island-font, 13px) * 0.55);
|
||
flex: 0 0 auto;
|
||
width: 100%;
|
||
height: calc(var(--island-font, 13px) * 2.7);
|
||
padding: 0 calc(var(--island-font, 13px) * 0.6);
|
||
border: none;
|
||
border-radius: calc(var(--island-font, 13px) * 0.5);
|
||
background: rgba(255, 255, 255, 0.045);
|
||
color: var(--wn-text-1);
|
||
text-align: left;
|
||
cursor: pointer;
|
||
transition: background var(--ch-dur-fast) var(--ch-ease-out);
|
||
}
|
||
|
||
.row-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 0 0 auto;
|
||
width: calc(var(--island-font, 13px) * 1.3);
|
||
height: calc(var(--island-font, 13px) * 1.3);
|
||
border-radius: calc(var(--island-font, 13px) * 0.36);
|
||
background: var(--wn-surface);
|
||
color: var(--wn-text-2);
|
||
}
|
||
|
||
.row-icon svg {
|
||
width: calc(var(--island-font, 13px) * 0.86);
|
||
height: calc(var(--island-font, 13px) * 0.86);
|
||
}
|
||
|
||
.row-icon.call {
|
||
color: #ff9f0a;
|
||
}
|
||
|
||
.row-icon.homework {
|
||
color: var(--island-accent);
|
||
}
|
||
|
||
.row-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
gap: 1px;
|
||
min-width: 0;
|
||
flex: 1 1 auto;
|
||
}
|
||
|
||
.row-title {
|
||
font-size: calc(var(--island-font, 13px) * 0.9);
|
||
font-weight: 600;
|
||
line-height: 1.2;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.row-sub {
|
||
font-size: calc(var(--island-font, 13px) * 0.68);
|
||
line-height: 1.1;
|
||
color: var(--wn-text-3);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.row-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
flex: 0 0 auto;
|
||
height: calc(var(--island-font, 13px) * 1.25);
|
||
padding: 0 calc(var(--island-font, 13px) * 0.5);
|
||
border-radius: 999px;
|
||
font-size: calc(var(--island-font, 13px) * 0.68);
|
||
font-weight: 600;
|
||
background: rgba(255, 255, 255, 0.12);
|
||
color: rgba(255, 255, 255, 0.78);
|
||
}
|
||
|
||
/* 列表底部的提示行:能展开时是按钮,屏幕到任务栏了就是一句"去应用里看" */
|
||
.list-hint {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 0 0 auto;
|
||
height: calc(var(--island-font, 13px) * 2.1);
|
||
}
|
||
|
||
.more-btn {
|
||
border: none;
|
||
background: var(--wn-surface);
|
||
color: var(--wn-text-1);
|
||
height: 100%;
|
||
width: 100%;
|
||
border-radius: calc(var(--island-font, 13px) * 0.5);
|
||
font-size: calc(var(--island-font, 13px) * 0.76);
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: background var(--ch-dur-fast) var(--ch-ease-out);
|
||
}
|
||
|
||
.more-app {
|
||
font-size: calc(var(--island-font, 13px) * 0.76);
|
||
color: var(--wn-text-3);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: calc(var(--island-font, 13px) * 0.7);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.head-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: calc(var(--island-font, 13px) * 1.62);
|
||
height: calc(var(--island-font, 13px) * 1.62);
|
||
border-radius: calc(var(--island-font, 13px) * 0.5);
|
||
background: var(--wn-surface);
|
||
color: var(--wn-text-1);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.head-icon svg {
|
||
width: calc(var(--island-font, 13px) * 1.05);
|
||
height: calc(var(--island-font, 13px) * 1.05);
|
||
}
|
||
|
||
.head-icon.urgent {
|
||
background: rgba(255, 69, 58, 0.2);
|
||
color: #ff453a;
|
||
}
|
||
|
||
.head-icon.call {
|
||
background: rgba(255, 159, 10, 0.2);
|
||
color: #ff9f0a;
|
||
}
|
||
|
||
.head-icon.homework {
|
||
background: color-mix(in srgb, var(--island-accent) 22%, transparent);
|
||
color: var(--island-accent);
|
||
}
|
||
|
||
.head-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: calc(var(--island-font, 13px) * 0.55);
|
||
min-width: 0;
|
||
flex: 1 1 auto;
|
||
}
|
||
|
||
.badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: calc(var(--island-font, 13px) * 1.5);
|
||
padding: 0 calc(var(--island-font, 13px) * 0.62);
|
||
border-radius: 999px;
|
||
font-size: calc(var(--island-font, 13px) * 0.76);
|
||
font-weight: 600;
|
||
letter-spacing: 0.02em;
|
||
background: color-mix(in srgb, var(--island-accent) 26%, transparent);
|
||
color: color-mix(in srgb, var(--island-accent) 70%, #ffffff);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.badge-urgent {
|
||
background: rgba(255, 69, 58, 0.24);
|
||
color: #ff6961;
|
||
}
|
||
|
||
.badge-high {
|
||
background: rgba(255, 159, 10, 0.22);
|
||
color: #ffb340;
|
||
}
|
||
|
||
.badge-low,
|
||
.badge-normal {
|
||
background: rgba(255, 255, 255, 0.12);
|
||
color: rgba(255, 255, 255, 0.78);
|
||
}
|
||
|
||
.badge-call {
|
||
background: rgba(255, 159, 10, 0.24);
|
||
color: #ffb340;
|
||
}
|
||
|
||
.badge-homework {
|
||
background: color-mix(in srgb, var(--island-accent) 26%, transparent);
|
||
color: color-mix(in srgb, var(--island-accent) 72%, #ffffff);
|
||
}
|
||
|
||
.live-dot {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: calc(var(--island-font, 13px) * 0.32);
|
||
font-size: calc(var(--island-font, 13px) * 0.76);
|
||
color: #ff6961;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.live-dot.call {
|
||
color: #ffb340;
|
||
}
|
||
|
||
.live-dot.muted {
|
||
color: var(--wn-text-3);
|
||
}
|
||
|
||
.head-sub {
|
||
font-size: calc(var(--island-font, 13px) * 0.78);
|
||
color: var(--wn-text-3);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.icon-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: calc(var(--island-font, 13px) * 1.7);
|
||
height: calc(var(--island-font, 13px) * 1.7);
|
||
border: none;
|
||
border-radius: 50%;
|
||
background: var(--wn-surface);
|
||
color: rgba(255, 255, 255, 0.72);
|
||
cursor: pointer;
|
||
flex: 0 0 auto;
|
||
transition:
|
||
background var(--ch-dur-fast) var(--ch-ease-out),
|
||
color var(--ch-dur-fast) var(--ch-ease-out);
|
||
}
|
||
|
||
.icon-btn svg {
|
||
width: calc(var(--island-font, 13px) * 0.8);
|
||
height: calc(var(--island-font, 13px) * 0.8);
|
||
}
|
||
|
||
.title {
|
||
margin: 0;
|
||
font-size: calc(var(--island-font, 13px) * 1.08);
|
||
font-weight: 700;
|
||
line-height: 1.3;
|
||
color: #fff;
|
||
flex: 0 0 auto;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.body {
|
||
flex: 0 1 auto;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: calc(var(--island-font, 13px) * 0.35);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.content-text {
|
||
margin: 0;
|
||
font-size: calc(var(--island-font, 13px) * 0.95);
|
||
line-height: 1.42;
|
||
color: var(--wn-text-2);
|
||
word-break: break-word;
|
||
}
|
||
|
||
.call-hint {
|
||
margin: 0;
|
||
font-size: calc(var(--island-font, 13px) * 0.85);
|
||
line-height: 1.4;
|
||
color: color-mix(in srgb, var(--state-color) 66%, #ffffff);
|
||
word-break: break-word;
|
||
}
|
||
|
||
.foot {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: calc(var(--island-font, 13px) * 0.7);
|
||
flex: 0 0 auto;
|
||
margin-top: calc(var(--island-font, 13px) * 0.5);
|
||
padding-top: calc(var(--island-font, 13px) * 0.7);
|
||
border-top: 1px solid var(--wn-divider);
|
||
}
|
||
|
||
.more {
|
||
font-size: calc(var(--island-font, 13px) * 0.78);
|
||
color: var(--wn-text-2);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.more.muted {
|
||
color: var(--wn-text-3);
|
||
}
|
||
|
||
.actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: calc(var(--island-font, 13px) * 0.5);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.ghost-btn,
|
||
.solid-btn {
|
||
height: calc(var(--island-font, 13px) * 2.05);
|
||
padding: 0 calc(var(--island-font, 13px) * 0.9);
|
||
border: none;
|
||
border-radius: 999px;
|
||
font-size: calc(var(--island-font, 13px) * 0.76);
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition:
|
||
background var(--ch-dur-fast) var(--ch-ease-out),
|
||
transform var(--ch-dur-instant) var(--ch-ease-out);
|
||
}
|
||
|
||
.ghost-btn {
|
||
background: var(--wn-surface);
|
||
color: var(--wn-text-1);
|
||
}
|
||
|
||
.solid-btn {
|
||
background: #ffffff;
|
||
color: #0b0b0f;
|
||
}
|
||
|
||
.island-card.call .solid-btn {
|
||
background: #ff9f0a;
|
||
color: #1a1205;
|
||
}
|
||
|
||
.island-card.urgent .solid-btn {
|
||
background: #ff453a;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.ghost-btn:active,
|
||
.solid-btn:active {
|
||
transform: scale(0.97);
|
||
}
|
||
|
||
/* --------------------------------------------------------------- 悬停微交互
|
||
*
|
||
* **必须关在 `@media (hover: hover) and (pointer: fine)` 里**:教室机器上的希沃触摸屏
|
||
* 点一下会产生"幽灵 hover"并**一直粘着**,直到点别处才消失 —— 不关的话,点过「知道了」
|
||
* 的按钮会永远保持高亮(同 AGENTS.md §5 第 30 条那类问题)。
|
||
* 这是 beUI `useHoverCapable` 的 CSS 版:纯样式效果用媒体查询就够,不必挂 composable。
|
||
*/
|
||
@media (hover: hover) and (pointer: fine) {
|
||
.list-row:hover {
|
||
background: var(--wn-surface);
|
||
}
|
||
|
||
.more-btn:hover,
|
||
.ghost-btn:hover {
|
||
background: var(--wn-surface-hover);
|
||
}
|
||
|
||
.icon-btn:hover {
|
||
background: var(--wn-surface-hover);
|
||
color: #ffffff;
|
||
}
|
||
}
|
||
|
||
/* 同一个通知组件用于经典岛绝对层与自定义岛自然测量层。 */
|
||
.classic-notifications {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-shrink: 0;
|
||
}
|