/* 月账 · Monthly Ledger — app.css
   Small custom layer over Bootstrap 5.3. Adjusts spacing, card tiers, and
   the sidebar/nav only — everything else stays default Bootstrap.
   Tokens and component styles below are carried over from the reviewed
   design (sample.html). The budget progress bar and month-nav arrows are
   added in Phase 8 / Phase 5 — not present yet. */

:root{
  --ink:#20242e;
  --ink-2:#4a5163;
  --muted:#7b8398;
  --bg:#f4f5fa;
  --card:#ffffff;
  --line:#e6e8f0;
  --accent:#5a5bd8;
  --accent-ink:#4345b8;
  --accent-soft:#eeeffc;
  --hero-a:#fbfbff;
  --hero-b:#f0f1fe;
  --hero-line:#dcdef8;
  --track:#eef0f5;
  --good:#178a50;
  --r-lg:20px;
  --r-md:14px;
}

html,body{background:var(--bg);color:var(--ink);}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Helvetica Neue",Arial,sans-serif;}
.tnum{font-variant-numeric:tabular-nums;}

.card-x{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);
        box-shadow:0 1px 2px rgba(23,25,60,.04);}
.sec-title{font-size:.95rem;font-weight:700;letter-spacing:-.01em;}
.sec-sub{font-size:.78rem;color:var(--muted);}

/* Hero tier: tinted + lifted, reserved for the highest-priority cards
   (Add Expense form — Phase 3; income.php's summary strip). */
