/* Global App Layout -- shared shell (sidebar, topbar/identity chip,
   filters, page structure) for Dashboard Area (index.html) and
   Organization (organization.html), per the approved mockup: navy
   sidebar with full icon+label nav, light content area, white cards.

   Scope: LAYOUT/CHROME + base component styling only. Business logic,
   API calls, RBAC gating and computed values are untouched -- this file
   only changes how existing elements/classes are painted and arranged.
   index.html keeps a small inline <style> block of its own for rules a
   pre-existing test suite asserts verbatim (amber/warning colors,
   pill-warn, alert-warning/neutral, unauth-state) -- those are
   deliberately NOT duplicated or overridden here to avoid two sources
   of truth for the same selector. */

@font-face{
  font-family:"Plus Jakarta Sans";
  src:url("/static/fonts/plus-jakarta-sans-variable.woff2") format("woff2-variations");
  font-weight:200 800;
  font-style:normal;
  font-display:swap;
}

:root{
  --font-utama:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;
  --fs-xs:14px; --fs-sm:15px; --fs-base:16px; --fs-md:18px;
  --fs-lg:20px; --fs-xl:24px; --fs-2xl:30px; --fs-hero:44px;

  /* Sidebar stays dark navy; content area/cards are light -- per the
     approved mockup, not a full dark theme. */
  --navy:#0B1E3D; --navy-light:#16294D;
  --blue:#1E56C8; --blue-soft:#E8EFFC;
  --bg:#F6F8FC; --card:#FFFFFF; --border:#E2E7F0;
  --text:#101828; --text-muted:#5B6472;
  --green:#1A8754; --green-bg:#E8F6EE;
  --amber:#B7791F; --amber-bg:#FDF3DF;
  --red:#C13333; --red-bg:#FBEAEA;
  --icon-badge-blue-bg:var(--blue-soft); --icon-badge-green-bg:var(--green-bg);

  --sidebar-width:232px;
  --sidebar-width-collapsed:76px;
}

*{box-sizing:border-box;}

/* THE hidden ATTRIBUTE HAS TO OUTRANK THE CLASS THAT PAINTS THE ELEMENT.
   `display:none` for [hidden] comes only from the browser's own stylesheet,
   and an author stylesheet always beats that -- so any class here that sets
   `display` (.form-field, .filters, .form-grid, .tabs, ... ) silently
   defeats el.hidden = true. The element carries the attribute and still
   renders, which is the worst shape a defect can take: the JavaScript reads
   correct, the screen is wrong, and instrumentation that asks for
   `el.hidden` agrees with the code instead of with the screen.
   See docs/TEMUAN_HIDDEN_TIDAK_MENGIKAT.md. */
[hidden]{display:none !important;}

body{margin:0;font-family:var(--font-utama);background:var(--bg);color:var(--text);font-size:var(--fs-base);}
input, select, textarea, button{font-family:inherit;font-size:var(--fs-base);}
a{color:inherit;}

/* ---- App shell / sidebar ---- */
.app{display:grid;grid-template-columns:var(--sidebar-width) 1fr;min-height:100vh;min-width:1100px;}
.sidebar{background:var(--navy);padding:8px 0 20px;display:flex;flex-direction:column;}
/* FALLBACK BRANDING -- not final. No approved reverse/white logo asset
   exists in this repo (checked static/img/ and the whole repo tree) --
   the real logo-nexa.webp has a dark wordmark meant for light
   backgrounds, illegible on this navy sidebar, so the image is left out
   entirely rather than shown unreadable or duplicated next to text.
   Plain white text carries the brand name here until a real
   reverse-color logo asset from NEXA is supplied -- swap it in (an
   <img> replacing/joining .brand-text) before this ships. */
