Files
TripLog/assets/style.css
T
laoyang a43dd06d1f 修版心双重内缩与预览图溢出:宽屏整页错位、头像盖住表单
线上反馈「界面更乱了、全都错位、导航条头像非常大、下拉菜单乱七八糟」。
用无头浏览器实测出三处硬伤,都不是样式文件坏了,是布局算式写错。

一、版心被推两次 → 宽屏正文列塌陷(「全都错位」的根)

  .topbar 与 .container 各自用了同一份「把内容推到居中」的 padding,
  而 .container 本来就已经有 max-width + margin:auto。于是内容被推两次:

    1280px  顶栏品牌 x=89   正文 x=178     差 89px
    1920px  顶栏品牌 x=409  正文 x=818     差 409px,正文列只剩 262px
    2560px  正文列宽度 = 0                内容完全挤没

  改法:抽一个 --shell-pad(= max(--gutter, (100% - --container) / 2)),
  顶栏与正文共用它,并且 .container 不再设 max-width —— 正文列宽度由 padding
  反推,宽屏下正好等于 --container,两边用的是同一个公式,左边缘必然对齐。
  用 100% 而非 100vw,避免滚动条让两者差半格。

二、预览容器把图片尺寸写在了外层 div 上 → 400×400 头像盖住整个表单

  .avatar-preview / .cover-preview 把 width/height/object-fit 写在**容器**上,
  里面的 <img> 完全不受约束,按原始尺寸铺出来:
  头像 400×400、封面 1920×1080,直接把下面的表单项盖住。
  (对照:.card-cover img / .activity-cover img 是写对的。)

  改法:容器只负责「框」(定尺寸、overflow:hidden 裁圆角),
  尺寸与 object-fit 一律落到 > img 上,且用绝对定位铺满 ——
  不用 `display:grid + width:100%`,那种写法列宽会反过来依赖元素自身宽度,
  形成循环,浏览器只能把图算成 0 宽(实测踩到过)。

三、上传区被当成小圆框 → 按钮和提示文字压进头像里

  .avatar-upload 被套上 84×84 圆形尺寸,而模板把预览、按钮、提示文字都放在
  它内部,三样东西全挤在那个小圆里互相重叠。改法:上传容器只做排列
  (头像横排、封面竖排),虚线圆框与圆角归预览块,按钮自成一行。

