/* Chart.js sets an explicit pixel width on <canvas> based on its container at creation
   time; if that measurement ever races ahead of CSS Grid settling on a track's final
   width (a real timing gotcha when a canvas shares a grid row with a sibling), the canvas
   keeps its oversized width and forces the whole row — and the page — to overflow
   horizontally. This is a blanket safety net so no chart can ever push a page wider than
   its container, on top of fixing the actual grid items with min-w-0 where this occurs. */
canvas {
  max-width: 100%;
}

.material-symbols-outlined {
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  font-size: 1.25rem;
  line-height: 1;
  vertical-align: middle;
  display: inline-block;
  user-select: none;
}
.icon-fill {
  font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}
.icon-sm { font-size: 1rem; }
.icon-md { font-size: 1.75rem; }
.icon-lg { font-size: 1.75rem; }
.icon-xl { font-size: 2.5rem; }

/* Slightly roomier vertical padding for form fields using Tailwind's py-2 (0.5rem) */
input.py-2,
select.py-2,
textarea.py-2 {
  padding-top: 0.625rem !important;
  padding-bottom: 0.625rem !important;
}

/* An icon-only button standing in as its own form field (e.g. the calculator trigger
   next to the amount field) — sized to be pixel-identical to a same-row text input, not
   just visually close. Scoped to this class specifically (not all button.py-2) so it
   doesn't affect ordinary text buttons elsewhere that happen to use py-2. */
.field-icon-btn {
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
}
.field-icon-btn .material-symbols-outlined {
  line-height: 1.25rem;
}

.input-icon-wrap {
  position: relative;
}
.input-icon-wrap .material-symbols-outlined,
.input-icon-wrap .input-prefix {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  color: #94a3b8;
  font-size: 1.15rem;
  pointer-events: none;
}
.input-icon-wrap .input-prefix {
  font-size: 0.875rem;
  font-weight: 600;
  font-family: inherit;
}
.input-icon-wrap input,
.input-icon-wrap select,
.input-icon-wrap textarea {
  padding-left: 2.5rem;
}
.input-icon-wrap .input-icon-right {
  left: auto;
  right: 0.75rem;
  cursor: pointer;
  pointer-events: auto;
}
.input-icon-wrap input.has-right-icon {
  padding-right: 2.5rem;
}

/* App-wide borderless field style, matching the redesigned Catat Manual modal
   (includes/modal_add_transaction.php) — every field still using the older bordered-white
   look (class="... border border-slate-300 rounded-lg/rounded-full ...") picks this up
   automatically, without needing to touch each individual form's markup. Dark-mode
   background is already handled by the broader `html.dark input/select/textarea` rule
   below; this only needs to also drop the visible border there. */
input.border-slate-300.rounded-lg,
select.border-slate-300.rounded-lg,
textarea.border-slate-300.rounded-lg {
  background-color: #f8fafc;
  border-color: transparent;
  border-radius: 0.75rem;
}
input.border-slate-300.rounded-full,
select.border-slate-300.rounded-full,
textarea.border-slate-300.rounded-full {
  background-color: #f8fafc;
  border-color: transparent;
}

.progress-track {
  background: #e2e8f0;
  border-radius: 9999px;
  overflow: hidden;
  height: 0.5rem;
}
.progress-fill {
  height: 100%;
  border-radius: 9999px;
  transition: width .3s ease;
}
.toast {
  animation: toast-in .2s ease-out;
}

/* PIN-lock keypad screen (includes/layout_app_start.php) — a handful of very specific
   layout/sizing values here aren't in the compiled Tailwind bundle, and this project has
   no npm/build step to regenerate it, so they live here instead, same as .progress-track
   and .icon-sm above. */
.pin-screen {
  padding: 3.5rem 1.5rem 2rem;
}
.pin-dot {
  width: 14px;
  height: 14px;
  border-radius: 9999px;
  border: 2px solid #cbd5e1;
  transition: background-color .15s ease, border-color .15s ease;
}
.pin-dot.filled {
  background: #266210;
  border-color: #266210;
}
.pin-dot.error {
  border-color: #e11d48;
}
.pin-key {
  padding: 1.1rem 0;
  border-radius: 1rem;
  font-size: 1.5rem;
  font-weight: 500;
  color: #334155;
  transition: background-color .1s ease;
}
.pin-key:active {
  background: #f1f5f9;
}
.pin-shake {
  animation: pin-shake .35s ease;
}
@keyframes pin-shake {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-8px); }
  40%, 80% { transform: translateX(8px); }
}

