/* MoneyBrader 计算器站 — 设计 token + 组件 + 布局 */

:root {
  --bg: #F5F5F0;
  --card: #ffffff;
  --line: rgba(0, 0, 0, .08);
  --orange: #FF6B00;
  --orange-hover: #E55F00;
  --orange-light: #FFB380;
  --slate: #94A3B8;
  /* 图表三个系列的专用色：同一橙色系由浅到深，越深 = 越是「钱自己生的」。
     环内标签的颜色由 chart.js 按对比度自动决定，这套色阶下的结果是
     前两档配深褐、品牌橙配白字（白字在它上面 2.9:1，在浅橙上只有 1.3:1）。
     单独立 token，不借用 --slate/--orange-light —— 那两个还有别处在用。 */
  --series-initial: #FFDCC0;
  --series-contrib: #FFA45C;
  --series-interest: #FF6B00;
  --input-border: #E8E6DE;
  --ink: #1a1a1a;
  --muted: #888888;
  --danger: #d33a4b;
  --sand: #FAFAF7;
  --font-num: 'Sora', sans-serif;
  --font-body: 'Noto Sans SC', sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  padding: 1.5rem 1rem 3rem;
  -webkit-font-smoothing: antialiased;
}

.page { max-width: 1080px; margin: 0 auto; }

/* ————— header ————— */
.site-header { padding: .25rem 0 1.4rem; }
.brand {
  font-size: 12px; font-weight: 600; letter-spacing: 2px;
  color: var(--orange); text-transform: uppercase; margin-bottom: 8px;
  text-align: center;
}
/* 原图是 2000×2000、四周大片透明，已按 alpha 包围盒裁掉留白并压到 520×283。
   这里显示宽 130px，width/height 属性写的是真实像素，浏览器据此预留位置，
   图片加载完不会把下面的内容顶下去。margin auto 让它与上面那行品牌字一起居中。 */
.brand-logo { display: block; width: 130px; height: auto; margin: 0 auto 14px; }

.head-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.head-row h1 { font-family: var(--font-num); font-size: 1.75rem; font-weight: 700; line-height: 1.25; }
/* 副标题是完整的两三句说明，需要行高和阅读宽度上限，否则在宽屏上会拉成很难读的长行 */
.sub { font-size: 13px; color: var(--muted); margin-top: 8px; line-height: 1.75; max-width: 46em; }

.lang-switch { display: flex; align-items: center; gap: 6px; flex: none; }
.lang-btn {
  background: none; border: none; cursor: pointer; padding: 2px 4px;
  font-family: var(--font-num); font-size: 13px; font-weight: 600;
  color: var(--muted);
}
.lang-btn.is-active { color: var(--orange); }
.lang-btn:hover { color: var(--orange-hover); }
.lang-sep { color: var(--input-border); font-size: 13px; }

/* ————— card ————— */
.card {
  background: var(--card);
  border: .5px solid var(--line);
  border-radius: 16px;
  padding: 1.4rem 1.3rem;
}
.card-title { font-family: var(--font-num); font-size: 15px; font-weight: 700; margin-bottom: 1rem; }

/* ————— 布局 ————— */
.layout { display: grid; grid-template-columns: 1fr; gap: 1rem; min-width: 0; }
.results { display: grid; gap: 1rem; align-content: start; min-width: 0; }


/* grid item 默认 min-width:auto 会按内容撑开轨道；
   .card 内部的 .end-value 用了 nowrap，撑爆时会把整个网格（乃至 body）推宽。
   显式清零，讓內容溢出只发生在盒子自己内部，不传导到页面。 */
.card { min-width: 0; }