顺带
  · 下拉面板加 max-height + overflow,13 个菜单项在矮屏不再顶出屏幕底部;
    宽度 max-content 且不换行,并限制不超过视口。
  · 头像地址一律先过 media_avatar() 再判断:外站地址(https://…)会被拒,
    以前按原始值判断非空 → 渲染出 <img src="">,用户管理列表里两个用户
    就是破图。现在退回首字母色块。头像隐藏域仍保留原始值,避免单纯保存就抹掉数据。
  · CSS 结构体检报告不再写在被检查文件旁边(assets/style.css.syntax.txt
    曾被当成站点文件打进部署包);打包排除规则改为「根目录 _ 开头 +
    任意层级的工具报告/日志」,并且不再误伤 templates/ 下 _ 前缀的局部模板。

配套的检查能力(本次之前的检查全绿、页面却视觉上是坏的,所以补这一层)
  · _tooling/_snapshot3.py   按登录态渲染线上页面 + 抓静态资源到本地
  · _tooling/_layout_check.py  无头浏览器测量真实几何并断言:顶栏/正文左右边缘
    对齐、正文列宽度、无横向溢出、头像恒 26px、预览图不溢出且铺满、预览图
    确实加载成功、下拉面板不出屏。6 个页面 × 7 档宽度 = 392 项。
    先用线上那份坏样式跑证明它抓得到(89 项失败),再用修复后的跑(0 失败)。
  · _tooling/css_syntax_check.py  词法级 CSS 结构体检(跳过注释与字符串后数括号),
    比 grep 数大括号可靠 —— 配平不等于合法。
  · 部署脚本新增 7 条静态哨兵,锁住上面三个根因。

验证
  本地:php -l 55 文件 0 失败;模板渲染 234 项;SQL 15 表无未知列;PDO 0 问题;
        CSS 202 类全有定义;CSS 结构体检通过;Mime 27 项;内联 JS 9 个文件;
        布局几何 392 项全通过。
  线上:部署 10 步 EXIT=0(80 项静态断言全 OK / 0 FAIL,含 7 条新哨兵),
        双 PHP 渲染 14 条路由字节数完全一致,26 项内容断言全通过
        (含照片代理 69/69 字节逐字节一致);
        对已部署状态重抓渲染再测布局几何 392 项 0 失败;
        端到端 239 项通过 / 0 项失败。
        用户管理列表里 example.com 外链出现次数由 2 降为 0。
2026-09-23 00:01:05 +08:00

1020 lines
46 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================================
家庭出行记录 · 样式表
----------------------------------------------------------------------------
组织方式:设计令牌 → 基础 → 布局 → 组件 → 页面 → 响应式
约定:
· 颜色/间距/圆角一律走 CSS 变量,改主题只动 :root
· 不写 !important;靠顺序与具体度控制
· 组件类名与模板一一对应,改名前先搜模板
========================================================================== */
/* ── 1. 设计令牌 ─────────────────────────────────────────────────────────── */
:root {
--bg: #f5f6f8;
--bg-soft: #eceef2;
--surface: #ffffff;
--surface-2: #fafbfc;
--border: #e3e6ec;
--border-strong: #cfd5df;
--text: #1c2029;
--text-soft: #5b6371;
--text-mute: #8b93a1;
--accent: #3d6bf5;
--accent-dark: #2f56cf;
--accent-soft: #eaf0ff;
--accent-ring: rgba(61, 107, 245, .18);
--success: #12855a;
--success-soft: #e4f6ee;
--warn: #b7791f;
--warn-soft: #fdf3e0;
--danger: #d63b3f;
--danger-soft: #fdecec;
--radius-sm: 8px;
--radius: 12px;
--radius-lg: 16px;
--shadow-xs: 0 1px 2px rgba(22, 28, 45, .06);
--shadow-sm: 0 2px 8px rgba(22, 28, 45, .07);
--shadow-md: 0 8px 24px rgba(22, 28, 45, .10);
--shadow-lg: 0 18px 48px rgba(22, 28, 45, .16);
/* ── 版心 ─────────────────────────────────────────────────────────────
顶栏与正文必须共用同一套「左右留白」,否则宽屏下两者左边缘会错开。 */
--container: 1080px; /* 正文列的目标宽度 */
--gutter: clamp(14px, 3.2vw, 24px); /* 窄屏时内容与视口边缘的最小留白 */
--topbar-h: 60px;
/* 版心左右留白:视口比 --container 宽时,把它推到「让正文列正好等于
--container 且居中」的位置;视口不够宽时退化为 --gutter。
⚠️ 顶栏与 .container 只共用这一个值,两边都不许再叠加
`max-width + margin auto` —— 那等于把内容推两次。曾经就是这么错的:
1920px 下正文列只剩 240px,2560px 下直接塌成 0,整页错位。
⚠️ 这里用 100% 而不是 100vw:100vw 含滚动条宽度,会让顶栏比正文
偏出半个滚动条。100% 相对各自包含块,两边算出来才严格相等。 */
--shell-pad: max(var(--gutter), calc((100% - var(--container)) / 2));
}
* { box-sizing: border-box; }
/* 图片一律不得宽过所在容器 —— 这是兜底,不是主要手段。
主因见下面 .avatar-preview / .cover-preview 的注释:尺寸要写在 img 上。
(这里只约束宽度,高度仍由各自的规则决定;单靠这条救不了「400×400 的方图
塞进 84px 圆框」那种高度溢出。) */
img { max-width: 100%; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "Segoe UI", Roboto, sans-serif;
font-size: 15px;
line-height: 1.62;
color: var(--text);
background: var(--bg);
-webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-dark); text-decoration: underline; }
h1, h2, h3, h4 { margin: 0 0 .4em; line-height: 1.3; font-weight: 650; letter-spacing: -.01em; }
h1 { font-size: 22px; }
h2 { font-size: 17px; }
h3 { font-size: 15px; }
p { margin: 0 0 .8em; }
hr { border: 0; border-top: 1px solid var(--border); margin: 20px 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
/* 工具类 */
.muted { color: var(--text-mute); font-size: 13px; }
.danger { color: var(--danger); }
.meta { color: var(--text-mute); font-size: 12.5px; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.section-title {
font-size: 15px; font-weight: 650; margin: 28px 0 12px;
display: flex; align-items: center; gap: 8px;
}
.section-title::before {
content: ''; width: 3px; height: 15px; border-radius: 2px; background: var(--accent);
}
/* ── 2. 顶栏 ─────────────────────────────────────────────────────────────── */
.topbar {
position: sticky; top: 0; z-index: 40;
display: flex; align-items: center; justify-content: space-between;
gap: 12px;
min-height: var(--topbar-h);
padding: 8px var(--shell-pad); /* 与 .container 同一个版心留白 */
background: rgba(255, 255, 255, .88);
backdrop-filter: saturate(180%) blur(12px);
-webkit-backdrop-filter: saturate(180%) blur(12px);
border-bottom: 1px solid var(--border);
}
.brand {
display: inline-flex; align-items: center; gap: 8px;
min-width: 0; /* 允许品牌文字省略,别把顶栏撑破 */
font-weight: 680; font-size: 16px; color: var(--text); letter-spacing: -.01em;
}
.brand:hover { text-decoration: none; color: var(--text); }
.brand-mark { font-size: 18px; line-height: 1; }
.brand-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 右侧一整组(新建 + 菜单)整体不许被压缩:窄屏宁可省略名字,也别把菜单挤没 */
.topbar-right { display: flex; align-items: center; gap: 10px; flex: none; min-width: 0; }
/* ── 3. 右上角下拉菜单 ───────────────────────────────────────────────────── */
.menu { position: relative; flex: none; }
.menu-trigger {
list-style: none;
display: inline-flex; align-items: center; gap: 8px;
padding: 5px 10px 5px 5px;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--surface);
cursor: pointer;
user-select: none;
transition: border-color .15s, box-shadow .15s, background .15s;
}
.menu-trigger::-webkit-details-marker { display: none; }
.menu-trigger:hover { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.menu[open] > .menu-trigger {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-ring);
background: var(--surface);
}
.menu-name {
font-size: 14px; font-weight: 550;
max-width: 7em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.menu-caret { font-size: 10px; color: var(--text-mute); transition: transform .18s; }
.menu[open] .menu-caret { transform: rotate(180deg); }
.menu-panel {
position: absolute; right: 0; top: calc(100% + 8px);
/* 宽:按最长菜单项撑开(不换行),但窄屏下不许宽过视口 */
width: max-content;
min-width: 224px;
max-width: min(320px, calc(100vw - var(--gutter) * 2));
/* 高:13 个菜单项接起来有 500 多 px,笔记本(768 高)会顶出屏幕底部。
给上限 + 滚动,菜单项再多也不会「乱七八糟」。 */
max-height: calc(100vh - var(--topbar-h) - 24px);
overflow-y: auto;
overscroll-behavior: contain;
padding: 6px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow-md);
animation: menu-in .14s ease-out;
z-index: 50;
}
@keyframes menu-in {
from { opacity: 0; transform: translateY(-6px); }
to { opacity: 1; transform: translateY(0); }
}
.menu-head { padding: 8px 10px 10px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.menu-head-name { font-weight: 620; font-size: 14px; }
.menu-head-role { font-size: 12px; color: var(--text-mute); }
.menu-item {
display: flex; align-items: center; gap: 10px;
padding: 8px 10px;
border-radius: var(--radius-sm);
color: var(--text); font-size: 14px; text-decoration: none;
white-space: nowrap; /* 菜单项不折行,靠面板宽度自适应 */
transition: background .12s;
}
.menu-item:hover { background: var(--bg-soft); text-decoration: none; color: var(--text); }
.menu-icon { width: 18px; text-align: center; font-size: 15px; opacity: .9; }
.menu-sep {
font-size: 11px; color: var(--text-mute);
padding: 10px 10px 4px; letter-spacing: .06em;
}
.menu-item-danger { color: var(--danger); }
.menu-item-danger:hover { background: var(--danger-soft); color: var(--danger); }
/* ── 4. 容器与页头 ───────────────────────────────────────────────────────── */
.container {
/* 这里**故意不写 max-width**:正文列宽度由 --shell-pad 反推 ——
视口够宽时 padding 会把它挤到正好 var(--container) 宽且居中;
这与 .topbar 用的是同一个公式,所以两者左边缘必然对齐。
曾经这里把 max-width 也设成了 --container,再配 `margin: 0 auto` 和同一份
padding:等于把内容推两次。1920px 下正文列只剩 240px、2560px 下塌成 0,
是本次「整页错位」的直接原因。改这里前请先想清楚这一点。 */
margin: 0 auto;
padding: 24px var(--shell-pad) 64px;
}
.container-guest {
max-width: 420px;
display: flex; align-items: center; justify-content: center;
min-height: 100vh; padding: 24px 16px;
}
.page-header {
display: flex; align-items: flex-start; justify-content: space-between;
gap: 16px; flex-wrap: wrap;
margin-bottom: 20px;
}
.page-header h1 { margin-bottom: 3px; }
.page-header .muted { margin: 0; }
.page-header > div:first-child { min-width: 0; }
.footer {
text-align: center; color: var(--text-mute); font-size: 12.5px;
padding: 20px 16px 36px;
}
/* ── 5. 按钮 ─────────────────────────────────────────────────────────────── */
.btn, .btn-primary, .btn-danger, .btn-sm, .btn-primary-sm {
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
padding: 8px 15px;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--text);
font-size: 14px; font-family: inherit; font-weight: 550; line-height: 1.4;
cursor: pointer; text-decoration: none; white-space: nowrap;
transition: background .15s, border-color .15s, box-shadow .15s, transform .06s;
}
.btn:hover, .btn-sm:hover {
background: var(--surface-2); border-color: var(--border-strong);
text-decoration: none; color: var(--text);
}
.btn:active, .btn-primary:active, .btn-danger:active { transform: translateY(1px); }
.btn-primary, .btn-primary-sm {
background: var(--accent); border-color: var(--accent); color: #fff;
box-shadow: var(--shadow-xs);
}
.btn-primary:hover, .btn-primary-sm:hover {
background: var(--accent-dark); border-color: var(--accent-dark);
color: #fff; text-decoration: none;
}
.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { background: #bd3135; border-color: #bd3135; color: #fff; text-decoration: none; }
.btn-sm, .btn-primary-sm { padding: 5px 11px; font-size: 13px; }
.topbar-new { flex: none; }
/* ── 6. 提示 / 空态 / 标签 ───────────────────────────────────────────────── */
.alert {
display: flex; align-items: flex-start; gap: 8px;
padding: 11px 14px; margin-bottom: 18px;
background: var(--accent-soft);
border: 1px solid #cddbff;
border-left: 3px solid var(--accent);
border-radius: var(--radius-sm);
color: #1f3d8f; font-size: 14px;
}
.empty {
text-align: center; color: var(--text-mute);
padding: 40px 20px; font-size: 14px;
background: var(--surface);
border: 1px dashed var(--border-strong);
border-radius: var(--radius);
}
.empty p { margin: 0; }
.tag-default, .tag-self, .tag-temp, .status-tag, .mode-tag, .veh-tag, .role-tag, .node-type {
display: inline-flex; align-items: center; gap: 4px;
padding: 2px 8px; border-radius: 999px;
font-size: 12px; font-weight: 550; line-height: 1.7; white-space: nowrap;
}
.tag-default { background: var(--bg-soft); color: var(--text-soft); }
.tag-self { background: var(--success-soft); color: var(--success); }
.tag-temp { background: var(--warn-soft); color: var(--warn); }
.node-type { background: var(--accent-soft); color: var(--accent-dark); }
.status-planned { background: var(--bg-soft); color: var(--text-soft); }
.status-ongoing { background: var(--accent-soft); color: var(--accent-dark); }
.status-completed { background: var(--success-soft); color: var(--success); }
.status-cancelled { background: var(--danger-soft); color: var(--danger); }
/* 账号状态(用户列表用文字 + 颜色,不是胶囊标签) */
.status-active { color: var(--success); font-size: 13px; font-weight: 550; }
.status-inactive { color: var(--text-mute); font-size: 13px; }
.mode-tag { background: var(--bg-soft); color: var(--text-soft); }
.mode-drive_own, .mode-drive_rental { background: #e9f2ff; color: #1e5bb8; }
.mode-train { background: #eaf1ff; color: #2f56cf; }
.mode-plane { background: #e8f6fb; color: #17708f; }
.mode-ship { background: #e6f7f4; color: #106b60; }
.mode-walk, .mode-bike { background: var(--success-soft); color: var(--success); }
.mode-subway, .mode-bus, .mode-taxi { background: var(--warn-soft); color: var(--warn); }
.veh-own { background: var(--bg-soft); color: var(--text-soft); }
.veh-rental { background: var(--warn-soft); color: var(--warn); }
.role-admin { background: #f0e9ff; color: #6b3fc4; }
.role-user { background: var(--bg-soft); color: var(--text-soft); }
.money-over { color: var(--danger); }
.money-under { color: var(--success); }
/* ── 7. 卡片 ─────────────────────────────────────────────────────────────── */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
gap: 16px;
}
.card {
display: flex; flex-direction: column;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: hidden;
transition: transform .16s, box-shadow .16s, border-color .16s;
}
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.card-cover { position: relative; aspect-ratio: 16 / 9; background: var(--bg-soft); overflow: hidden; }
.card-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-cover-placeholder, .cover-placeholder {
display: flex; align-items: center; justify-content: center;
height: 100%; min-height: 96px;
background: linear-gradient(135deg, #eef2fb, #e6ebf7);
color: #9aa6bd; font-size: 30px;
}
.card-body { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
.card-body h3 { margin: 0; font-size: 15.5px; }
.card-body h3 a { color: var(--text); }
.card-body h3 a:hover { color: var(--accent); text-decoration: none; }
.activity-cover { position: relative; border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 20px; }
.activity-cover img { width: 100%; max-height: 320px; object-fit: cover; display: block; }
.activity-cover .cover-placeholder { min-height: 150px; }
/* ── 8. 时间轴与节点卡片 ─────────────────────────────────────────────────── */
.timeline-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
.timeline-col > h2 { margin-bottom: 12px; }
.node-card {
background: var(--surface);
border: 1px solid var(--border);
border-left: 3px solid var(--border-strong);
border-radius: var(--radius);
padding: 13px 15px;
margin-bottom: 12px;
transition: box-shadow .15s, border-color .15s;
}
.node-card:hover { box-shadow: var(--shadow-sm); }
.node-plan { border-left-color: #9db4f0; }
.node-reality { border-left-color: var(--success); }
.node-cancelled { opacity: .62; }
.node-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.node-title { font-weight: 620; font-size: 15px; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.node-icon { font-size: 15px; }
.node-time { color: var(--text-mute); font-size: 12.5px; margin-top: 2px; }
.node-loc {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
font-size: 13px; color: var(--text-soft); margin-top: 6px;
}
.loc-start, .loc-end { display: inline-flex; align-items: center; gap: 4px; }
.loc-arrow { color: var(--text-mute); }
.node-transport { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 7px; }
.node-cancel-reason { font-size: 12.5px; color: var(--danger); margin-top: 6px; }
.node-actions {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
margin-top: 10px; padding-top: 9px; border-top: 1px dashed var(--border);
}
.node-action-link, .node-action-strong {
font-size: 12.5px; color: var(--accent); padding: 3px 7px; border-radius: 6px;
}
.node-action-link:hover, .node-action-strong:hover { background: var(--accent-soft); text-decoration: none; }
.node-action-strong { font-weight: 600; }
.node-action-note { font-size: 12.5px; color: var(--text-mute); }
.node-action-btn, .node-action-form button {
font-size: 12.5px; padding: 3px 9px; border-radius: 6px;
border: 1px solid var(--border); background: var(--surface); color: var(--text-soft);
cursor: pointer; font-family: inherit;
}
.node-action-btn:hover, .node-action-form button:hover { border-color: var(--border-strong); color: var(--text); }
.node-action-form { display: inline; }
/* ── 9. 表单 ─────────────────────────────────────────────────────────────── */
.form { max-width: 720px; }
.form-plain { max-width: none; }
.form-row { margin-bottom: 15px; }
.form-row > label {
display: block; margin-bottom: 5px;
font-size: 13px; font-weight: 600; color: var(--text-soft);
}
.form-row .muted { margin-top: 4px; }
input[type="text"], input[type="password"], input[type="number"], input[type="datetime-local"],
input[type="date"], input[type="email"], input[type="tel"], input[type="url"], input[type="search"],
select, textarea {
width: 100%;
padding: 9px 11px;
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--text);
font-size: 14px; font-family: inherit; line-height: 1.5;
transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus, textarea:focus {
outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring);
}
input:disabled, select:disabled, textarea:disabled { background: var(--bg-soft); color: var(--text-mute); }
input[type="file"] { font-size: 13px; padding: 6px 0; border: 0; background: none; width: auto; }
textarea { resize: vertical; min-height: 84px; }
select { cursor: pointer; }
.form-actions {
display: flex; align-items: center; gap: 10px;
margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border);
}
.fieldset {
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 15px 16px 4px;
margin: 0 0 16px;
background: var(--surface-2);
}
.fieldset > legend {
padding: 0 7px; font-size: 13px; font-weight: 620; color: var(--text-soft);
}
.inline-panel {
padding: 14px 16px; margin: 12px 0;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.panel {
padding: 18px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 18px;
}
.radio-group { display: flex; flex-wrap: wrap; gap: 8px; }
.radio-label {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 11px; border: 1px solid var(--border-strong); border-radius: 999px;
font-size: 13px; cursor: pointer; background: var(--surface);
}
.radio-label:hover { border-color: var(--accent); }
.radio-label input { margin: 0; }
.check-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.checkbox-label {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 11px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
font-size: 13px; cursor: pointer; background: var(--surface); max-width: 100%;
}
.checkbox-label:hover { border-color: var(--accent); background: var(--accent-soft); }
.checkbox-label input { margin: 0; }
.checkbox-label span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 高德地址联想下拉 */
.amap-dropdown {
position: absolute; left: 0; right: 0; top: calc(100% + 4px);
max-height: 260px; overflow-y: auto;
background: var(--surface);
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-md);
z-index: 30;
}
.amap-dropdown-item { padding: 9px 12px; cursor: pointer; border-bottom: 1px solid var(--border); }
.amap-dropdown-item:last-child { border-bottom: 0; }
.amap-dropdown-item:hover, .amap-dropdown-item.active { background: var(--accent-soft); }
.amap-dropdown-name { font-size: 13.5px; }
.amap-dropdown-sub { font-size: 12px; color: var(--text-mute); }
/* emoji 选择 */
.emoji-picker { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.emoji-btn {
width: 34px; height: 34px; font-size: 17px; line-height: 1;
display: inline-flex; align-items: center; justify-content: center;
border: 1px solid var(--border); border-radius: var(--radius-sm);
background: var(--surface); cursor: pointer; padding: 0;
}
.emoji-btn:hover { border-color: var(--accent); background: var(--accent-soft); }
/* 表格 */
.data-table { width: 100%; border-collapse: collapse; font-size: 14px; background: var(--surface); }
.data-table th, .data-table td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); }
.data-table th { font-size: 12.5px; font-weight: 620; color: var(--text-mute); background: var(--surface-2); white-space: nowrap; }
.data-table tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover { background: var(--surface-2); }
.data-table td.actions { white-space: nowrap; }
.data-table td.actions a, .data-table td.actions button { margin-right: 8px; }
/* ── 10. 详情页 ──────────────────────────────────────────────────────────── */
.detail-grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 14px 22px;
padding: 16px 18px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.detail-item { min-width: 0; }
.detail-item-wide { grid-column: 1 / -1; }
.detail-label { font-size: 12px; color: var(--text-mute); margin-bottom: 2px; }
.detail-value { font-size: 14px; word-break: break-word; }
/* 花销汇总条 */
.activity-stats { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 18px; }
.activity-stat {
flex: 1 1 140px;
padding: 11px 14px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
display: flex; flex-direction: column; gap: 1px;
}
.activity-stat .detail-label { margin: 0; }
.activity-stat strong { font-size: 16px; }
/* ── 11. 评论 ────────────────────────────────────────────────────────────── */
.comment-thread { margin-top: 8px; }
.comment-list { display: flex; flex-direction: column; gap: 14px; }
.comment-item {
padding: 12px 14px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.comment-child {
margin-left: 22px;
background: var(--surface-2);
border-left: 2px solid var(--accent-soft);
}
.comment-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 5px; }
.comment-author { font-weight: 620; font-size: 13.5px; }
.comment-time { font-size: 12px; color: var(--text-mute); }
.comment-body { font-size: 14px; white-space: pre-wrap; word-break: break-word; }
.comment-replies { margin-top: 10px; display: flex; flex-direction: column; gap: 10px; }
.comment-del-form { display: inline; margin-left: auto; }
.comment-del {
border: 0; background: none; color: var(--text-mute);
font-size: 15px; line-height: 1; cursor: pointer; padding: 2px 6px; border-radius: 6px;
}
.comment-del:hover { background: var(--danger-soft); color: var(--danger); }
.comment-form { margin-top: 14px; }
.comment-form-inline { margin-top: 8px; }
.comment-form textarea, .comment-form-inline textarea { min-height: 68px; }
.comment-reply-box { margin-top: 10px; }
/* ── 12. 参与人 ──────────────────────────────────────────────────────────── */
.member-list { display: flex; flex-direction: column; gap: 10px; }
.member-row {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding: 10px 13px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.member-name { font-weight: 600; font-size: 14px; }
.member-role { display: inline-flex; flex-wrap: wrap; gap: 5px; }
.member-emotion { font-size: 17px; line-height: 1; }
.member-checkin { font-size: 12.5px; color: var(--text-mute); }
.member-del-form { display: inline; margin-left: auto; }
.member-del-form button {
border: 0; background: none; color: var(--text-mute);
font-size: 15px; cursor: pointer; padding: 2px 6px; border-radius: 6px;
}
.member-del-form button:hover { background: var(--danger-soft); color: var(--danger); }
.emotion-grid { display: flex; flex-wrap: wrap; gap: 6px; }
.emotion-option {
display: inline-flex; align-items: center; gap: 5px;
padding: 5px 10px; border: 1px solid var(--border-strong); border-radius: 999px;
cursor: pointer; font-size: 14px; background: var(--surface);
}
.emotion-option:hover { border-color: var(--accent); }
.emotion-option input { margin: 0; }
.emotion-face { font-size: 16px; line-height: 1; }
.emotion-text { font-size: 12.5px; color: var(--text-soft); }
/* ── 13. 花销 ────────────────────────────────────────────────────────────── */
.expense-summary { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.expense-stat {
flex: 1 1 130px;
padding: 11px 14px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.expense-stat > div:first-child { font-size: 12px; color: var(--text-mute); }
.expense-stat strong { font-size: 16px; }
.expense-list { display: flex; flex-direction: column; gap: 10px; }
.expense-row {
display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
padding: 11px 14px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.expense-main { min-width: 0; }
.expense-cat { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.expense-desc { font-size: 13px; color: var(--text-soft); margin-top: 2px; }
.expense-sub { font-size: 12.5px; color: var(--text-mute); margin-top: 3px; }
.expense-amount { font-size: 15px; font-weight: 650; white-space: nowrap; }
.expense-kind { font-size: 11.5px; padding: 1px 7px; border-radius: 999px; font-weight: 550; }
.expense-kind-budget { background: var(--bg-soft); color: var(--text-soft); }
.expense-kind-actual { background: var(--success-soft); color: var(--success); }
/* ── 14. 附件与照片 ──────────────────────────────────────────────────────── */
.drop-zone {
border: 2px dashed var(--border-strong);
border-radius: var(--radius);
background: var(--surface);
padding: 22px 16px;
text-align: center;
cursor: pointer;
transition: border-color .15s, background .15s;
}
.drop-zone:hover, .drop-zone.dragging { border-color: var(--accent); background: var(--accent-soft); }
.drop-zone-inner { color: var(--text-soft); }
.drop-zone-inner .muted { margin-top: 4px; }
.file-list { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; }
.file-row {
font-size: 13px; color: var(--text-soft);
padding: 7px 11px; background: var(--surface-2);
border: 1px solid var(--border); border-radius: var(--radius-sm);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 待上传照片的暂存区 */
.photo-stage { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 14px; }
.photo-item {
width: 132px; background: var(--surface);
border: 1px solid var(--border); border-radius: var(--radius);
overflow: hidden; display: flex; flex-direction: column;
}
.photo-thumb { width: 100%; height: 96px; object-fit: cover; background: var(--bg-soft); display: block; }
.photo-info { padding: 6px 8px 0; font-size: 11.5px; color: var(--text-mute); }
.photo-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-soft); }
.photo-actions { display: flex; gap: 4px; padding: 6px 8px 8px; }
.photo-actions button {
flex: 1; font-size: 11.5px; padding: 4px; cursor: pointer;
border: 1px solid var(--border); border-radius: 6px;
background: var(--surface); color: var(--text-soft); font-family: inherit;
}
.photo-actions button:hover { border-color: var(--accent); color: var(--accent); }
.photo-badge {
margin: 6px 8px 0; align-self: flex-start;
font-size: 11px; padding: 1px 6px; border-radius: 999px;
background: var(--success-soft); color: var(--success);
}
/* 已上传的照片墙 */
.photo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 12px;
}
.photo-grid-sm { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
.photo-card {
position: relative; display: block;
border: 1px solid var(--border); border-radius: var(--radius);
overflow: hidden; background: var(--surface);
transition: box-shadow .15s, transform .15s;
}
.photo-card:hover { box-shadow: var(--shadow-sm); transform: translateY(-2px); }
.photo-card > a { display: block; color: inherit; }
.photo-card > a:hover { text-decoration: none; }
.photo-card img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; background: var(--bg-soft); }
/* 存储后端标记(本地 / OSS),压在缩略图左上角 */
.photo-tag {
position: absolute; top: 6px; left: 6px;
font-size: 10.5px; padding: 1px 6px; border-radius: 999px;
background: rgba(20, 24, 34, .6); color: #fff; letter-spacing: .3px;
}
.photo-tag-oss { background: rgba(232, 122, 45, .92); }
.photo-cap { padding: 8px 10px 10px; font-size: 12px; color: var(--text-mute); }
.photo-cap-name {
display: block; font-size: 12.5px; color: var(--text);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.photo-cap-sub {
display: block; margin-top: 2px; font-size: 11.5px; color: var(--text-mute);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.photo-cap-links { display: block; margin-top: 7px; }
.photo-cap-links a { font-size: 12px; margin-right: 12px; }
.photo-del-form { position: absolute; top: 6px; right: 6px; margin: 0; opacity: 0; transition: opacity .15s; }
.photo-card:hover .photo-del-form, .photo-del-form:focus-within { opacity: 1; }
.photo-del {
width: 26px; height: 26px; border-radius: 50%;
border: 0; cursor: pointer; line-height: 1;
background: rgba(20, 24, 34, .55); color: #fff; font-size: 15px;
display: flex; align-items: center; justify-content: center;
}
.photo-del:hover { background: var(--danger); }
/* 详情页上的小照片墙 */
.photo-more {
display: flex; flex-direction: column; align-items: center; justify-content: center;
aspect-ratio: 4 / 3; border: 1px dashed var(--border-strong);
border-radius: var(--radius); background: var(--surface-2);
color: var(--text-soft); font-size: 18px; font-weight: 620;
}
.photo-more span { font-size: 11.5px; font-weight: 400; color: var(--text-mute); }
.photo-more:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.photo-bar { display: flex; align-items: center; gap: 12px; margin-top: 12px; flex-wrap: wrap; }
/* 通用附件卡(非图片也用) */
.attachment-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px;
}
.attachment-card {
border: 1px solid var(--border); border-radius: var(--radius);
overflow: hidden; background: var(--surface); display: flex; flex-direction: column;
}
.attachment-link { display: block; color: inherit; }
.attachment-link:hover { text-decoration: none; }
.attachment-thumb { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; background: var(--bg-soft); }
.attachment-icon {
display: flex; align-items: center; justify-content: center;
height: 96px; font-size: 30px; background: var(--bg-soft);
}
.attachment-meta { padding: 9px 11px; display: flex; align-items: center; gap: 6px; }
.attachment-name {
font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0;
}
.attachment-sub { font-size: 11.5px; color: var(--text-mute); }
.attachment-delete {
border: 0; background: none; color: var(--text-mute);
font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 6px; border-radius: 6px; flex: none;
}
.attachment-delete:hover { background: var(--danger-soft); color: var(--danger); }
/* ── 15. 弹窗与裁剪 ──────────────────────────────────────────────────────── */
.modal {
position: fixed; inset: 0; z-index: 100;
display: none; align-items: center; justify-content: center;
padding: 20px;
}
.modal.open { display: flex; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(18, 22, 32, .58); }
.modal-content {
position: relative; z-index: 1;
width: 100%; max-width: 460px;
max-height: calc(100vh - 40px); overflow: auto;
background: var(--surface);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg);
padding: 20px;
}
.modal-content-wide { max-width: 720px; }
.modal-actions {
display: flex; justify-content: flex-end; gap: 10px;
margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border);
}
.crop-container { width: 100%; max-height: 60vh; overflow: hidden; background: #111; border-radius: var(--radius-sm); }
.crop-container-wide { max-height: 66vh; }
/* Cropper 需要按原始尺寸接管这张图(自己算内联宽高),不能被 max-width 夹住;
容器自带 overflow:hidden,所以就算图超出也只会被裁掉,不会撑破页面。 */
.crop-container img { max-width: none; display: block; }
/* 预览容器只负责「框」:定尺寸、圆角、把图片裁进去。
⚠️ width / height / object-fit 必须写在 **img** 上,不能写在外层 div 上 ——
写错地方图片就完全不受约束,会按原始尺寸铺出来:头像 400×400、封面
1920×1080,直接把下面的表单盖住(这就是「头像非常大、整页错位」的根)。
对照写对了的 .card-cover img / .activity-cover img。 */
.avatar-preview {
position: relative; flex: none;
width: 84px; height: 84px; border-radius: 50%;
overflow: hidden; /* 把方图裁成圆,并兜住任何溢出 */
background: var(--bg-soft); border: 2px dashed var(--border-strong);
}
.cover-preview {
position: relative;
width: 100%; aspect-ratio: 16 / 9;
overflow: hidden;
border-radius: var(--radius); background: var(--bg-soft);
border: 2px dashed var(--border-strong);
}
/* 图和占位块都用绝对定位铺满容器:
百分比相对 padding box 解析,宽高一定确定。
⚠️ 不要用 `display: grid; place-items: center` + `width: 100%` ——
自动列宽会反过来依赖元素自身宽度,形成循环,浏览器只能把图算成 0 宽
(实测就是这么坏的:img 宽 0、只剩一个空框)。 */
.avatar-preview > img,
.cover-preview > img {
position: absolute; inset: 0;
display: block; width: 100%; height: 100%; object-fit: cover;
}
.avatar-preview > .avatar-placeholder,
.cover-preview > .cover-placeholder {
position: absolute; inset: 0;
width: 100%; height: 100%;
display: flex; align-items: center; justify-content: center;
}
/* 上传区只是「预览 + 操作按钮」的布局容器,不是那个虚线圆框本身。
⚠️ 这里曾经把 84×84 的圆形尺寸套在 .avatar-upload 上,而模板把预览、
按钮、提示文字都放在它**内部** → 三样东西全被塞进那个小圆里互相重叠
(编辑用户页的「选择图片/移除」就压在头像上)。圆框属于
.avatar-preview / .cover-preview,容器只负责排列。 */
.avatar-upload {
display: flex; align-items: center; gap: 16px;
width: auto; height: auto;
border: 0; border-radius: 0; background: none;
}
.cover-upload {
display: flex; flex-direction: column; gap: 12px;
width: 100%; height: auto;
border: 0; border-radius: 0; background: none;
}
/* "+" 占位块:尺寸已经被 `.avatar-preview > .avatar-placeholder` 铺满了,这里只管样子 */
.avatar-placeholder {
border-radius: 50%;
background: var(--bg-soft); color: var(--text-mute); font-size: 26px;
}
/* 悬停高亮落在预览框上(那才是"会被换掉的东西") */
.avatar-preview, .cover-preview { transition: border-color .15s, background .15s; }
.avatar-upload:hover .avatar-preview,
.cover-upload:hover .cover-preview { border-color: var(--accent); background: var(--accent-soft); }
.avatar-upload-actions, .cover-upload-actions {
display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin-top: 0;
}
/* ── 16. 头像与用户 ──────────────────────────────────────────────────────── */
/* 这两类是直接写在 <img>(或首字母 <span>)上的,所以尺寸放这里是对的。
注意别把 .avatar-placeholder 的 84px 带进来:它常与 .avatar-sm 叠用
(用户列表里用首字母当头像),靠下面那条组合规则把字号压回 13px。 */
.avatar-xs, .avatar-sm {
border-radius: 50%; object-fit: cover; flex: none;
display: inline-flex; align-items: center; justify-content: center;
overflow: hidden;
}
.avatar-xs { width: 26px; height: 26px; }
.avatar-sm { width: 30px; height: 30px; }
.avatar-initial { background: var(--accent); color: #fff; font-size: 12px; font-weight: 620; }
.avatar-sm.avatar-placeholder,
.avatar-xs.avatar-placeholder {
font-size: 13px; font-weight: 620;
background: var(--accent-soft); color: var(--accent);
}
.user-cell { display: flex; align-items: center; gap: 9px; }
.user-info { display: inline-flex; align-items: center; gap: 8px; }
/* ── 17. 登录页 ──────────────────────────────────────────────────────────── */
.login-wrapper { width: 100%; }
.login-form {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
padding: 28px 24px;
}
.login-form h1 { font-size: 19px; text-align: center; margin-bottom: 4px; }
.login-form > p { text-align: center; margin-bottom: 20px; }
/* ── 18. 存储设置页 ──────────────────────────────────────────────────────── */
.settings-status { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
.settings-chip {
flex: 1 1 190px;
padding: 11px 14px;
background: var(--surface);
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
border-radius: var(--radius);
font-size: 13px;
}
.settings-chip.ok { border-left-color: var(--success); }
.settings-chip.warn { border-left-color: var(--warn); }
.settings-chip > div:first-child { font-size: 12px; color: var(--text-mute); }
.settings-chip strong { font-size: 14px; }
.settings-hint { font-size: 12.5px; color: var(--text-mute); margin-top: 5px; line-height: 1.6; }
.settings-hint code { background: var(--bg-soft); padding: 1px 5px; border-radius: 4px; font-size: 12px; word-break: break-all; }
.oss-fields { display: none; }
.oss-fields.show { display: block; }
.test-result {
margin-top: 12px; padding: 11px 13px; border-radius: var(--radius-sm);
font-size: 13px; display: none; white-space: pre-wrap; word-break: break-word;
}
.test-result.show { display: block; }
.test-result.ok { background: var(--success-soft); color: var(--success); border: 1px solid #b9e4d1; }
.test-result.bad { background: var(--danger-soft); color: var(--danger); border: 1px solid #f3c9ca; }
.role-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.role-chip {
font-size: 12.5px; padding: 3px 10px; border-radius: 999px;
border: 1px solid var(--border-strong); background: var(--surface);
cursor: pointer; font-family: inherit; color: var(--text-soft);
}
.role-chip:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
/* ── 19. 形态开关(自有车 / 租车 等按需显示的字段) ─────────────────────── */
.own-only, .rental-only, .mode-field { display: none; }
/* ── 20. 附件页与表单补充 ───────────────────────────────────────────────── */
/* 表单里的小字说明 */
.form-hint { font-size: 12.5px; color: var(--text-mute); margin-top: 5px; line-height: 1.65; }
.form-hint code, .settings-hint code, .alert code {
background: var(--bg-soft); padding: 1px 5px; border-radius: 4px;
font-size: 12px; word-break: break-all;
}
.alert-warn { background: var(--warn-soft); color: var(--warn); border-color: #ecd9b4; }
.text-danger { color: var(--danger); }
.req { color: var(--danger); font-weight: 620; }
.inline-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.inline-row > input { flex: 1 1 220px; min-width: 0; }
/* 上传区 */
.drop-zone-icon { font-size: 30px; line-height: 1.1; }
.drop-zone-title { margin: 6px 0 0; font-size: 14.5px; color: var(--text); }
.drop-zone-hint { font-size: 12.5px; margin: 4px 0 0; }
/* 待上传暂存区 */
.stage-head {
display: flex; align-items: center; justify-content: space-between;
gap: 12px; margin-top: 18px; flex-wrap: wrap;
}
.stage-count { font-size: 13px; color: var(--text-soft); }
.stage-tools { display: flex; gap: 8px; }
.photo-thumb-icon {
display: flex; align-items: center; justify-content: center;
font-size: 28px; height: 96px; background: var(--bg-soft);
}
.photo-badge-plain { background: var(--bg-soft); color: var(--text-soft); }
.photo-actions button[disabled] { opacity: .45; cursor: not-allowed; }
/* 上传进度 */
.upload-progress { margin-top: 14px; }
.upload-track {
height: 8px; border-radius: 999px; background: var(--bg-soft); overflow: hidden;
}
.upload-bar {
height: 100%; width: 0; border-radius: 999px;
background: var(--accent); transition: width .2s ease;
}
.upload-text { margin-top: 6px; font-size: 12.5px; color: var(--text-mute); }
/* 弹窗标题 */
.modal-title { font-size: 16px; margin: 0 0 4px; }
.modal-hint { font-size: 12.5px; color: var(--text-mute); margin: 0 0 12px; }
/* ── 21. 响应式 ──────────────────────────────────────────────────────────── */
@media (max-width: 820px) {
.timeline-grid { grid-template-columns: 1fr; }
.card-grid { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
}
@media (max-width: 640px) {
body { font-size: 14.5px; }
/* 留白仍走 --shell-pad(此时它等于 --gutter):断点里也不能改成固定值,
否则窄屏下顶栏与正文又会对不齐。 */
.container { padding: 16px var(--shell-pad) 52px; }
.container-guest { padding: 20px 14px; }
.topbar { padding: 8px var(--shell-pad); }
.brand-text { display: none; }
.menu-name { display: none; }
.menu-trigger { padding: 4px; gap: 4px; }
.menu-panel { min-width: 208px; }
.two-col { grid-template-columns: 1fr; }
.card-grid, .photo-grid, .attachment-grid {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.detail-grid { grid-template-columns: 1fr; }
.page-header { flex-direction: column; align-items: stretch; }
.page-header .btn, .page-header .btn-primary { align-self: flex-start; }
.comment-child { margin-left: 10px; }
.modal { padding: 12px; }
.modal-content { padding: 16px; }
.topbar-new { padding: 5px 9px; font-size: 12.5px; }
.expense-row { flex-direction: column; }
.expense-amount { align-self: flex-end; }
.photo-item { width: calc(50% - 6px); }
.settings-chip { flex: 1 1 100%; }
.inline-row { align-items: stretch; }
}