html.dark .pin-dot { border-color: #475569; }
html.dark .pin-dot.filled { background: #a4c52e; border-color: #a4c52e; }
html.dark .pin-dot.error { border-color: #fb7185; }
html.dark .pin-key { color: #cbd5e1; }
html.dark .pin-key:active { background: #263449; }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(.5rem); }
  to { opacity: 1; transform: translateY(0); }
}
@media print {
  .no-print { display: none !important; }
  body { background: #fff !important; }
}

@media (max-width: 1023.98px) {
  /* Long workspace names wrap to 2 lines in the header switcher on narrow viewports —
     keep it to one line with an ellipsis instead. Desktop has room, so left unconstrained
     there. Budget shrunk from 9rem to make room for the emoji prefix (plus its flex gap)
     added alongside this span — at 9rem the header's left and right groups together
     exceeded small phone viewports (~375px) and caused horizontal scroll site-wide. */
  .ws-name-truncate {
    display: inline-block;
    max-width: 6rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
  }

  .modal-backdrop {
    align-items: flex-end !important;
    padding: 0 !important;
    animation: sakuin-backdrop-in 0.2s ease-out;
  }
  .modal-backdrop > div {
    width: 100% !important;
    max-width: 100% !important;
    max-height: 88vh !important;
    margin: 0 !important;
    border-radius: 1.25rem 1.25rem 0 0 !important;
    padding-top: 2rem !important;
    overflow-y: auto !important;
    position: relative;
    animation: sakuin-sheet-up 0.28s cubic-bezier(0.32, 0.72, 0, 1);
  }
  .modal-backdrop > div::before {
    content: '';
    position: absolute;
    top: 0.65rem;
    left: 50%;
    transform: translateX(-50%);
    width: 2.5rem;
    height: 0.28rem;
    border-radius: 9999px;
    background: #e2e8f0;
  }

  .modal-backdrop > div.sheet-flex {
    display: flex;
    flex-direction: column;
    overflow-y: hidden !important;
  }
  .sheet-flex .sheet-header {
    flex-shrink: 0;
  }
  .sheet-flex .sheet-scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0;
  }
  .sheet-flex .sheet-footer {
    flex-shrink: 0;
    position: sticky;
    bottom: 0;
    background: #fff;
    padding-top: 0.75rem;
    box-shadow: 0 -6px 8px -4px rgba(0, 0, 0, 0.06);
  }
}
@keyframes sakuin-sheet-up {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}
@keyframes sakuin-backdrop-in {
  from { background-color: rgba(0, 0, 0, 0); }
  to { background-color: rgba(0, 0, 0, 0.4); }
}

.chat-bubble-80 { max-width: 80%; }
.chat-bubble-85 { max-width: 85%; }
.chat-bubble-90 { max-width: 90%; }

.txn-success-card {
  animation: sakuin-success-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.txn-success-circle {
  stroke-width: 2.5;
  stroke: #1fab80;
  stroke-dasharray: 151;
  stroke-dashoffset: 151;
  animation: sakuin-check-circle 0.5s cubic-bezier(0.65, 0, 0.45, 1) forwards;
}
.txn-success-check {
  stroke-width: 3.5;
  stroke: #1fab80;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 36;
  stroke-dashoffset: 36;
  animation: sakuin-check-mark 0.35s cubic-bezier(0.65, 0, 0.45, 1) 0.45s forwards;
}
@keyframes sakuin-check-circle {
  to { stroke-dashoffset: 0; }
}
@keyframes sakuin-check-mark {
  to { stroke-dashoffset: 0; }
}
@keyframes sakuin-success-pop {
  from { opacity: 0; transform: scale(0.85); }
  to { opacity: 1; transform: scale(1); }
}

/* Article body content (public/article_detail.php) is raw admin-authored HTML with no
   utility classes of its own, so headings render visually identical to paragraphs — Tailwind's
   Preflight reset strips default heading font-size/weight/margin, and nothing else re-adds it. */
.prose-sakuin h2 {
  font-size: 1.25rem;
  font-weight: 700;
  color: #1e293b;
  line-height: 1.35;
  margin-top: 0.5rem;
}
.prose-sakuin h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  color: #1e293b;
  line-height: 1.4;
}
.prose-sakuin p { line-height: 1.75; }
.prose-sakuin ul,
.prose-sakuin ol { padding-left: 1.25rem; line-height: 1.75; }
.prose-sakuin ul { list-style: disc; }
.prose-sakuin ol { list-style: decimal; }
.prose-sakuin li { margin-bottom: 0.375rem; }
.prose-sakuin strong { font-weight: 700; color: #1e293b; }
.prose-sakuin blockquote {
  border-left: 3px solid var(--color-brand-500);
  padding-left: 1rem;
  color: #475569;
  font-style: italic;
}
.prose-sakuin a { color: var(--color-brand-700); text-decoration: underline; }

/* ===== Dark mode ===== */
html.dark body { background-color: #0b1220 !important; color: #e2e8f0 !important; }

html.dark .prose-sakuin h2,
html.dark .prose-sakuin h3,
html.dark .prose-sakuin strong { color: #e2e8f0 !important; }
html.dark .prose-sakuin blockquote { color: #b0bdcf !important; }
html.dark .prose-sakuin a { color: #bad361 !important; }

html.dark .bg-white { background-color: #1a2436 !important; }
html.dark .bg-slate-50 { background-color: #202b40 !important; }
html.dark .bg-slate-100 { background-color: #283449 !important; }
html.dark .bg-slate-200 { background-color: #384457 !important; }
html.dark .hover\:bg-slate-50:hover { background-color: #202b40 !important; }
html.dark .hover\:bg-slate-100:hover { background-color: #283449 !important; }
html.dark .hover\:bg-slate-200:hover { background-color: #384457 !important; }

html.dark .border-slate-50 { border-color: #202b40 !important; }
html.dark .border-slate-100 { border-color: #263449 !important; }
html.dark .border-slate-200 { border-color: #334155 !important; }
html.dark .border-slate-300 { border-color: #475569 !important; }
html.dark .divide-slate-50 > :not([hidden]) ~ :not([hidden]) { border-color: #263449 !important; }
html.dark .divide-slate-100 > :not([hidden]) ~ :not([hidden]) { border-color: #334155 !important; }

html.dark .text-slate-900 { color: #f1f5f9 !important; }
html.dark .text-slate-800 { color: #e2e8f0 !important; }
html.dark .text-slate-700 { color: #cbd5e1 !important; }
html.dark .text-slate-600 { color: #b0bdcf !important; }
html.dark .text-slate-500 { color: #94a3b8 !important; }
html.dark .text-slate-400 { color: #7487a0 !important; }
html.dark .text-slate-300 { color: #556275 !important; }

html.dark .bg-brand-50 { background-color: rgba(164, 197, 46, 0.14) !important; }
html.dark .bg-rose-50 { background-color: rgba(244, 63, 94, 0.14) !important; }
html.dark .bg-amber-50 { background-color: rgba(245, 158, 11, 0.14) !important; }
html.dark .bg-sky-50 { background-color: rgba(14, 165, 233, 0.14) !important; }
html.dark .bg-gold-50 { background-color: rgba(255, 222, 78, 0.14) !important; }
html.dark .border-brand-200 { border-color: rgba(164, 197, 46, 0.35) !important; }
html.dark .border-rose-200 { border-color: rgba(244, 63, 94, 0.35) !important; }
html.dark .border-amber-200 { border-color: rgba(245, 158, 11, 0.35) !important; }
html.dark .border-sky-200 { border-color: rgba(14, 165, 233, 0.35) !important; }

html.dark .text-brand-600 { color: #a4c52e !important; }
html.dark .text-brand-700 { color: #bad361 !important; }
html.dark .text-rose-600 { color: #fb7185 !important; }
html.dark .text-rose-700 { color: #fda4af !important; }
html.dark .text-amber-600 { color: #fbbf24 !important; }
html.dark .text-amber-700 { color: #fcd34d !important; }
html.dark .text-sky-600 { color: #38bdf8 !important; }
html.dark .text-sky-700 { color: #7dd3fc !important; }
html.dark .text-gold-600 { color: #ffde4e !important; }
html.dark .text-gold-700 { color: #ffe575 !important; }

html.dark input:not([type="checkbox"]):not([type="radio"]),
html.dark select,
html.dark textarea {
  background-color: #1a2436 !important;
  color: #e2e8f0 !important;
}
html.dark input::placeholder,
html.dark textarea::placeholder { color: #64748b !important; }
html.dark .bg-slate-50\/50 { background-color: rgba(32, 43, 64, 0.5) !important; }
html.dark input.border-slate-300,
html.dark select.border-slate-300,
html.dark textarea.border-slate-300 { border-color: transparent !important; }

html.dark .progress-track { background: #2d3b52 !important; }
html.dark .modal-backdrop > div::before { background: #475569 !important; }
html.dark .sheet-flex .sheet-footer { background: #1a2436 !important; }
html.dark ::-webkit-scrollbar-thumb { background-color: #334155; }

/* Dashboard balance card's investment/net worth strip (public/dashboard.php) — this
   exact gold isn't a compiled Tailwind utility (no npm build step here), so it's
   hand-written, same reasoning as .progress-track above. */
.balance-invest-strip {
  background: #e1e100;
}
.collapse-chevron {
  transition: transform 0.15s ease;
}
[aria-expanded="true"] .collapse-chevron {
  transform: rotate(180deg);
}

/* Dashboard's mobile/tablet menu tabs (public/dashboard.php) — the tab bar and icon row
   scroll horizontally when they don't fit, but a visible scrollbar there reads as a
   layout glitch rather than an intentional swipe gesture. Not a compiled Tailwind
   utility, so hand-written like the rest of this section. */
.no-scrollbar {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.no-scrollbar::-webkit-scrollbar {
  display: none;
}

/* App sidebar (includes/layout_app_start.php) — hidden below lg (mobile/tablet use the
   menu tabs on the dashboard instead, see .no-scrollbar above), flex at lg+. Plain
   "hidden lg:flex" isn't in the compiled Tailwind bundle since nothing else in the app
   used that exact pair before, so it's hand-written like the rest of this section. */
#sidebar {
  display: none;
}
@media (min-width: 1024px) {
  #sidebar {
    display: flex;
  }
}

/* Dompet page's ATM-style wallet cards (public/wallets.php) — white-on-color text/icon
   opacity variants the compiled Tailwind bundle doesn't have (no npm build step here), same
   reasoning as the rest of this section. Card background itself is each wallet's provider
   color (or a brand/slate fallback), set inline per-card since it's a dynamic PHP value. */
.wallet-card-label {
  color: rgba(255, 255, 255, 0.75);
}
.wallet-card-sub {
  color: rgba(255, 255, 255, 0.85);
}
.wallet-card-menu-btn {
  color: rgba(255, 255, 255, 0.85);
}
.wallet-card-menu-btn:hover {
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
}
.wallet-card-icon-badge {
  background: rgba(255, 255, 255, 0.2);
}

/* Shared "ATM card" ornament: a dot-grid texture fading in from the top-right corner plus
   a soft glare circle bottom-left, so a flat color fill reads as embossed. Used by the
   Dompet wallet cards (.wallet-atm-card) and the dashboard's "Total Saldo" card
   (.dashboard-balance-card) — both are solid/gradient colored cards on white text.
   The card itself (not its children) establishes the stacking context via z-index: 0, and
   the pseudo-elements sit at z-index: -1 within it — that way ordinary static content (the
   wallet's dropdown menu included) naturally paints above the ornament without needing its
   own position/z-index, which previously gave every direct child its own stacking context
   and made a later sibling (the balance amount) paint over an earlier one's dropdown menu. */
.wallet-atm-card,
.dashboard-balance-card {
  position: relative;
  z-index: 0;
  overflow: hidden;
}
.wallet-atm-card::before,
.dashboard-balance-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: radial-gradient(rgba(255, 255, 255, 0.16) 1.2px, transparent 1.2px);
  background-size: 14px 14px;
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 85% 15%, #000 40%, transparent 75%);
  mask-image: radial-gradient(ellipse 80% 70% at 85% 15%, #000 40%, transparent 75%);
}
.wallet-atm-card::after,
.dashboard-balance-card::after {
  content: '';
  position: absolute;
  z-index: -1;
  width: 220px;
  height: 220px;
  left: -60px;
  bottom: -80px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
}

/* Wallet card's own gradient fill + tinted shadow (provider color -> darker shade, both
   from PHP via --card-c1/--card-c2/--card-shadow-rgb) — the dashboard balance card keeps
   its existing Tailwind bg-gradient-to-br utility instead, so this stays wallet-only. */
.wallet-atm-card {
  background: linear-gradient(160deg, var(--card-c1), var(--card-c2));
  box-shadow: 0 10px 24px -10px rgba(var(--card-shadow-rgb), 0.45);
}

/* Floating "pill" bottom nav (includes/layout_app_end.php) — detaches the bar from the
   screen edge with side/bottom margin and large corner radius instead of sitting flush
   against the bottom edge; safe-area-inset is baked into the bottom offset here (rather
   than as padding) since the bar no longer touches the edge itself. */
#bottom-nav {
  left: 12px;
  right: 12px;
  bottom: calc(14px + env(safe-area-inset-bottom));
  border-radius: 22px;
  background: linear-gradient(160deg, #266210, #144d07);
  box-shadow: 0 12px 28px -10px rgba(20, 40, 10, 0.45);
}

/* Bottom nav item/FAB colors, matching the dashboard balance card's own palette: white
   (active) / translucent white (inactive) text on the bar's brand-green fill, and the
   FAB reuses the balance card's investment-strip color (#e1e100) with its dark-green
   text (#063b00) for contrast, same pairing as that strip already uses. */
.bottom-nav-item {
  color: rgba(255, 255, 255, 0.6);
}
.bottom-nav-item.active {
  color: #ffffff;
}
.bottom-nav-fab {
  background: #e1e100;
  color: #063b00;
  box-shadow: 0 8px 18px -4px rgba(225, 225, 0, 0.5);
}