@media (min-width: 900px) {
  /* 输入卡与摘要卡放进同一行，高度因此自动取齐、底边对齐；增长图卡落到
     右栏第二行。
     .results 用 display:contents 把两张结果卡直接交给 .layout 的网格，
     不必改动它们在 HTML 里的嵌套。
     代价是右栏不再 sticky —— sticky 原本是为「拖动输入实时看图变」服务的，
     而计算已改为按钮触发、年限也没有滑块，这个收益已经不存在。 */
  .layout {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto;
  }

  /* 副标题不越过左边输入卡的右边缘。用 calc 跟上面的网格算式挂钩
     （两等分栏 + 1rem 间隙），而不是写死像素——以后改栏宽比例，这行自动跟上。 */
  .sub { max-width: calc((100% - 1rem) / 2); }

  .results { display: contents; }
  .inputs  { grid-column: 1; grid-row: 1; }
  .summary { grid-column: 2; grid-row: 1; }
  .tables  { grid-column: 1; grid-row: 2; }
  /* align-self:start —— 增长图卡按自己的内容取高度，不跟着明细表变。
     默认（grid item 会被拉伸到行高）时，用户点开月度明细会把这一行撑到
     两倍多，右边的图卡跟着变成一个下半截全是空白的高盒子。固定尺寸更稳。 */
  .growth  { grid-column: 2; grid-row: 2; align-self: start; }

  /* 摘要卡被拉高到与输入卡齐平后，内容整体垂直居中，避免下方留一大块空白 */
  .summary { display: flex; flex-direction: column; justify-content: center; }

  /* 增长图卡与明细表卡同处第二行，卡片高度会随明细表（尤其展开月度表时）变化。
     图表本身固定贴在标题下方，不随卡片变高而重新垂直居中——否则用户点开
     月度明细时，右边的图会毫无理由地整个往下挪一大截。
     卡片底边仍与明细表对齐，只是多出来的高度留白在下方。 */
}

/* ————— 输入 ————— */
.group-title {
  font-family: var(--font-num); font-size: 16px; font-weight: 700;
  letter-spacing: .5px; text-transform: uppercase; color: var(--ink);
  margin: 1.3rem 0 .8rem;
}
.group-title:first-child { margin-top: 0; }

.field { margin-bottom: .75rem; }
/* 与右侧摘要卡的金额清单同为 15px —— 两张卡并排时字号不一致会显得左边被压扁 */
.field label { display: block; font-size: 15px; color: #444; margin-bottom: 6px; }

/* 一行两个字段并排（本金/期限卡与定期投入卡共用）。
   两列各自独立成 grid item：一侧显示错误文案增高，只撑高自己的格子，
   不会挪动旁边字段的输入框位置（grid 按行顶对齐，不共享盒子）。 */
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 .7rem;
}
.field-row .field { min-width: 0; }

.input-wrap {
  display: flex; align-items: center;
  border: 1.5px solid var(--input-border); border-radius: 10px;
  background: #fff; overflow: hidden;
  transition: border-color .12s;
}
.input-wrap:focus-within { border-color: var(--orange); }
.input-wrap.is-invalid { border-color: var(--danger); }

.affix {
  font-family: var(--font-num); font-size: 12px; font-weight: 600;
  color: var(--muted); padding: 0 0 0 12px; flex: none; white-space: nowrap;
}
.affix-end { padding: 0 12px 0 0; }