.brand{height:64px;margin:0 12px;padding:0 14px;display:flex;align-items:center;flex:0 0 auto;}
.brand-text{color:#fff;font-size:15px;font-weight:700;line-height:1.3;letter-spacing:.01em;}
.nav-items{display:flex;flex-direction:column;gap:2px;width:100%;}
.nav-group{height:1px;background:rgba(255,255,255,.10);margin:10px 20px;}
.nav-item{
  display:flex;align-items:center;gap:12px;margin:0 12px;padding:10px 14px;border-radius:8px;
  color:#B9C6E3;cursor:pointer;text-decoration:none;font-size:14px;font-weight:500;
}
.nav-item svg{flex:0 0 auto;}
.nav-item span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.nav-item:hover{color:#fff;background:rgba(255,255,255,.06);}
.nav-item.active{background:var(--navy-light);color:#fff;font-weight:600;}
.nav-item.disabled{color:#5A6E96;cursor:default;}

/* Collapse to an icon-only rail below 880px -- same markup/labels, just
   visually hidden text, so JS/role-gating logic is untouched. */
@media (max-width: 879px){
  .app{grid-template-columns:var(--sidebar-width-collapsed) 1fr;min-width:820px;}
  .sidebar{padding:8px 0 16px;}
  .brand{margin:0 8px;padding:0;justify-content:center;height:52px;}
  .brand-text{font-size:0;}
  .brand-text::first-letter{font-size:20px;}
  .nav-item{justify-content:center;margin:0 8px;padding:10px;}
  .nav-item span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);}
}

/* ---- Main column / topbar / identity chip ---- */
.main{padding:20px 32px 60px;}
.topbar-row{display:flex;justify-content:flex-end;align-items:center;gap:12px;margin-bottom:16px;}
.identity-chip{display:flex;align-items:center;gap:10px;background:var(--card);border:1px solid var(--border);border-radius:24px;padding:6px 8px 6px 16px;}
.identity-chip-text{text-align:right;}
.identity-name{font-size:var(--fs-sm);font-weight:700;color:var(--navy);}
.identity-role{font-size:var(--fs-xs);color:var(--text-muted);}
.avatar{width:34px;height:34px;border-radius:50%;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px;flex:0 0 auto;}
.topbar{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:16px;gap:16px;flex-wrap:wrap;}
.topbar h1{font-size:var(--fs-2xl);letter-spacing:-.015em;margin:0;color:var(--navy);}
.page-greeting{font-size:var(--fs-base);color:var(--text-muted);margin-top:10px;max-width:720px;line-height:1.6;}

.badge{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:20px;font-size:var(--fs-xs);font-weight:600;white-space:nowrap;}
.badge-official{background:var(--green-bg);color:var(--green);}
.badge-neutral{background:#EEF1F6;color:var(--text-muted);}
.dot{width:7px;height:7px;border-radius:50%;background:currentColor;}

/* ---- Filters (Dashboard context strip + "Filter lainnya" overflow) ---- */
.context-strip{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px 18px;margin-bottom:18px;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;}
.context-strip-left{display:flex;align-items:center;gap:12px;}
.context-strip-icon{width:36px;height:36px;border-radius:8px;background:var(--blue-soft);color:var(--blue);display:flex;align-items:center;justify-content:center;flex:0 0 auto;}
.context-strip-label{font-size:var(--fs-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:2px;}
.context-strip-value{font-size:var(--fs-lg);font-weight:700;color:var(--navy);}
.context-strip-filters{display:flex;gap:8px;align-items:flex-end;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:10px 12px;}

.filters{display:flex;gap:14px 18px;margin-bottom:10px;flex-wrap:wrap;align-items:flex-end;}
.filters select, .filters input[type=number],
.context-strip-filters select, .context-strip-filters input[type=number]{
  padding:8px 10px;border:1px solid var(--border);border-radius:8px;font-size:var(--fs-base);
  background:#fff;color:var(--text);min-width:150px;height:38px;box-sizing:border-box;
}
/* Tahun is a 4-digit year, not a free-form number field -- narrower than
   the default 150px filter width, same border/radius/font/padding as
   every other select/input above. */
#fYear{min-width:0;width:90px;}
.context-strip-filters .btn{height:38px;box-sizing:border-box;}
.filter-group label{font-size:var(--fs-xs);color:var(--text-muted);display:block;margin-bottom:4px;}
.filter-group{display:flex;flex-direction:column;}
/* Only the first 4 filter-groups in the DOM are "primary" (shown inline);
   anything wrapped in <details class="filters-more"> is secondary,
   revealed by the native "Filter lainnya" disclosure -- no extra JS. */
details.filters-more{width:100%;margin-top:6px;}
details.filters-more > summary{
  list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;
  padding:7px 14px;border:1px solid var(--border);border-radius:6px;color:var(--text-muted);font-size:var(--fs-sm);width:fit-content;background:#fff;
}
details.filters-more > summary::-webkit-details-marker{display:none;}
details.filters-more[open] > summary{color:var(--blue);border-color:var(--blue);}
details.filters-more > .filters-more-body{display:flex;gap:14px 18px;flex-wrap:wrap;margin-top:12px;}

.btn{padding:9px 16px;border:1px solid var(--blue);background:var(--blue);color:#fff;border-radius:8px;font-size:var(--fs-base);cursor:pointer;}
.btn:hover{background:#1746a2;}
.btn-ghost{background:#fff;color:var(--text-muted);border-color:var(--border);}
.btn-ghost:hover{background:var(--bg);color:var(--text);}
.btn-danger{background:var(--red);border-color:var(--red);}
.btn-danger:hover{background:#9c2828;}
.btn:disabled{opacity:.5;cursor:not-allowed;}

/* ---- Generic content components (cards/sections/tables/forms/tabs/modal) ---- */
.section{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:20px;margin-bottom:18px;}
.section h2{font-size:14px;margin:0 0 12px;color:var(--navy);}
table{width:100%;border-collapse:collapse;font-size:13px;}
th{text-align:left;color:var(--text-muted);font-weight:600;padding:7px 9px;border-bottom:1px solid var(--border);font-size:11px;text-transform:uppercase;letter-spacing:.03em;}
td{padding:8px 9px;border-bottom:1px solid #EEF1F6;color:var(--text);}
tr:last-child td{border-bottom:none;}
tr.clickable{cursor:pointer;}
tr.clickable:hover{background:#F7FAFF;}
.grid2{display:grid;grid-template-columns:1.3fr 1fr;gap:18px;}

.pill{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;}
.pill-good{background:var(--green-bg);color:var(--green);}
.pill-bad{background:var(--red-bg);color:var(--red);}
.pill-muted{background:#EEF1F6;color:var(--text-muted);}

.empty-state, .error-state, .unauth-state{padding:24px;text-align:center;color:var(--text-muted);font-size:13px;}
.error-state{color:var(--red);}
.loading{padding:24px;text-align:center;color:var(--text-muted);font-size:13px;}
.footnote{font-size:11px;color:var(--text-muted);margin-top:8px;}
.breadcrumb{font-size:12px;color:var(--text-muted);margin-bottom:8px;}
.breadcrumb a{color:var(--blue);cursor:pointer;text-decoration:none;}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);}
select:focus, input:focus, textarea:focus, .btn:focus, tr.clickable:focus{outline:2px solid var(--blue);outline-offset:1px;}

/* Centered empty state with the action directly below the message
   (Organization: "belum ada kategori"/"belum ada pengecualian"). */
.empty-state-block{padding:40px 24px;text-align:center;}
.empty-state-block .empty-state-icon{
  width:48px;height:48px;border-radius:12px;background:var(--blue-soft);color:var(--blue);
  display:flex;align-items:center;justify-content:center;margin:0 auto 14px;
}
.empty-state-block .empty-state-message{color:var(--text-muted);font-size:13px;margin-bottom:0;}
/* The action button for an empty state is the page's own existing
   button (e.g. #btnAddCategory/#btnAddOverride, already wired to its
   click handler at boot) sitting in a .form-actions row right after
   the content block -- centering it here, when the content block is
   empty, puts it directly below the message without duplicating the
   button or touching any business JS. */
.section:has(.empty-state-block) > .form-actions{justify-content:center;margin-top:16px;}

.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px 18px;}
.form-field{display:flex;flex-direction:column;gap:4px;}
.form-field label{font-size:12px;color:var(--text-muted);font-weight:600;}
.form-field input, .form-field select, .form-field textarea{padding:8px 10px;border:1px solid var(--border);border-radius:6px;font-size:13px;background:#fff;color:var(--text);font-family:inherit;}
.form-field input:disabled{background:#F2F4F8;color:var(--text-muted);}
.form-field .hint{font-size:11px;color:var(--text-muted);}
.form-field .field-error{font-size:11px;color:var(--red);min-height:14px;}
.form-actions{display:flex;gap:10px;margin-top:18px;}
.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 24px;margin-top:10px;}
.detail-field{display:flex;justify-content:space-between;gap:10px;padding:7px 0;border-bottom:1px solid var(--border);font-size:13px;}
.detail-field .detail-label{color:var(--text-muted);}
.detail-field .detail-value{font-weight:500;text-align:right;color:var(--text);}

.tabs{display:flex;gap:4px;border-bottom:1px solid var(--border);margin-bottom:16px;}
.tab{padding:9px 16px;font-size:13px;color:var(--text-muted);cursor:pointer;border-bottom:2px solid transparent;}
.tab.active{color:var(--blue);border-bottom-color:var(--blue);font-weight:600;}
.tab .count{display:inline-block;margin-left:6px;padding:1px 7px;border-radius:9px;background:#EEF1F6;font-size:11px;}

.txn-card{border:1px solid var(--border);border-radius:8px;padding:14px 16px;margin-bottom:10px;background:var(--card);}
.txn-card-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;}
.txn-card-title{font-weight:600;font-size:14px;color:var(--text);}
.txn-card-sub{font-size:12px;color:var(--text-muted);margin-top:2px;}
.txn-card-amount{font-weight:700;color:var(--navy);font-size:15px;white-space:nowrap;}
.txn-card-actions{display:flex;gap:8px;margin-top:12px;}
.revision-reason{background:var(--red-bg);color:#7A2323;padding:10px 12px;border-radius:6px;font-size:12px;margin-top:10px;}

.modal-backdrop{position:fixed;inset:0;background:rgba(11,30,61,.45);display:flex;align-items:center;justify-content:center;z-index:100;}
.modal{background:var(--card);border-radius:10px;padding:24px;width:420px;max-width:90vw;
  /* max-height + overflow were MISSING until 19 September 2026, and their
     absence was not a cosmetic problem. .modal-backdrop is position:fixed
     with align-items:center, so a modal taller than the viewport overflows
     in BOTH directions and nothing can scroll: the buttons go below the
     bottom edge and the title goes above the top, unreachable by any
     means. Measured on a 1366x768 laptop the revision modal stood at
     1080px -- title at y=-132, Simpan at y=869.

     Before six boxes were added on 19 September that same modal measured
     775px, i.e. it was THREE PIXELS from breaking and nobody could have
     known. See docs/TEMUAN_MODAL_TANPA_MAX_HEIGHT.md.

     90vh, never a fixed pixel height: this modal is also used on small
     screens. */
  max-height:90vh;overflow-y:auto;}

/* Keeps Batal/Simpan on screen while the body scrolls. Sticky rather than a
   flex footer so no modal's markup has to change -- the negative margins
   cancel .modal's own 24px padding so the bar spans the full width and
   nothing shows through beneath it. */
.modal .form-actions{position:sticky;bottom:-24px;background:inherit;
  margin:0 -24px -24px;padding:14px 24px 24px;border-top:1px solid var(--border);}
.modal h3{margin:0 0 14px;font-size:16px;color:var(--navy);}
.preview-box{background:var(--blue-soft);border-radius:8px;padding:12px 14px;margin-top:10px;}
.preview-box .row{display:flex;justify-content:space-between;font-size:13px;padding:3px 0;}
.preview-box .row b{color:var(--navy);}

@media (max-width: 1400px) and (min-resolution: 1.25dppx){
  .app{ zoom: 0.8; }
}
