/* 酒酷 sharp1 — pixel-quality + refinement layer (loaded LAST). Presentation only: no layout / logic / data changes.
   1. text: legibility rendering, no permanent GPU layers that freeze a low raster scale (the main blur cause)
   2. hairlines: 1 *device* pixel borders instead of 2px-thick 1 CSS px at DPR 2-3
   3. vector icon system (SVG sprite in index.html) + keypad backspace glyph
   4. natural spring easings (CSS linear()) and refined press states (transform/opacity only)  */
:root{
  --hair:1px;
  --ic-accent:#C98F1E;
  --spring:cubic-bezier(.34,1.3,.64,1);
  --hig-spring:cubic-bezier(.34,1.25,.64,1);
  --press-in:.075s;
}
@media (min-resolution:1.5dppx){:root{--hair:.5px}}
@media (min-resolution:2.25dppx){:root{--hair:.38px}}
@media (min-resolution:3.25dppx){:root{--hair:.3px}}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--ic-accent:#FFD66B}}
[data-theme=dark]{--ic-accent:#FFD66B}
@supports (transition-timing-function:linear(0,1)){
  :root{
    --spring:linear(0,.1102,.335,.5688,.7611,.8967,.9796,1.0219,1.0372,1.037,1.0297,1.0205,1.0122,1.006,1.002,.9997,.9987,.9985,.9987,.9991,.9994,.9997,.9999,1);
    --hig-spring:linear(0,.186,.492,.7385,.8914,.9696,1.0019,1.0107,1.01,1.0067,1.0037,1.0016,1.0005,1.0001,.9999,1);
  }
}

/* ---- 1. text sharpness ---- */
html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;font-kerning:normal;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{font-optical-sizing:auto}
canvas{image-rendering:auto}
img,svg{image-rendering:auto}
/* permanent will-change:transform kept every button/row/title on its own layer rasterised at the *initial* scale, so after a press/spring (scale .96→1) the text stayed resampled = soft.
   Promote only while the element is actually moving. */
.btn,.icon-btn,.fab,.key,.cat,.tabs a,.seg span,.seg.mini button,.entry button,.emopick button,.rwrap .rrow,#app>h2,#app>.herow h2{will-change:auto}
.btn:active,.icon-btn:active,.fab:active,.key:active,.cat:active,.tabs a:active,.seg.mini button:active,.emopick button:active,.entry button:active,.seg label:active span{will-change:transform}
/* small controls are ~opaque already: their own backdrop-filter only cost GPU time (and per-frame re-blur during press animations) */
.btn,.icon-btn,.key,.cat,.entry button,.seg span,.emopick button,.sync{-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
.sync{background:color-mix(in srgb,var(--bg) 88%,transparent)}
/* sharper type on the surfaces that carry numbers */
.kpi .v,.amtbox b,.cf-card .big,.key{font-variant-numeric:tabular-nums lining-nums;font-feature-settings:"tnum" 1,"lnum" 1}
.card h3,.kpi .l{text-rendering:optimizeLegibility}

/* ---- 2. retina hairlines ---- */
.card,.kpi,.btn,.icon-btn,.sync,.cat,.key,.emo,.pill,.tabs,.edgeind,.ptr-c,.cf-est,.warn,.seg,.seg span,.seg button,.entry button,.emopick button,.hig-tip,.toast,.undo,.install-pill,.ctx-menu,select,input:not([type=checkbox]):not([type=radio]),textarea,dialog:not(.hig-wheel):not(.hig-as){border-width:var(--hair)!important}
.top{border-bottom-width:var(--hair)!important}
.sb-brand{border-bottom-width:var(--hair)!important}
.card,.kpi{box-shadow:var(--shadow),var(--u3-card-edge,inset 0 1px 0 rgba(255,255,255,.9)),0 1px 1px rgba(90,58,30,.05)}

/* ---- 3. vector icons ---- */
.ic{display:inline-block;width:1.25em;height:1.25em;flex:none;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;vertical-align:-.22em;overflow:visible;shape-rendering:geometricPrecision}
.ic .f{fill:currentColor;fill-opacity:.16;stroke:none}
.ic .a{stroke:var(--ic-accent);}
.ic .af{fill:var(--ic-accent);stroke:none}
.ic .s{fill:currentColor;stroke:none}
.tabs a i{display:grid;place-items:center;height:1.35em}
.tabs a i .ic{width:1.2em;height:1.2em;vertical-align:baseline;transition:transform .45s var(--spring)}
.tabs a.on i .ic{transform:translateY(-1px) scale(1.06)}
.tabs a.on i .ic .a,.tabs a.on i .ic .af{stroke:#FFD66B}.tabs a.on i .ic .af{fill:#FFD66B}
.tabs a.on i .ic .f{fill-opacity:.28}
html[data-device=tablet] .tabs a i{height:auto}
html[data-device=tablet] .tabs a i .ic{width:1.05em;height:1.05em}
.icon-btn .ic{width:22px;height:22px;vertical-align:middle}
h3 .ic,.warn .ic,.nm .ic,.row .ic,b .ic{width:1.1em;height:1.1em;vertical-align:-.2em;margin-right:.18em}
.btn .ic{width:1.1em;height:1.1em;vertical-align:-.2em;margin-right:.2em}
.warn .ic,.neg .ic{color:var(--out)}
.ctx-menu button span .ic{width:20px;height:20px;vertical-align:middle}
/* keypad backspace: keep the ⌫ text node for logic/a11y, draw a vector glyph instead */
.key[data-k="⌫"]{font-size:0!important;color:var(--ink)}
.key[data-k="⌫"]::before{content:"";display:block;width:26px;height:26px;margin:auto;background:currentColor;-webkit-mask:var(--bs) center/contain no-repeat;mask:var(--bs) center/contain no-repeat;
  --bs:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 6.5A1.5 1.5 0 0 0 19.5 5H9L3 12l6 7h10.5a1.5 1.5 0 0 0 1.5-1.5z'/%3E%3Cpath d='M12.5 9.5l5 5M17.5 9.5l-5 5'/%3E%3C/svg%3E")}

/* ---- 4. refined press states + natural motion ---- */
.btn,.icon-btn,.fab,.key,.cat,.seg.mini button,.emopick button,.tabs a,.entry button{transition:transform .42s var(--spring),box-shadow .28s var(--ease),background-color .22s var(--ease),filter .22s var(--ease),opacity .2s var(--ease)}
.btn:active,.icon-btn:active,.fab:active,.key:active,.cat:active,.seg.mini button:active,.emopick button:active,.seg label:active span{transform:scale(.965);transition-duration:var(--press-in),.12s,.1s,.1s,.1s;filter:brightness(.97)}
.tabs a:active{transform:scale(.93);transition-duration:var(--press-in)}
.entry button:active{transform:scale(.9);transition-duration:var(--press-in)}
.key:active{box-shadow:inset 0 2px 4px rgba(90,58,30,.14)}
.fab:active{transform:scale(.94)}
@media (hover:hover){.btn:hover,.icon-btn:hover,.cat:hover,.key:hover{filter:brightness(1.015)}}
/* entrance: land on whole pixels (final frame is transform:none) and ease like a spring-settle, not a linear slide */
@keyframes rise{from{opacity:0;transform:translate3d(0,12px,0)}to{opacity:1;transform:none}}
@keyframes itemIn{from{opacity:0;transform:translate3d(0,12px,0) scale(.975)}to{opacity:1;transform:none}}
@keyframes sheet{from{transform:translate3d(0,36px,0);opacity:0}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){.btn:active,.icon-btn:active,.key:active,.cat:active,.fab:active,.tabs a:active,.entry button:active{transform:none}.tabs a.on i .ic{transform:none}}

/* ---- calculator process display (record keypad + amount sheet): expression line above the amount, result below, same field ---- */
.amtbox{flex-wrap:wrap;row-gap:2px}
.amtbox .calc-x{position:static;order:-1;flex:0 0 100%;max-width:100%;box-sizing:border-box;text-align:right;direction:ltr;font-size:1.125rem;line-height:1.35;font-weight:600;letter-spacing:0;
  color:var(--ink);opacity:0;min-height:1.35em;max-height:2.7em;overflow-x:hidden;overflow-y:auto;white-space:normal;overflow-wrap:anywhere;word-break:break-all;overscroll-behavior:contain;scrollbar-width:none;pointer-events:auto;font-variant-numeric:tabular-nums;transition:opacity .18s var(--ease)}
.amtbox .calc-x::-webkit-scrollbar{display:none}
.amtbox .calc-x.on{opacity:.82}
.amtbox.has-op b::before{content:"=\00a0";font-size:.55em;font-weight:700;color:var(--mut);letter-spacing:0;vertical-align:.18em}
.amtbox.has-op b{color:var(--ink)}
@media(max-height:760px){.amtbox .calc-x{font-size:1rem;min-height:1.3em}}

/* ---- month/record rows: never squeeze the title into a 0-24px column (vertical, one-char-per-line text).
   emo(40)+date(44)+title+amount+2 buttons(48) needs ~400px; narrower cards now wrap amount + action buttons to a second line. ---- */
.entry{flex-wrap:wrap;row-gap:4px}
.entry .m{flex:1 1 9.5em;min-width:9.5em}
.entry .amt{margin-left:auto}
.entry .nm,.entry .meta span,.entry .m{writing-mode:horizontal-tb;word-break:normal}
.entry .meta span{white-space:nowrap}
.entry .meta{row-gap:4px}
@media(max-width:480px){.card{padding-left:18px;padding-right:18px}.entry{gap:8px}.entry .d{width:36px}.entry .emo{width:36px;height:36px}}

.pill.s-已入帳,.pill.s-已繳{color:#1a6c41}
[data-theme=dark] .pill.s-已入帳,[data-theme=dark] .pill.s-已繳{color:var(--in)}
@media(prefers-color-scheme:dark){:root:not([data-theme=light]) .pill.s-已入帳,:root:not([data-theme=light]) .pill.s-已繳{color:var(--in)}}

/* ---- ux1: 8pt tokens (4/8 multiples), states ---- */
:root{--sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:24px;--sp-6:32px;--sp-7:48px;--r-1:8px;--r-2:16px;--r-3:24px;--r-pill:999px;--dur-fast:.15s;--dur:.2s;--dur-slow:.3s;--ease-out:cubic-bezier(.2,.7,.2,1);--solid-t:#fff9f0;--fs-title:22px;--fs-sec:17px;--fs-body:15px;--fs-help:12px}
.btn:active,.icon-btn:active,.fab:active,.key:active,.cat:active,.seg.mini button:active,.emopick button:active,.seg label:active span{transform:scale(.97)}
.chip,select,input,.seg span{transition-duration:var(--dur);transition-timing-function:var(--ease-out)}
.empty{gap:var(--sp-2)}.empty .note{font-size:var(--fs-body);line-height:1.5;max-width:28em}
.empty-cta{margin-top:var(--sp-2);min-height:44px;display:inline-flex;align-items:center;justify-content:center;padding:0 var(--sp-5);text-decoration:none}
.btn[disabled],.btn.busy{opacity:.55;pointer-events:none}
input[aria-invalid=true],select[aria-invalid=true]{border-color:var(--out,#c0344a)!important;box-shadow:0 0 0 3px rgba(192,52,74,.14)}
.fld-err{color:var(--out,#a82a40);font-size:var(--fs-help);line-height:1.4;margin:var(--sp-1) 0 var(--sp-2)}
.sync.can-retry{cursor:pointer;min-height:32px;text-decoration:underline dotted;text-underline-offset:3px}
.sync.can-retry:active{transform:scale(.97)}
.sync.retrying{opacity:.6}
@keyframes ux-sh{to{background-position:-200% 0}}
#app:empty{min-height:60vh;padding:var(--sp-4)}
#app:empty::before{content:"";display:block;height:176px;border-radius:var(--r-3);margin-bottom:var(--sp-4);background:linear-gradient(90deg,rgba(150,110,60,.08) 25%,rgba(150,110,60,.18) 37%,rgba(150,110,60,.08) 63%) 0 0/200% 100%;animation:ux-sh 1.4s linear infinite}
#app:empty::after{content:"";display:block;height:240px;border-radius:var(--r-3);background:linear-gradient(90deg,rgba(150,110,60,.08) 25%,rgba(150,110,60,.18) 37%,rgba(150,110,60,.08) 63%) 0 0/200% 100%;animation:ux-sh 1.4s linear infinite}
@media(prefers-reduced-motion:reduce){#app:empty::before,#app:empty::after{animation:none}}