.input-wrap input,
.input-wrap select {
  flex: 1 1 auto; min-width: 0;
  border: none; outline: none; background: transparent;
  padding: 9px 12px;
  font-family: var(--font-num); font-size: 15px; font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.input-wrap select { font-family: var(--font-body); font-size: 14px; font-weight: 500; cursor: pointer; }
/* 去掉 number 输入的浏览器上下箭头，避免与右侧单位挤在一起 */
.input-wrap input[type=number] { -moz-appearance: textfield; }
.input-wrap input[type=number]::-webkit-outer-spin-button,
.input-wrap input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.field-err { font-size: 11.5px; color: var(--danger); margin-top: 4px; min-height: 0; display: none; }
.field-err.is-shown { display: block; }

/* ————— 结果摘要 ————— */
.summary { text-align: center; }
.end-label { font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
/* nowrap 无条件生效（不只是窄屏）：金额一长，"RM" 会被甩到单独一行，
   而这是全页最显眼的元素。字号由脚本按可用宽度回缩——CSS 的 clamp 只能
   跟着视口走，跟不上「数字有多少位」，而这里的金额从 RM 0.00 到十三位数都有。 */
.end-value {
  font-family: var(--font-num); font-size: clamp(1.9rem, 6vw, 2.6rem); font-weight: 700;
  color: var(--orange); line-height: 1.15; margin: 4px 0 .4rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 四列通栏：色块 | 名称（左） | 占比 | 金额（右）。
   li 用 display:contents 把四个子元素直接交给 ul 的网格，于是三行的
   占比列与金额列天然各自对齐成一列，不必逐行量宽度。
   1fr 给名称列，把占比和金额推到右边缘——与下方图表同宽，读起来是一条
   完整的横带，而不是浮在中间的一小块。 */
.amount-list {
  display: grid; grid-template-columns: 1fr auto auto;
  column-gap: 1.1rem;
  list-style: none; text-align: left; font-size: 15px;
  margin: 1rem 0 1.2rem;
}
.amount-list li { display: contents; }
.amount-list > li > * { padding: 9px 0; border-top: 1px solid var(--sand); }
.amount-list > li:first-child > * { border-top: none; }

/* 色块必须待在 data-i18n 节点「外面」：applyLang 对每个 data-i18n 节点做
   textContent 赋值，色块若在里面会被整块抹掉。所以这里外套一层 flex 容器，
   色块与文字并列，i18n 只管里层那个 span。 */
.am-name { display: flex; align-items: center; gap: 8px; color: #444; }
.am-pct {
  font-family: var(--font-num); font-size: 13.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right;
}
.am-value {
  font-family: var(--font-num); font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right;
}

/* 图表 + 颜色 key 并排：key 只剩色块+名字——占比已经画在甜甜圈段内，
   金额已经挪到上面的 amount-list，这里不重复数字。
   ≥561px（两栏布局的结果栏、以及大多数单栏宽度）并排放得下；
   更窄（典型手机竖屏 ~390px）时增长图会被挤得连 x 轴年份标签都叠在一起，
   于是在 560px 断点把 key 退回图表下方——用测量校准过，见 task 报告。 */
.chart-key-row { display: flex; align-items: center; gap: 1.1rem; text-align: left; }

/* 甜甜圈已不配图例，直接 margin auto 居中即可，不再需要
   「1fr auto 1fr 三栏把圆环钉在中栏」那套用来抵消右侧图例宽度的写法。 */

/* 圆环的上限由「纵向」决定，不是宽度：卡片内宽有 477px，但摘要卡的高度被
   锁定与输入卡齐平（两者同处网格第一行），实测纵向只剩约 89px 余量，
   也就是圆环最多到 389px。取 370px 留一点缓冲——再大就会把这一行撑高，
   反过来在输入卡底部拉出一块空白。 */
/* width:100% 是必须的：摘要卡是纵向 flex，.donut-wrap 又是 flex:none 且带
   auto 外边距，不会被拉伸；没有显式宽度时它退回 SVG 替换元素的默认 300px，
   max-width 就永远没机会生效（改大数值看不到任何变化，排查过一次）。 */
.donut-wrap { flex: none; margin: 0 auto; width: 100%; max-width: 300px; }
.donut-wrap svg { width: 100%; height: auto; display: block; }

.key { list-style: none; font-size: 14.5px; flex: none; }
.key li { display: flex; align-items: center; gap: 10px; padding: 6px 0; }

.dot { width: 12px; height: 12px; border-radius: 3px; display: block; flex: none; }
.dot-initial { background: var(--series-initial); }
.dot-contrib { background: var(--series-contrib); }
.dot-interest { background: var(--series-interest); }

/* ————— 增长图 ————— */
.chart-wrap { flex: 1 1 240px; min-width: 0; }

/* 增长图的 key 放到图「下方」横排（甜甜圈那份仍在右侧）。
   放右侧会吃掉约 145px 宽度，SVG 是按宽度等比缩放的，宽度一少整张图连同
   坐标轴文字一起缩小，卡片下半截还空着——挪到下面，图既拿到全宽也能加高。 */
.growth .chart-key-row { flex-direction: column; align-items: stretch; gap: .8rem; }
.growth .key {
  display: flex; flex-direction: row; flex-wrap: wrap;
  justify-content: center; gap: .2rem 1.4rem;
}
.chart-wrap svg { width: 100%; height: auto; display: block; overflow: visible; }

@media (max-width: 560px) {
  .chart-key-row { flex-direction: column; align-items: stretch; }
  .chart-key-row .donut-wrap { max-width: 200px; margin: 0 auto; }
  .chart-key-row .key { margin-top: .7rem; }
  .growth .chart-key-row .key {
    display: flex; flex-direction: row; flex-wrap: wrap;
    justify-content: center; gap: .2rem 1rem;
  }
}

/* ————— 表格 ————— */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-tall { max-height: 420px; overflow-y: auto; }

/* min-width 只作为窄屏兜底：低于它才横向滚动。设得太大（曾经是 460px）会让
   「期末余额」那一列在左栏里被推到滚动区之外——恰恰是最该看到的一列。 */
table.sched { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 350px; }
table.sched th {
  position: sticky; top: 0; z-index: 1;
  background: var(--card);
  text-align: right; font-family: var(--font-num); font-size: 11.5px; font-weight: 600;
  letter-spacing: .5px; text-transform: uppercase; color: var(--muted);
  padding: 8px 10px; border-bottom: 1px solid var(--input-border);
}
table.sched th:first-child, table.sched td:first-child { text-align: left; }
table.sched td {
  text-align: right; padding: 8px 10px;
  font-family: var(--font-num); font-variant-numeric: tabular-nums;
  /* 不许把 "RM" 和数字拆到两行——宁可整表横向滚动，也不要单元格里
     上一行一个孤零零的 RM。数额过大时脚本会改用无分位格式来省宽度。 */
  white-space: nowrap;
}
table.sched tbody tr:nth-child(even) { background: var(--sand); }

.btn-calc {
  display: block; width: 100%; margin-top: 1rem;
  background: var(--orange); color: #fff;
  border: none; border-radius: 10px; padding: 13px;
  font-family: var(--font-body); font-size: 15px; font-weight: 700;
  cursor: pointer;
  transition: background .12s;
}
.btn-calc:hover { background: var(--orange-hover); }
.btn-calc:active { transform: translateY(1px); }

.toggle {
  display: block; width: 100%; margin-top: 1rem;
  background: var(--sand); border: 1.5px solid var(--input-border); border-radius: 10px;
  padding: 11px; cursor: pointer;
  font-family: var(--font-body); font-size: 13.5px; font-weight: 600; color: #444;
}
.toggle:hover { border-color: var(--orange-light); color: var(--orange); }
.monthly-wrap { margin-top: 1rem; }
.is-hidden { display: none !important; }

/* ————— footer ————— */
.site-footer { margin-top: 1.4rem; padding: 0 .2rem; }
.site-footer p { font-size: 11.5px; color: var(--muted); line-height: 1.7; }

/* ————— 过渡：改输入时图形平滑变化，webinar 演示用 ————— */
@media (prefers-reduced-motion: no-preference) {
  .chart-wrap rect { transition: height .18s ease, y .18s ease; }
  .donut-wrap path { transition: d .18s ease; }
}

/* 期末余额缺陷修复："RM" 不能和数字断行。单列布局一直持续到 900px 断点
   （见上面 `@media (min-width: 900px)` 才切两栏），所以保护范围要覆盖整个
   900px 以下的单列区间，不能只缩在 ≤480px——480–900px 之间同样是单列，
   同样会在大额数值下把 "RM" 单独挤到一行。nowrap 保证永不出现这种断法；
   万一输入逼近字段上限（1e12 本金量级，13 位数字）导致仍然放不下，盒子
   自身横向可滑动（和下面的明细表一个模式），绝不会把 body 撑出横向滚动条。 */
@media (max-width: 899px) {
  .end-value {
    white-space: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

@media (max-width: 480px) {
  body { padding: 1rem .75rem 2.5rem; }
  .card { padding: 1.1rem 1rem; border-radius: 14px; }
  .head-row h1 { font-size: 1.45rem; }
  .table-tall { max-height: 320px; }

  /* 窄屏进一步把字号收紧到更保守的区间，只是为了让常见量级更从容地
     放下，不是 nowrap 保护本身——那部分已经在上面的 899px 断点里处理了。 */
  .end-value {
    font-size: clamp(1.3rem, 7vw, 1.9rem);
  }
}