.card-summary{background:linear-gradient(180deg,#f9f9ff,#f2f2fd);border:1px solid var(--hero-line);
              border-radius:var(--r-lg);box-shadow:0 6px 18px -12px rgba(74,76,200,.35),0 1px 2px rgba(23,25,60,.04);}

/* ============ Dashboard month summary — dark "Bold Balance Card" +
   radial budget ring (design review: combined options 2 + 3). Solid
   indigo, white type, and a ring instead of a linear bar. Scoped child
   overrides below repoint the shared .kicker/.mini-nav/.text-secondary/
   .text-body/.link-quiet rules (used elsewhere in light mode) to
   readable colors on this dark background — those shared rules
   themselves are untouched, so every other page keeps its light look. */
.card-summary-dark{border-radius:var(--r-lg);color:#fff;
  background:linear-gradient(135deg,#5a5bd8,#4038b0 65%,#372f9e);
  box-shadow:0 16px 36px -14px rgba(55,47,158,.55),0 1px 2px rgba(23,25,60,.05);}
.card-summary-dark .kicker{color:rgba(255,255,255,.72);}
.card-summary-dark .spent-big{color:#fff;}
.card-summary-dark .text-secondary{color:rgba(255,255,255,.72)!important;}
.card-summary-dark .text-body{color:#fff!important;}
.card-summary-dark .link-quiet{color:#fff;text-decoration:underline;}
.card-summary-dark .mini-nav{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.28);color:#fff;}
.card-summary-dark .mini-nav:hover{background:rgba(255,255,255,.2);border-color:rgba(255,255,255,.4);}
.card-summary-dark .cs-divider{border-top:1px solid rgba(255,255,255,.18);}
.card-summary-dark #bdtEquivalent{color:rgba(255,255,255,.6);}
.card-summary-dark .cs-good{color:#8ff0c0;}
.card-summary-dark .cs-good[data-over="1"]{color:#ff9eb0;}

.cs-ring-wrap{position:relative;flex:0 0 auto;width:64px;height:64px;margin-right:.9rem;}
.cs-ring-wrap svg{width:64px;height:64px;}
.cs-ring-track{stroke:rgba(255,255,255,.22);}
.cs-ring-fill{stroke:#fff;transition:stroke-dashoffset .4s ease;}
.cs-ring-fill.over{stroke:#ff9eb0;}
.cs-ring-label{position:absolute;inset:0;display:grid;place-items:center;font-size:.82rem;font-weight:800;color:#fff;}
.cs-ring-label.over{color:#ff9eb0;}

/* ============ Sidebar (desktop) + offcanvas (mobile) ============ */
.sidebar{position:fixed;inset:0 auto 0 0;width:260px;background:var(--card);
         border-right:1px solid var(--line);display:none;flex-direction:column;
         padding:1.25rem 1rem;z-index:1030;}
@media (min-width:992px){
  .sidebar{display:flex;}
  .app-main{margin-left:260px;}
}
.brand{display:flex;align-items:center;gap:.65rem;padding:.25rem .5rem 1rem;}
.brand-badge{width:36px;height:36px;border-radius:11px;background:var(--accent);color:#fff;
             display:grid;place-items:center;font-size:1.05rem;flex:0 0 auto;}
.brand-name{font-weight:700;letter-spacing:-.01em;}
.side-link{display:flex;align-items:center;gap:.75rem;padding:.6rem .75rem;margin:.1rem 0;
           border-radius:10px;color:var(--ink);text-decoration:none;font-size:.95rem;font-weight:500;}
.side-link i{font-size:1.05rem;color:var(--muted);width:1.25rem;text-align:center;}
.side-link:hover{background:#f3f4f9;color:var(--ink);}
.side-link.active{background:var(--accent-soft);color:var(--accent-ink);}
.side-link.active i{color:var(--accent-ink);}
.side-footer{margin-top:auto;border-top:1px solid var(--line);padding-top:.5rem;}
.side-footer .side-link{font-size:.86rem;padding:.4rem .75rem;margin:0;}
.side-footer .side-link i{font-size:1rem;}

/* ============ Quiet top bar ============ */
.topbar{position:sticky;top:0;z-index:1020;background:rgba(244,245,250,.9);backdrop-filter:blur(8px);}
.topbar-inner{display:flex;align-items:center;gap:.75rem;padding:.65rem 0;}
.icon-btn{width:38px;height:38px;border-radius:12px;border:1px solid var(--line);
          background:var(--card);color:var(--ink);display:grid;place-items:center;}
.icon-btn:hover{background:#f3f4f9;}
.avatar{width:32px;height:32px;border-radius:50%;background:var(--accent-soft);
        color:var(--accent-ink);display:grid;place-items:center;font-weight:700;font-size:.85rem;}

/* ============ Form controls + primary action button ============
   Global rules (not hero-specific) so login and every later form share
   the same look with no extra classes. */
.form-control,.form-select{border-color:var(--line);border-radius:12px;padding:.55rem .8rem;background:#fff;}
.form-control:focus,.form-select:focus{border-color:var(--accent);box-shadow:0 0 0 4px rgba(90,91,216,.14);}

.btn-accent{background:var(--accent);border:0;color:#fff;border-radius:14px;
            padding:.75rem 1rem;font-weight:700;font-size:1rem;
            box-shadow:0 6px 16px -8px rgba(74,76,200,.55);}
.btn-accent:hover{background:var(--accent-ink);color:#fff;}
.btn-accent:focus-visible{outline:2px solid var(--accent-ink);outline-offset:2px;}

.field-label{font-size:.78rem;font-weight:700;color:var(--ink-2);margin:.95rem 0 .45rem;}
.field-error{color:#dc3545;font-size:.78rem;margin-top:.35rem;}

/* ============ 1) HERO: Add expense ============ */
.hero{background:linear-gradient(180deg,var(--hero-a),var(--hero-b));
      border:1px solid var(--hero-line);border-radius:var(--r-lg);
      box-shadow:0 10px 28px -14px rgba(74,76,200,.28),0 2px 4px rgba(23,25,60,.05);
      padding:1.1rem 1.1rem 1.25rem;}
@media (min-width:992px){.hero{padding:1.5rem;}}
.hero-title{display:flex;align-items:center;gap:.5rem;font-weight:700;margin-bottom:.9rem;}
.hero-title i{color:var(--accent);}

.amount-wrap{background:#fff;border:1.5px solid var(--hero-line);border-radius:16px;
             display:flex;align-items:baseline;gap:.55rem;padding:.55rem 1rem;}
.amount-wrap:focus-within{border-color:var(--accent);box-shadow:0 0 0 4px rgba(90,91,216,.14);}
.amount-wrap.has-error{border-color:#dc3545;box-shadow:0 0 0 4px rgba(220,53,69,.12);}
.amount-cur{font-size:1.5rem;font-weight:700;color:var(--accent-ink);}
.amount-in{border:0;outline:0;width:100%;background:transparent;font-size:2.35rem;
           font-weight:800;letter-spacing:-.02em;color:var(--ink);}
.amount-in::placeholder{color:#c6cbe0;font-weight:700;}
#desc::placeholder,#editDesc::placeholder{color:#b7bccc;}

/* Uniform category grid: equal tiles, equal gaps, one-line labels */
.cat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;}
.cat{display:flex;flex-direction:column;align-items:center;gap:.4rem;
     padding:.7rem .25rem .6rem;border-radius:var(--r-md);
     background:#fff;border:1.5px solid var(--line);cursor:pointer;}
.cat:hover{border-color:#c9cde4;}
.cat:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.cat-ic{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;font-size:1.05rem;
        background:color-mix(in srgb,var(--c) 14%,#fff);color:var(--c);}
.cat-name{font-size:.72rem;font-weight:600;color:var(--ink-2);line-height:1;white-space:nowrap;}
.cat.selected{border-color:var(--accent);box-shadow:0 0 0 3px rgba(90,91,216,.15);}
.cat.selected .cat-name{color:var(--accent-ink);}
.cat-more .cat-ic{background:#eef0f5;color:var(--muted);}

/* Small color-only dot (no icon) — used by budgets.php's category list and
   reports.php's Planned/Actual table, which are denser, table-like layouts
   where a full icon circle would be too heavy. Kept distinct from the
   dashboard's icon-circle treatment (.hrow-ic, .cat-ic, .tx-ic) on purpose. */
.hdot{width:9px;height:9px;border-radius:3px;background:var(--c);flex:0 0 auto;align-self:center;}

.btn-save{background:var(--accent);border:0;color:#fff;border-radius:14px;width:100%;
          padding:.85rem 1rem;font-weight:700;font-size:1.02rem;margin-top:1.1rem;
          box-shadow:0 6px 16px -8px rgba(74,76,200,.55);}
.btn-save:hover{background:var(--accent-ink);color:#fff;}
.btn-save:disabled{opacity:.7;}
.btn-save:focus-visible{outline:2px solid var(--accent-ink);outline-offset:2px;}

/* ============ 2) Month summary ============ */
.kicker{font-size:.72rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);}
.spent-big{font-size:1.9rem;font-weight:800;letter-spacing:-.02em;line-height:1.15;}
.mini-nav{width:32px;height:32px;border-radius:10px;border:1px solid var(--line);background:#fff;
          color:var(--muted);display:grid;place-items:center;text-decoration:none;flex:0 0 auto;}
.mini-nav:hover{color:var(--accent-ink);border-color:var(--accent);}

/* ============ 3) Spending by category — horizontal bars ============ */
.hrow{padding:.55rem 0;display:flex;align-items:flex-start;gap:.65rem;}
.hrow + .hrow{border-top:1px dashed var(--line);}
.hrow-ic{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;font-size:1rem;
        flex:0 0 auto;background:color-mix(in srgb,var(--c) 14%,#fff);color:var(--c);}
.hrow-body{flex:1;min-width:0;}
.hrow-top{display:flex;align-items:baseline;gap:.5rem;margin-bottom:.35rem;}
.hname{font-size:.86rem;font-weight:600;}
.hamt{margin-left:auto;font-weight:700;font-size:.9rem;white-space:nowrap;}
.hpct{font-size:.75rem;color:var(--muted);width:3.2rem;text-align:right;}
.htrack{height:8px;border-radius:99px;background:var(--track);overflow:hidden;}
.htrack>span{display:block;height:100%;border-radius:99px;background:var(--c);min-width:6px;}

/* Clickable variant of .hrow (This year's total → jump to that month),
   same hover/tap-target trick as .tx below. */
.hrow-link{color:inherit;text-decoration:none;padding-left:.5rem;padding-right:.5rem;
           margin:0 -.5rem;border-radius:12px;}
.hrow-link:hover{background:#f6f7fb;}
.hrow-link:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.hrow-ic-num{background:var(--accent-soft);color:var(--accent-ink);font-weight:800;font-size:.78rem;
             letter-spacing:.02em;}
.year-badge{background:var(--accent-soft);color:var(--accent-ink);font-weight:700;font-size:.76rem;
            border-radius:99px;padding:.22rem .55rem;}

/* ============ 4) Recent — secondary ============ */
.tx{display:flex;align-items:center;gap:.8rem;padding:.65rem .5rem;margin:0 -.5rem;
    border-radius:12px;cursor:pointer;}
.tx:hover{background:#f6f7fb;}
.tx:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.tx + .tx{border-top:1px solid var(--line);}
/* Someone else's expense, viewed by a non-admin (Sumona) — visible, but
   not clickable: she can see it, just can't open it to edit or delete. */
.tx-locked{cursor:default;}
.tx-locked:hover{background:none;}
.tx-ic{width:34px;height:34px;border-radius:12px;display:grid;place-items:center;font-size:.95rem;flex:0 0 auto;
       background:color-mix(in srgb,var(--c) 14%,#fff);color:var(--c);}
.tx-desc{font-weight:600;font-size:.92rem;line-height:1.25;}
.tx-meta{font-size:.76rem;color:var(--muted);}
.tx-amt{margin-left:auto;font-weight:700;white-space:nowrap;}
.link-quiet{font-size:.8rem;font-weight:600;color:var(--accent-ink);text-decoration:none;}
.link-quiet:hover{text-decoration:underline;}

/* ============ Report: Planned vs. actual — mobile stacked rows ============
   Same visual language as the dashboard's .hrow (icon-less version): one
   line per category instead of a 4-column table, which is what forced
   numbers to wrap mid-figure on narrow phones (Section 19's report page). */
.pv-row{padding:.6rem 0;}
.pv-row + .pv-row{border-top:1px dashed var(--line);}
.pv-top{display:flex;align-items:baseline;gap:.5rem;}
.pv-name{font-weight:600;font-size:.9rem;}
.pv-diff{margin-left:auto;font-weight:700;font-size:.9rem;white-space:nowrap;}
.pv-sub{font-size:.78rem;color:var(--muted);margin-top:.15rem;}
.pv-total{border-top:2px solid var(--line);margin-top:.1rem;padding-top:.75rem;}
.pv-total .pv-name,.pv-total .pv-diff{font-weight:800;font-size:.95rem;}

/* ============ Dashboard layout (Section 20) ============
   CSS Grid, not Bootstrap's row/col/order: those can only reorder whole
   columns as a block, but the mobile order (Summary, Add Expense, Chart,
   Recent) needs Summary pulled out from its desktop grouping with Chart/
   Recent independently — grid-template-areas does that per breakpoint. */
.dash-grid{display:grid;grid-template-columns:1fr;gap:1rem;
  grid-template-areas:"summary" "add" "chart" "recent" "yeartotal";}
.dash-add{grid-area:add;}
.dash-summary{grid-area:summary;}
.dash-chart{grid-area:chart;}
.dash-recent{grid-area:recent;}
.dash-yeartotal{grid-area:yeartotal;}

@media (min-width:992px){
  .dash-grid{grid-template-columns:5fr 7fr;column-gap:1.5rem;row-gap:1.5rem;
    grid-template-areas:"add summary" "add chart" "add recent" "yeartotal yeartotal";}
}

.sticky-col{position:sticky;top:76px;}

@media (prefers-reduced-motion: reduce){*{transition:none!important;animation:none!important;}}
