/* ============================================================ 家书 FamilyBook · 界面样式 配色取自图标:宣纸米 / 砖红封面 / 深褐书脊 / 纸白 原则:扁平、留白充足、字重克制(正文 400,标题 500-600) ============================================================ */ :root { --paper: #F7F3EA; --surface: #FFFFFF; --ink: #2C231D; --muted: #7E6B5A; --faint: #A8988A; --brand: #A84A28; --brand-2: #C96F45; --brand-ink:#6E3820; --green: #6F9E5C; --red: #C0533F; --line: rgba(44, 35, 29, .10); --line-2: rgba(44, 35, 29, .06); --radius: 16px; --radius-s: 10px; --shadow: 0 1px 2px rgba(44, 35, 29, .05); --shadow-l: 0 4px 16px rgba(44, 35, 29, .08); } * { box-sizing: border-box; } html, body { height: 100%; } body { margin: 0; background: var(--paper); color: var(--ink); font: 15px/1.7 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", sans-serif; -webkit-font-smoothing: antialiased; } a { color: var(--brand); text-decoration: none; } a:hover { text-decoration: underline; } /* ---------------- 顶栏 ---------------- */ .topbar { position: sticky; top: 0; z-index: 20; background: var(--surface); border-bottom: 1px solid var(--line); } .topbar-inner { max-width: 1080px; margin: 0 auto; padding: 0 24px; height: 60px; display: flex; align-items: center; gap: 24px; } .brand { display: flex; align-items: center; gap: 10px; color: var(--ink); } .brand:hover { text-decoration: none; } .brand img { width: 30px; height: 30px; border-radius: 8px; display: block; } .brand span { font-size: 16px; font-weight: 600; letter-spacing: .5px; } .nav { display: flex; gap: 4px; margin-left: 8px; } .nav a { padding: 6px 12px; border-radius: 999px; color: var(--muted); font-size: 14px; } .nav a:hover { background: var(--line-2); text-decoration: none; } .nav a.on { background: var(--brand); color: #fff; } .topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; } .who { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 14px; } a.who:hover { text-decoration: none; } /* 头像/名字是个「编辑我自己」的入口 —— hover 时给点反馈,让人知道它可点 */ a.who:hover .who-name { color: var(--brand); text-decoration: underline; } a.who:hover img { box-shadow: 0 0 0 2px var(--brand-2); } .who img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; } .who img { transition: box-shadow .15s ease; } .link-quiet { color: var(--muted); font-size: 14px; } .link-quiet:hover { color: var(--brand); } /* 顶栏里的文字一律不许换行 —— 一换行就是「首/页」「名/册」竖排,很难看 */ .nav a, .topbar-right a, .who-name { white-space: nowrap; } /* ---------------- 布局 ---------------- */ .container { max-width: 1080px; margin: 0 auto; padding: 28px 24px 64px; } .container-narrow { max-width: 560px; margin: 0 auto; padding: 28px 24px 64px; } .page-head { display: flex; align-items: flex-end; gap: 16px; margin-bottom: 20px; } .page-head h1 { font-size: 22px; font-weight: 600; margin: 0; } .page-head .sub { color: var(--muted); font-size: 14px; } .page-head .actions { margin-left: auto; display: flex; gap: 8px; } .section { margin-top: 28px; } .section-title { display: flex; align-items: center; gap: 10px; font-size: 15px; font-weight: 600; margin: 0 0 12px; } .section-title .hint { font-weight: 400; color: var(--muted); font-size: 13px; } /* ---------------- 卡片 ---------------- */ .card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); } .card-pad { padding: 20px; } /* 首页头图 */ .hero { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 26px 28px; display: flex; align-items: center; gap: 20px; flex-wrap: wrap; } .hero-logo { width: 64px; height: 64px; border-radius: 16px; flex: 0 0 auto; } .hero-main { flex: 1 1 240px; min-width: 0; } .hero h1 { font-size: 24px; font-weight: 600; margin: 0 0 4px; } .hero .motto { color: var(--muted); margin: 0; font-size: 14px; } /* 那句小字到底是谁的:自己写的那句要标一下,否则用户会以为这是系统统一发的 */ .motto-from { display: inline-block; margin-left: 6px; padding: 0 7px; border-radius: 999px; background: var(--line-2); font-size: 11px; color: var(--faint); } .motto-edit { margin-left: 8px; font-size: 12px; color: var(--brand-2); white-space: nowrap; } /* 详情页顶部引用本人的一句话 */ .motto-line { margin: -8px 0 16px; padding-left: 12px; border-left: 3px solid var(--brand-2); color: var(--muted); font-size: 14px; } .hero-stats { margin-left: auto; display: flex; gap: 28px; } .stat { text-align: center; } .stat b { display: block; font-size: 24px; font-weight: 600; line-height: 1.2; } .stat span { font-size: 12px; color: var(--muted); } /* ---------------- 成员卡 ---------------- */ .people-grid { display: grid; gap: 16px; margin-top: 4px; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); } .person { display: block; color: var(--ink); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); transition: transform .15s ease, box-shadow .15s ease; } .person:hover { transform: translateY(-2px); box-shadow: var(--shadow-l); text-decoration: none; } .person .ph { background: #F1E7D6; aspect-ratio: 1 / 1; overflow: hidden; } .person .ph img { width: 100%; height: 100%; object-fit: cover; display: block; } .person .pb { padding: 12px 14px 14px; } .person .pname { font-weight: 600; font-size: 15px; display: flex; align-items: center; gap: 6px; } .person .pmeta { color: var(--muted); font-size: 13px; margin-top: 2px; } .badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 500; line-height: 1.7; background: var(--line-2); color: var(--muted); } .badge-admin { background: #F6E3D7; color: var(--brand-ink); } .badge-open { background: #E6F0DC; color: #4A7226; } .badge-me { background: var(--brand); color: #fff; } /* 生日条 —— 一个人可能同时出两条(农历与阳历不在同一天), 落在同一天时并成一条、kinds 里挂多个标签,正好对应"要分别提醒"。 */ .bdays { display: flex; gap: 12px; flex-wrap: wrap; } .bday { display: flex; align-items: center; gap: 12px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 18px 10px 10px; box-shadow: var(--shadow); color: var(--ink); text-decoration: none; transition: transform .15s ease, box-shadow .15s ease; } .bday:hover { transform: translateY(-2px); box-shadow: var(--shadow-l); text-decoration: none; } .bday img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; } .bday b { font-weight: 500; } .bday .d { color: var(--brand); font-size: 13px; } .bday-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 3px; } .bday-date { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; } /* 「身份证生日 / 阳历生日 / 农历生日」的标签,首页与详情页共用 */ .bd-kind { display: inline-block; padding: 0 7px; border-radius: 999px; font-size: 11px; line-height: 1.8; background: var(--line-2); color: var(--muted); } .bd-kind-id { background: #E6F0DC; color: #4A7226; } .bd-kind-solar { background: #F6E3D7; color: var(--brand-ink); } .bd-kind-lunar { background: #E8E4F2; color: #55477E; } /* 详情页的三个生日 */ .bd-list { list-style: none; margin: 0; padding: 0; } .bd-list li { display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px; flex-wrap: wrap; } .bd-list .bd-val { font-variant-numeric: tabular-nums; } /* ---------------- 表单 ---------------- */ .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } .field { display: flex; flex-direction: column; gap: 6px; } .field.full { grid-column: 1 / -1; } .field label { font-size: 13px; color: var(--muted); font-weight: 500; } .field .tip { font-size: 12px; color: var(--muted); } .input, .select, textarea.input { width: 100%; padding: 10px 12px; font: inherit; font-size: 14px; color: var(--ink); background: #fff; border: 1px solid var(--line); border-radius: var(--radius-s); transition: border-color .15s ease, box-shadow .15s ease; } .input:focus, .select:focus, textarea.input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(168, 74, 40, .12); } textarea.input { min-height: 76px; resize: vertical; } .err { color: var(--red); font-size: 12px; } .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 9px 16px; font: inherit; font-size: 14px; font-weight: 500; border-radius: var(--radius-s); border: 1px solid transparent; cursor: pointer; background: var(--brand); color: #fff; transition: background .15s ease; } .btn:hover { background: #944022; text-decoration: none; } .btn-ghost { background: #fff; color: var(--ink); border-color: var(--line); } .btn-ghost:hover { background: #FAF7F1; } .btn-danger { background: #fff; color: var(--red); border-color: rgba(192,83,63,.35); } .btn-danger:hover { background: #FDF1EE; } .btn-sm { padding: 5px 12px; font-size: 13px; } .btn-row { display: flex; gap: 10px; margin-top: 20px; } /* ---------------- 详情 ---------------- */ .detail { display: grid; grid-template-columns: 260px 1fr; gap: 24px; } .detail-photo { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; text-align: center; box-shadow: var(--shadow); } .detail-photo img { width: 100%; aspect-ratio: 1/1; object-fit: cover; border-radius: 12px; display: block; } .detail-photo .name { font-size: 18px; font-weight: 600; margin: 14px 0 4px; } .detail-photo .sub { color: var(--muted); font-size: 13px; } .kv { display: flex; flex-direction: column; } .kv-row { display: grid; grid-template-columns: 96px 1fr; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line-2); } .kv-row:last-child { border-bottom: 0; } .kv-row dt { color: var(--muted); font-size: 13px; } .kv-row dd { margin: 0; font-size: 14px; word-break: break-all; } .mono { font-family: ui-monospace, "SFMono-Regular", Consolas, monospace; letter-spacing: .5px; } /* ---------------- 提示 ---------------- */ .flash { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; } .flash-item { padding: 10px 14px; border-radius: var(--radius-s); font-size: 14px; background: #E6F0DC; color: #3D6B1F; } .flash-item.err { background: #F8DDDA; color: #A1341F; } .empty { background: var(--surface); border: 1px dashed var(--line); border-radius: var(--radius); padding: 40px 20px; text-align: center; color: var(--muted); } .empty b { display: block; color: var(--ink); font-weight: 500; margin-bottom: 4px; } /* ---------------- 登录 / 安装 ---------------- */ .auth-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 40px 20px; } .auth-card { width: 100%; max-width: 400px; background: var(--surface); border: 1px solid var(--line); border-radius: 20px; box-shadow: var(--shadow-l); padding: 32px; } /* 图标 + 「用手机号登录你的家书」+ 家庭名,整块水平居中。 ⚠️ 只有这一块居中:下面的表单仍然左对齐(label 左对齐才好读), 「忘记密码」那行本来就是居中,所以视觉上不会歪。 */ .auth-head { text-align: center; } .auth-card .logo { display: block; margin: 0 auto 14px; width: 56px; height: 56px; border-radius: 14px; } .auth-card h1 { font-size: 20px; font-weight: 600; margin: 0 0 4px; } .auth-card .lead { color: var(--muted); font-size: 14px; margin: 0 0 24px; } .auth-card .btn { width: 100%; margin-top: 20px; } .auth-foot { margin-top: 18px; font-size: 13px; color: var(--muted); text-align: center; } /* ---------------- 其他 ---------------- */ .muted { color: var(--muted); } .small { font-size: 13px; } .nowrap { white-space: nowrap; } .search { display: flex; gap: 8px; margin-bottom: 16px; } .search .input { max-width: 260px; } /* ---------------- 日期 + 时:分:秒 组合控件(templates/_datetime.php) ---------------- 原生 datetime-local 的显示格式由浏览器 UI 语言/系统时间格式决定, 中文环境渲染成「下午 03:30」且没有秒,所以自己拼一个。 日期部分仍是原生 date 控件 → app.js 的 showPicker 让它整框可点。 */ .dt-input { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } .dt-input .dt-date { flex: 1 1 150px; min-width: 0; padding: 9px 11px; border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); color: var(--ink); font: inherit; accent-color: var(--brand); } .dt-input .dt-date { cursor: pointer; } /* 整框可点,光标也要说明这一点 */ .dt-input .dt-date::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .65; } .dt-time { display: flex; align-items: center; gap: 3px; } .dt-input .dt-hour, .dt-input .dt-minute, .dt-input .dt-second { padding: 9px 6px; border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); color: var(--ink); font: inherit; font-variant-numeric: tabular-nums; cursor: pointer; } .dt-input .dt-colon { color: var(--muted); font-weight: 600; } /* 「以哪个生日为准」的两块:被选中的那块描一圈,一眼看出填的是哪边 */ .bd-source { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; } .bd-pane { border: 1px solid transparent; border-radius: var(--radius); padding: 10px 12px 2px; } .bd-pane.is-primary { border-color: var(--brand-2); background: #FDF6F1; } .bd-pane .bd-pane-k { font-size: 13px; font-weight: 600; margin: 0 0 8px; } .bd-readonly { display: inline-block; padding: 6px 10px; border-radius: var(--radius-s); background: var(--line-2); color: var(--muted); font-size: 14px; font-variant-numeric: tabular-nums; } /* ---------------- 称谓标签 ---------------- */ .rel-label { display: inline-block; padding: 1px 9px; border-radius: 999px; background: #F6E3D7; color: var(--brand-ink); font-size: 11px; font-weight: 500; line-height: 1.8; margin-right: 2px; } /* ---------------- 家谱(以我为中心) ---------------- */ .tree { display: flex; flex-direction: column; align-items: center; gap: 0; } .tree-gen { width: 100%; } .tree-gen-label { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; padding-left: 2px; } .tree-gen-label .gname { font-size: 13px; font-weight: 600; color: var(--ink); } .tree-gen-label .gtag { font-size: 11px; color: var(--muted); background: var(--line-2); padding: 1px 8px; border-radius: 999px; } .tree-row { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; align-items: stretch; } .tnode { display: flex; flex-direction: column; align-items: center; gap: 5px; width: 104px; padding: 12px 8px 10px; text-align: center; background: var(--surface); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); color: var(--ink); transition: transform .15s ease, box-shadow .15s ease; } .tnode:hover { transform: translateY(-2px); box-shadow: var(--shadow-l); text-decoration: none; } .tnode .tph { width: 52px; height: 52px; border-radius: 50%; overflow: hidden; background: #F1E7D6; } .tnode .tph img { width: 100%; height: 100%; object-fit: cover; display: block; } .tnode .tname { font-size: 13px; font-weight: 600; line-height: 1.3; } .tnode .tlabel { font-size: 11px; color: var(--brand); } .tnode .tph-mark { font-size: 10px; color: var(--faint); } .tnode.is-me { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(168, 74, 40, .12), var(--shadow); } .tnode.is-me .tlabel { color: var(--brand-ink); font-weight: 600; } .tnode.is-placeholder { border-style: dashed; } /* 世代之间的连接线(纯装饰,说明"往下走一代") */ .tree-link { width: 2px; height: 22px; background: linear-gradient(var(--line), var(--line-2)); margin: 6px auto; } /* 详情页里的迷你家谱 */ .mini-tree { display: flex; flex-direction: column; gap: 8px; } .mini-gen { display: flex; flex-wrap: wrap; gap: 8px; } .mini-node { display: flex; align-items: center; gap: 7px; padding: 5px 12px 5px 5px; border-radius: 999px; background: #FAF7F1; border: 1px solid var(--line); color: var(--ink); font-size: 13px; } .mini-node:hover { text-decoration: none; border-color: var(--brand); } .mini-node img { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; } .mini-node .mn-label { font-size: 11px; color: var(--brand); } .mini-node.is-me { border-color: var(--brand); background: #F6E3D7; } /* ---------------- 亲属关系编辑 ---------------- */ .rel-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; margin-bottom: 18px; } .rel-sum-item { background: #FAF7F1; border: 1px solid var(--line-2); border-radius: var(--radius-s); padding: 10px 14px; } .rel-sum-k { display: block; font-size: 12px; color: var(--muted); margin-bottom: 3px; } .rel-sum-v { font-size: 14px; } .rel-sum-v a { margin-right: 6px; } .rel-add { border-top: 1px solid var(--line-2); padding-top: 16px; } .rel-add-title { font-size: 14px; font-weight: 600; margin: 0 0 12px; } .rel-form { display: grid; grid-template-columns: 1fr 1fr 1.4fr auto; gap: 12px; align-items: end; } .rel-list { margin-top: 16px; font-size: 13px; } .rel-list summary { cursor: pointer; color: var(--muted); } .rel-list ul { margin: 10px 0 0; padding-left: 18px; } .rel-list li { margin-bottom: 6px; } .rel-list .btn { margin-left: 6px; } /* ---------------- 三角色 / 存储设置 ---------------- */ .role-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; } .role-card { background: #FAF7F1; border: 1px solid var(--line-2); border-radius: var(--radius-s); padding: 14px 16px; } .rc-name { font-weight: 600; margin-bottom: 5px; } .rc-desc { margin: 0; font-size: 13px; color: var(--muted); line-height: 1.65; } .radio-row { display: flex; flex-direction: column; gap: 10px; } .radio-item { display: flex; gap: 10px; align-items: flex-start; background: #FAF7F1; border: 1px solid var(--line-2); border-radius: var(--radius-s); padding: 12px 14px; cursor: pointer; } .radio-item input { margin-top: 3px; } .check-item { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; cursor: pointer; } .check-item input { margin-top: 3px; } .oss-box { border: 1px solid var(--line-2); border-radius: var(--radius-s); padding: 12px 16px; background: #FCFAF6; } .oss-box summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--muted); } .plain-list { margin: 0; padding-left: 18px; font-size: 14px; } .plain-list li { margin-bottom: 7px; } @media (max-width: 720px) { .rel-form { grid-template-columns: 1fr; } .tnode { width: 88px; padding: 9px 6px 8px; } .tnode .tph { width: 44px; height: 44px; } .tree-row { gap: 8px; } } @media (max-width: 720px) { /* 390px 宽度放不下整套顶栏:只留 图标 + 导航 + 头像 + 退出 */ .topbar-inner { gap: 6px; padding: 0 10px; height: 54px; } .brand img { width: 26px; height: 26px; } .nav { gap: 0; } .nav a { padding: 6px 8px; font-size: 13px; } .topbar-right { gap: 6px; } .who-name, .who-pwd { display: none; } /* 名字与「改密码」收起,设置页里都有 */ .who img { width: 26px; height: 26px; } .container, .container-narrow { padding: 20px 16px 48px; } .form-grid { grid-template-columns: 1fr; } .detail { grid-template-columns: 1fr; } .hero { padding: 20px; gap: 14px; } .hero h1 { font-size: 20px; } .hero-stats { margin-left: 0; gap: 20px; } .page-head { flex-wrap: wrap; align-items: center; } .page-head .actions { margin-left: 0; width: 100%; } .kv-row { grid-template-columns: 84px 1fr; } .search { flex-wrap: wrap; } .search .input { max-width: none; flex: 1 1 auto; } } /* ---------------- 「我怎么称呼家人」(视角属性,见 app/Nickname.php) ---------------- */ .nick-list { display: flex; flex-direction: column; gap: 8px; } .nick-row { display: grid; grid-template-columns: minmax(120px, auto) 1fr auto; gap: 10px; align-items: center; padding: 8px 10px; border-radius: var(--radius-s); background: #FAF7F1; border: 1px solid var(--line-2); } .nick-who { display: flex; align-items: center; gap: 8px; font-size: 14px; min-width: 0; } .nick-who img { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; } .nick-who span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* 详情页上的单个"我叫他什么"输入行 */ .nick-inline { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } .nick-inline .input { flex: 1 1 220px; max-width: 340px; } @media (max-width: 720px) { .nick-row { grid-template-columns: 1fr; } .nick-inline .input { max-width: none; } } /* ---------------- 连通性测试与诊断(设置页) ---------------- */ .test-actions { display: flex; flex-direction: column; gap: 10px; } .test-actions form { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } .oss-diag { margin-top: 16px; border-radius: var(--radius-s); overflow: hidden; border: 1px solid var(--line); } .oss-diag-head { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; padding: 10px 14px; font-size: 13px; background: var(--line-2); } .oss-diag.is-ok .oss-diag-head { background: #E6F0DC; color: #3F6021; } .oss-diag.is-bad .oss-diag-head { background: #F6E3D7; color: var(--brand-ink); } .oss-diag-table { width: 100%; border-collapse: collapse; font-size: 13px; background: var(--surface); } .oss-diag-table th, .oss-diag-table td { padding: 8px 12px; text-align: left; vertical-align: top; border-top: 1px solid var(--line-2); } .oss-diag-table th { font-weight: 500; color: var(--muted); font-size: 12px; } .oss-diag-table td:nth-child(1) { white-space: nowrap; } .oss-diag-table td:nth-child(3) { white-space: nowrap; } .oss-diag-table tr.row-ok td:nth-child(2) { color: #4A7226; } .oss-diag-table tr.row-bad td:nth-child(2) { color: var(--red); } @media (max-width: 720px) { .oss-diag-table th:nth-child(3), .oss-diag-table td:nth-child(3) { display: none; } }