:root {
    /* Tells the browser which palette to use for controls it renders itself (native <select>
       popup list, checkboxes/radios, date/time pickers, scrollbars) — without this the browser
       falls back to its OS default (usually light) regardless of our data-theme toggle above,
       which is exactly why dropdown options could end up light-text-on-light or dark-on-dark
       independent of the rest of the page. */
    color-scheme: light;
    --primary: #0b5f55;
    --primary-2: #0e7668;
    --primary-soft: #e6f3f0;
    --accent: #d99a2b;
    --ink: #162321;
    --muted: #64706e;
    --line: #dfe7e5;
    /* --surface carries a gradient, not a flat color — background: var(--surface) still works
       everywhere it's already used (background accepts a gradient wherever it accepts a color),
       so every card/button/panel picked up the depth for free. --surface-solid is the same tone
       as a plain color, kept separately for the one spot that isn't a background (a box-shadow
       ring, which can't render a gradient) — see .chat-avatar below. */
    --surface: linear-gradient(160deg, #ffffff 0%, #f3faf7 100%);
    --surface-solid: #ffffff;
    --canvas: #f4f7f6;
    --danger: #b73535;
    --danger-soft: #fdecec;
    --warning: #936211;
    --warning-soft: #fff5d9;
    --success: #147244;
    --success-soft: #e8f6ee;
    --info: #205fa4;
    --info-soft: #eaf2fc;
    --radius: 15px;
    --shadow: 0 14px 38px rgba(15, 59, 52, .1);
    --right-panel-bg: linear-gradient(165deg, #eefbf4 0%, #dcf0e6 100%);
    --sidebar-bg: #ffffff;
    --sticker-bg: #f4f7f6;
    --sticker-border: #ffffff;
    --sticker-text: #375973;
    --sticker-highlight: rgba(255,255,255,0.8);
}
html[data-theme="dark"] {
    color-scheme: dark;
    --primary: #129b8b;
    --primary-2: #19b7a4;
    --primary-soft: rgba(14, 118, 104, 0.2);
    --accent: #f0b041;
    --ink: #e2e8f0;
    --muted: #94a3b8;
    --line: #334155;
    /* Flat #1e293b read as "plain" specifically because a shadow cast by a single-tone box onto
       an almost-equally-dark page has almost no contrast to show it — a slightly lighter top
       edge fading to the base tone gives the surface itself a sense of a light source, so the
       shadow reads as "this box is lifted" rather than disappearing into the canvas. */
    --surface: linear-gradient(160deg, #263450 0%, #1b2636 100%);
    --surface-solid: #1e293b;
    --canvas: #0f172a;
    --danger: #ef4444;
    --danger-soft: rgba(239, 68, 68, 0.15);
    --warning: #f59e0b;
    --warning-soft: rgba(245, 158, 11, 0.15);
    --success: #10b981;
    --success-soft: rgba(16, 185, 129, 0.15);
    --info: #3b82f6;
    --info-soft: rgba(59, 130, 246, 0.15);
    --shadow: 0 14px 38px rgba(0, 0, 0, 0.45);
    --right-panel-bg: linear-gradient(165deg, #17212f 0%, #0c121c 100%);
    --sidebar-bg: #1e293b;
    --sticker-bg: rgba(255, 255, 255, 0.05);
    --sticker-border: rgba(255, 255, 255, 0.1);
    --sticker-text: #cbd5e1;
    --sticker-highlight: rgba(255, 255, 255, 0.05);
}
* { box-sizing: border-box; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--canvas); }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }
html { scroll-behavior: smooth; }
body { margin: 0; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: var(--ink); background: var(--canvas); line-height: 1.55; transition: background-color 0.3s ease, color 0.3s ease; }
a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-2); }
img { max-width: 100%; }
button, input, select, textarea { font: inherit; }

/* --- TYPE SCALE ---
   One consistent hierarchy for the whole app: h1 = page title, h2 = card/section title,
   h3 = minor subheading, h4-h6 = field-group label. Without this, a bare <h2> inside a .card
   (there are dozens across the app) fell back to the browser's default UA size — inconsistent
   and oversized next to 13-14px body text. Public/marketing pages (hero, login, tickets) keep
   their own bigger clamp()-based overrides declared further down in the cascade; those win
   over this base on specificity. */
h1 { font-size: 24px; font-weight: 800; letter-spacing: -.02em; line-height: 1.25; margin: 0 0 6px; }
h2 { font-size: 17px; font-weight: 800; letter-spacing: -.01em; line-height: 1.3; margin: 0 0 6px; }
h3 { font-size: 15px; font-weight: 700; line-height: 1.35; margin: 0 0 6px; }
h4, h5, h6 { font-size: 14px; font-weight: 700; line-height: 1.4; margin: 0 0 6px; }
p { margin: 0 0 10px; }
p:last-child { margin-bottom: 0; }
.container { width: min(1180px, calc(100% - 32px)); margin-inline: auto; }
.public-header { position: sticky; top: 0; z-index: 40; background: rgba(255,255,255,.96); border-bottom: 1px solid var(--line); backdrop-filter: blur(14px); }
.public-nav { min-height: 72px; display: flex; align-items: center; gap: 26px; }
.brand { display: inline-flex; align-items: center; gap: 11px; font-weight: 800; color: var(--ink); letter-spacing: -.02em; }
.brand img { width: 38px; height: 38px; }
.brand small { display: block; font-size: 10px; color: var(--muted); font-weight: 600; letter-spacing: .03em; }
.public-links { display: flex; gap: 22px; align-items: center; margin-left: auto; font-size: 14px; font-weight: 650; }
.nav-actions { display: flex; align-items: center; gap: 10px; }
/* .btn.mobile-menu (not just .mobile-menu): the generic .btn rule further down also sets
   display, and with equal single-class specificity the later declaration wins regardless of
   which one is more "meant" to apply — that silently kept this button visible on desktop.
   Doubling the class in the selector raises specificity so this one reliably wins. */
.btn.mobile-menu { display: none; }
.hero { position: relative; overflow: hidden; background: linear-gradient(120deg, #073f39 0%, #0b675c 62%, #168879 100%); color: white; }
/* Hero carousel: one .hero-slide per active slide, each a full-bleed background (video or
   image) with text overlaid — same track-transform mechanics as .mini-slider-track, driven by
   the shared setupSlider() in app.js. */
.hero-slider-track { display: flex; transition: transform .6s cubic-bezier(.4,0,.2,1); }
.hero-slide { position: relative; flex: 0 0 100%; min-height: 570px; display: grid; align-items: center; overflow: hidden; }
.hero-slide-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.hero-slide-bg img { width: 100%; height: 100%; object-fit: cover; }
/* YouTube letterboxes/pillarboxes any source clip that isn't exactly 16:9 inside its own
   player — CSS can't reach into that cross-origin iframe to crop it, so instead the iframe
   itself is oversized well past the visible box and centered; overflow:hidden above crops the
   excess, taking the internal black bars with it. */
.hero-slide-bg iframe { position: absolute; top: 50%; left: 50%; width: 100vw; height: 56.25vw; min-height: 100%; min-width: 177.78vh; border: 0; transform: translate(-50%, -50%) scale(1.35); }
.hero-slide-overlay { position: absolute; inset: 0; z-index: 1; background: linear-gradient(120deg, rgba(7,63,57,.86) 0%, rgba(11,103,92,.72) 45%, rgba(22,136,121,.5) 100%); pointer-events: none; }
.hero-grid { display: grid; grid-template-columns: 1fr; gap: 50px; align-items: center; position: relative; z-index: 2; padding-block: 70px; }
.hero h1 { font-size: clamp(40px, 5vw, 68px); line-height: 1.04; letter-spacing: -.045em; margin: 0 0 22px; max-width: 760px; }
.hero p { font-size: 18px; color: rgba(255,255,255,.82); max-width: 650px; }
.hero-slider-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 3; width: 46px; height: 46px; border-radius: 50%; border: none; background: rgba(8,20,17,.35); color: white; display: grid; place-items: center; cursor: pointer; opacity: 0; transition: opacity .18s, background-color .18s; }
.hero:hover .hero-slider-nav { opacity: 1; }
.hero-slider-nav:hover { background: rgba(8,20,17,.6); }
.hero-slider-nav i { font-size: 20px; }
.hero-slider-prev { left: 18px; }
.hero-slider-next { right: 18px; }
.hero-slider-dots { position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 3; display: flex; gap: 7px; }
.hero-slider-dots button { width: 8px; height: 8px; border-radius: 50%; border: none; background: rgba(255,255,255,.45); cursor: pointer; padding: 0; transition: background-color .2s, width .2s; }
.hero-slider-dots button.active { background: white; width: 22px; border-radius: 5px; }
@media (hover: none) {
    /* No hover on touch devices — keep the arrows reachable instead of permanently invisible. */
    .hero-slider-nav { opacity: 1; }
}
.eyebrow { text-transform: uppercase; letter-spacing: .16em; font-weight: 800; font-size: 12px; color: var(--accent); }
.hero-actions, .actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.btn { appearance: none; border: 1px solid transparent; border-radius: 10px; padding: 10px 16px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-weight: 750; cursor: pointer; transition: transform .15s cubic-bezier(0.4, 0, 0.2, 1), background .18s, color .18s, border-color .18s; font-size: 14px; position: relative; overflow: hidden; min-height: 42px; }
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: scale(0.95); }
.btn-primary { background: var(--primary); color: white; }
.btn-primary:hover { background: var(--primary-2); color: white; }
.btn-accent { background: var(--accent); color: #261c08; }
.btn-accent:hover { color: #261c08; background: #e8a93a; }
.btn-outline { border-color: var(--line); color: var(--ink); background: transparent; }
.btn-outline:hover { border-color: var(--primary); color: var(--primary); }
.btn-ghost { color: inherit; background: transparent; }
.btn-danger { background: var(--danger); color: white; }
.btn-danger:hover { color: white; }
.btn-sm { padding: 7px 11px; border-radius: 8px; font-size: 12px; min-height: 34px; }
.btn-icon-only { width: 42px !important; min-width: 42px; max-width: 42px; height: 42px; padding: 0 !important; border-radius: 10px; gap: 0; flex: 0 0 auto; }
.btn-icon-only.btn-sm { width: 34px !important; min-width: 34px; max-width: 34px; height: 34px; border-radius: 8px; }
.btn-icon-only i { display: flex; line-height: 1; margin-top: 2px; }
.btn-icon-only .btn-label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.section { padding-block: 72px; }
.section-tight { padding-block: 38px; }
.section-white { background: white; }
.section-heading { display: flex; align-items: end; justify-content: space-between; gap: 20px; margin-bottom: 28px; }
.section-heading h2 { font-size: clamp(28px, 4vw, 42px); letter-spacing: -.035em; margin: 4px 0; }
.section-heading p { color: var(--muted); margin: 0; }
.grid { display: grid; gap: 20px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 5px 18px rgba(15,59,52,.035); padding: 22px; }
/* "Tentang" section's optional YouTube embed (Super Admin-configurable, see Content::video_url) —
   a real, user-controlled embed (autoplay/controls left on), not the decorative muted
   background videos elsewhere, so no oversize/crop trick needed here. */
.about-video-card { padding: 10px; }
.about-video-card iframe { display: block; width: 100%; aspect-ratio: 16/9; border: 0; border-radius: calc(var(--radius) - 6px); }
.card-hover { transition: .2s ease; }
.card-hover:hover { transform: translateY(-4px); box-shadow: var(--shadow); border-color: #c9d9d5; }
.card h3, .card h4 { margin-top: 0; }
.card p:last-child { margin-bottom: 0; }
.media-card { padding: 0; overflow: hidden; }
.media-card .cover { aspect-ratio: 16/9; width: 100%; object-fit: cover; background: var(--primary-soft); display: block; }
.media-card .card-body { padding: 20px; }
/* Description text (slide subtitle, content excerpt, event summary, ...) was unbounded, so a
   long one made the card grow tall and dense next to its shorter neighbors — clamp to 3 lines
   with an ellipsis so every card in a grid reads at a consistent, uncluttered height. */
.media-card .card-body p { display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.meta { color: var(--muted); font-size: 13px; display: flex; gap: 12px; flex-wrap: wrap; }
.badge { display: inline-flex; align-items: center; white-space: nowrap; border-radius: 999px; padding: 4px 9px; font-size: 11px; font-weight: 800; background: #edf1f0; color: #3c4a47; }
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }
.badge-danger { background: var(--danger-soft); color: var(--danger); }
.badge-info { background: var(--info-soft); color: var(--info); }
.badge-neutral { background: #edf1f0; color: #53605e; }
.feature-strip { margin-top: -36px; position: relative; z-index: 4; }
.feature-strip .card { display: grid; grid-template-columns: repeat(3, 1fr); padding: 0; overflow: hidden; }
.feature-item { padding: 22px; display: flex; gap: 14px; align-items: center; }
.feature-item + .feature-item { border-left: 1px solid var(--line); }
.feature-icon { width: 58px; height: 58px; flex: 0 0 58px; border-radius: 14px; background: var(--primary-soft); color: var(--primary); display: grid; place-items: center; font-weight: 900; }
.feature-icon svg { width: 36px; height: 36px; overflow: visible; }

/* Versioning Word: lines draw in one after another, like a new revision being written */
.feature-icon-version .v-line { stroke-dasharray: 12; stroke-dashoffset: 12; animation: v-draw 2.6s ease-in-out infinite; }
.feature-icon-version .v-line:nth-child(4) { animation-delay: .15s; }
.feature-icon-version .v-line:nth-child(5) { animation-delay: .3s; }
@keyframes v-draw { 0%, 8% { stroke-dashoffset: 12; } 32%, 78% { stroke-dashoffset: 0; } 92%, 100% { stroke-dashoffset: 12; } }

/* Review Terstruktur: checkmark draws in as if a decision was just approved */
.feature-icon-review .r-check { stroke-dasharray: 20; stroke-dashoffset: 20; animation: r-check 2.6s ease-in-out infinite; }
@keyframes r-check { 0%, 15% { stroke-dashoffset: 20; } 45%, 80% { stroke-dashoffset: 0; } 95%, 100% { stroke-dashoffset: 20; } }

/* Event & Ticketing: ticket stub pulses gently, dot travels the perforation like a scan */
.feature-icon-event svg { animation: e-pulse 2.4s ease-in-out infinite; }
.feature-icon-event .e-dot { animation: e-dot 2.4s ease-in-out infinite; }
@keyframes e-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
@keyframes e-dot { 0%, 100% { transform: translateY(-6px); } 50% { transform: translateY(6px); } }

@media (prefers-reduced-motion: reduce) {
    .feature-icon-version .v-line, .feature-icon-review .r-check, .feature-icon-event svg, .feature-icon-event .e-dot { animation: none; stroke-dashoffset: 0; transform: none; }
}
.public-footer { background: #0c2623; color: rgba(255,255,255,.72); padding: 55px 0 25px; }
.footer-grid { display: grid; grid-template-columns: 1.3fr repeat(3, 1fr); gap: 40px; }
.public-footer h4 { color: white; display: flex; align-items: center; gap: 8px; }
.public-footer a { color: rgba(255,255,255,.75); display: inline-flex; align-items: center; gap: 8px; }
.public-footer a:hover { color: white; }
.public-footer h4 i, .public-footer a i { font-size: 14px; opacity: .85; }
.copyright { border-top: 1px solid rgba(255,255,255,.12); margin-top: 36px; padding-top: 20px; font-size: 13px; }
/* Prayer-times widget: "column" sits in the footer grid — a compact 2-col grid of 5 items
   (instead of 5 stacked rows) so its natural content height lands close to its siblings'
   h4 + 3 <p> rhythm, letting CSS Grid's row-stretch behavior do the rest. "row" is a compact
   single horizontal strip used on the dashboard. */
.prayer-times-column h4 { margin-bottom: 2px; }
.prayer-times-column .prayer-times-location { margin: 0 0 8px; font-size: 11px; color: rgba(255,255,255,.5); }
.prayer-times-column .prayer-times-list { display: grid; grid-template-columns: repeat(2, auto); gap: 3px 20px; }
.prayer-times-column .prayer-time-item { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; }
.prayer-times-column .prayer-time-label { color: rgba(255,255,255,.72); }
.prayer-times-column .prayer-time-value { color: white; font-weight: 700; font-variant-numeric: tabular-nums; }
.prayer-times-row { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; box-shadow: 0 5px 18px rgba(15,59,52,.035); transition: background-color .3s ease, border-color .3s ease; }
.prayer-times-row .prayer-times-head { display: flex; align-items: center; gap: 5px; font-size: 9px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .02em; margin-bottom: 4px; }
.prayer-times-row .prayer-times-head i { color: var(--primary); font-size: 10px; }
.prayer-times-row .prayer-times-head span { flex: 1; }
/* Flexbox, not a fixed grid-template-columns count: the list holds 5 items normally, 6 when
   the Qur'an button is configured, and flex:1 on each item adapts to either without needing a
   modifier class. */
.prayer-times-row .prayer-times-list { display: flex; gap: 4px; }
.prayer-times-row .prayer-time-item { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 3px 3px; border-radius: 5px; background: var(--primary-soft); }
.prayer-times-row .prayer-time-label { font-size: 8.5px; font-weight: 700; color: var(--primary); text-transform: uppercase; letter-spacing: .01em; }
.prayer-times-row .prayer-time-value { font-size: 10px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
/* The Qur'an button is a 6th item in the same row, same size as the time cards, but colored
   solid to read as an action rather than a static value. */
.prayer-times-row .prayer-time-item.prayer-times-quran-btn { background: var(--primary); text-decoration: none; cursor: pointer; transition: background-color .15s ease, transform .15s ease; }
.prayer-times-row .prayer-time-item.prayer-times-quran-btn:hover { background: var(--primary-2); transform: translateY(-1px); }
.prayer-times-row .prayer-time-item.prayer-times-quran-btn .prayer-time-label { color: white; font-size: 11px; }
.prayer-times-row .prayer-time-item.prayer-times-quran-btn .prayer-time-value { color: white; font-size: 8.5px; text-transform: uppercase; letter-spacing: .01em; }
@media (max-width: 640px) {
    .prayer-times-row .prayer-times-list { flex-wrap: wrap; }
    .prayer-times-row .prayer-time-item { flex: 1 1 calc(33.333% - 4px); }
    .prayer-times-column .prayer-times-list { grid-template-columns: 1fr; }
}
.page-hero { background: linear-gradient(120deg, #073f39, #0e7668); color: white; padding: 65px 0; }
.page-hero h1 { font-size: clamp(34px, 5vw, 54px); line-height: 1.08; letter-spacing: -.04em; margin: 0 0 12px; }
.page-hero p { max-width: 720px; color: rgba(255,255,255,.78); }
.prose { font-size: 16px; line-height: 1.8; }
.prose h2, .prose h3, .prose h4 { letter-spacing: -.02em; margin: 24px 0 12px; }
.prose h2:first-child, .prose h3:first-child, .prose h4:first-child { margin-top: 0; }
.prose p { margin: 0 0 16px; }
.prose img { max-width: 100%; height: auto; border-radius: var(--radius); margin: 16px 0; }
/* Admin-embedded iframes (YouTube/Maps via the "Edit HTML" mode) have hardcoded width/height
   attributes from the pasted embed code, which overflow a narrow card/mobile viewport as-is. */
.prose iframe { max-width: 100%; aspect-ratio: 16/9; height: auto; border-radius: var(--radius); margin: 16px 0; }
.prose ul, .prose ol { margin: 0 0 16px; padding-left: 24px; }
.prose li { margin-bottom: 6px; }
.prose blockquote { margin: 16px 0; padding: 4px 18px; border-left: 3px solid var(--primary); color: var(--muted); }
.prose a { color: var(--primary); text-decoration: underline; }

.app-shell { min-height: 100vh; display: grid; grid-template-columns: var(--sidebar-w, 270px) minmax(0, 1fr); transition: grid-template-columns .35s cubic-bezier(.4, 0, .2, 1); }
.app-shell.has-right-panel { grid-template-columns: var(--sidebar-w, 270px) minmax(0, 1fr) var(--right-w, 300px); }
body.sidebar-collapsed .app-shell { --sidebar-w: 76px; }
body.rightpanel-collapsed .app-shell.has-right-panel { --right-w: 0px; }
.sidebar { position: sticky; top: 0; height: 100vh; background: var(--sidebar-bg); color: var(--muted); padding: 20px 14px; overflow-x: hidden; overflow-y: auto; border-right: 1px solid var(--line); transition: background-color 0.3s ease, border-color 0.3s ease; display: flex; flex-direction: column; }
.sidebar .brand { color: var(--primary); padding: 2px 10px 16px; white-space: nowrap; }
/* Soft/neumorphic pill: a sunken track (inset shadow) holding raised glossy circle buttons —
   each button reads as physically embossed, with a pressed-in look on click. Uses the theme's
   own --surface/--canvas so it still adapts to dark mode; only the shadow tint needs a
   dark-mode override below since highlight/shadow direction depends on which side is "lighter". */
.sidebar-tools {
    display: flex; align-items: center; gap: 8px; width: fit-content; margin: 0 8px 14px; padding: 7px;
    background: var(--canvas); border-radius: 999px;
    box-shadow: inset 0 2px 6px rgba(0,0,0,.1), inset 0 -1px 0 rgba(255,255,255,.7);
}
.sidebar-collapse-toggle, .sidebar-tool-btn, .panel-icon-btn {
    width: 36px; height: 36px; border-radius: 50%; border: none; background: var(--surface); color: var(--muted);
    display: grid; place-items: center; cursor: pointer; flex-shrink: 0;
    box-shadow: 0 1px 2px rgba(0,0,0,.1), 0 4px 9px rgba(0,0,0,.08), inset 0 1px 0 rgba(255,255,255,.85);
    transition: margin .35s cubic-bezier(.4, 0, .2, 1), color .2s, box-shadow .2s ease, transform .15s ease, background-color .3s;
}
.sidebar-collapse-toggle { margin: 0; }
.sidebar-collapse-toggle:hover, .sidebar-tool-btn:hover, .panel-icon-btn:hover {
    color: var(--primary); transform: translateY(-1px);
    box-shadow: 0 2px 5px rgba(0,0,0,.1), 0 5px 12px rgba(0,0,0,.06), inset 0 1px 0 rgba(255,255,255,.8);
}
.sidebar-collapse-toggle:active, .sidebar-tool-btn:active, .panel-icon-btn:active {
    transform: translateY(0); box-shadow: inset 0 2px 4px rgba(0,0,0,.14);
}
/* Dashboard's icon in this row uses the same "current page" orange as .sidebar-link.active. */
.sidebar-tool-btn.active { background: #E86C45; color: white; }
.sidebar-tool-btn.active:hover { color: white; }
html[data-theme="dark"] .sidebar-tools { box-shadow: inset 0 2px 6px rgba(0,0,0,.4), inset 0 -1px 0 rgba(255,255,255,.04); }
html[data-theme="dark"] .sidebar-collapse-toggle,
html[data-theme="dark"] .sidebar-tool-btn,
html[data-theme="dark"] .panel-icon-btn { box-shadow: 0 1px 2px rgba(0,0,0,.3), 0 3px 6px rgba(0,0,0,.2), inset 0 1px 0 rgba(255,255,255,.05); }
html[data-theme="dark"] .sidebar-collapse-toggle:hover,
html[data-theme="dark"] .sidebar-tool-btn:hover,
html[data-theme="dark"] .panel-icon-btn:hover { box-shadow: 0 2px 5px rgba(0,0,0,.35), 0 5px 12px rgba(0,0,0,.25), inset 0 1px 0 rgba(255,255,255,.08); }
.sidebar-collapse-toggle i { transition: transform .35s cubic-bezier(.4, 0, .2, 1); display: block; }
body.sidebar-collapsed .sidebar-tools { justify-content: center; padding-inline: 0; flex-wrap: wrap; }
body.sidebar-collapsed .sidebar-tool-btn { display: none; }
/* The search trigger stays reachable even collapsed — the whole point of it living in this
   compact icon row is that it never needs the sidebar expanded to be used. */
body.sidebar-collapsed .sidebar-tool-btn[data-global-search-toggle] { display: grid; }
body.sidebar-collapsed .sidebar-collapse-toggle { margin-left: auto; margin-right: auto; }
body.sidebar-collapsed .sidebar-collapse-toggle i { transform: rotate(180deg); }
body.sidebar-collapsed .brand span { display: none; }
body.sidebar-collapsed .sidebar-credit { width: 42px; height: 42px; padding: 0; margin-inline: auto; justify-content: center; }
body.sidebar-collapsed .sidebar-credit span { display: none; }
body.sidebar-collapsed .sidebar .sidebar-link { font-size: 0; padding: 8px; justify-content: center; }
body.sidebar-collapsed .sidebar .sidebar-label { font-size: 0; justify-content: center; padding: 8px; }
body.sidebar-collapsed .sidebar-label .acc-icon { display: none; }
/* Collapsing to icon-only used font-size:0 to hide the label text, but the icon+text wrapper's
   own `gap` (see the inline style in layouts/app.blade.php) isn't relative to font-size — it kept
   reserving space for a now-invisible span, so the centered flex box was actually icon+gap+empty
   text, and the icon rendered visibly off-center (shifted left by half the gap). Same fix applies
   to .sidebar-link for consistency, even though its icon is currently only shown via the flyout
   clone (unaffected by these collapsed rules) rather than inline. Rule of thumb for any future
   icon+label pair collapsing to icon-only: hide the label with `display:none`, not `font-size:0`,
   so it's removed from flex flow entirely instead of leaving a phantom gap. */
body.sidebar-collapsed .sidebar-label > div { gap: 0; }
body.sidebar-collapsed .sidebar-label > div > span,
body.sidebar-collapsed .sidebar .sidebar-link > span:not(.sidebar-icon) { display: none; }
body.sidebar-collapsed .sidebar .sidebar-menu { display: none !important; }

/* Collapsed sidebar: clicking a section opens a flyout popover instead of the inline accordion. */
.sidebar-flyout { position: fixed; left: 84px; z-index: 70; background: var(--surface); border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 14px 34px rgba(0, 0, 0, .15); padding: 10px; min-width: 220px; max-width: 260px; opacity: 0; transform: translateX(-8px); pointer-events: none; transition: opacity .18s ease, transform .18s ease; }
.sidebar-flyout.active { opacity: 1; transform: translateX(0); pointer-events: auto; }
.sidebar-flyout .sidebar-link { margin: 2px 0; }
.sidebar-section { margin-top: 6px; }
.sidebar-label { padding: 8px 12px; margin: 0 8px 4px 8px; background: var(--sticker-bg); border-radius: 12px; border: 1px solid var(--sticker-border); box-shadow: 0 4px 10px rgba(0,0,0,0.03), inset 0 2px 0 var(--sticker-highlight); font-size: 11px; text-transform: uppercase; letter-spacing: .12em; color: var(--sticker-text); font-weight: 850; cursor: pointer; display: flex; justify-content: space-between; align-items: center; transition: transform 0.2s, box-shadow 0.2s, background 0.3s, border-color 0.3s; }
.sidebar-label:hover { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(0,0,0,0.05), inset 0 2px 0 var(--sticker-highlight); background: var(--surface); }
.sidebar-label .acc-icon { transition: transform 0.2s; font-size: 9px; color: #7f95a6; }
/* display:none/block has no transition, so the old version of this only animated opening
   (display:none -> block could fade in) and snapped shut instantly on close. max-height +
   opacity are both animatable in either direction, so open and close now mirror each other. */
.sidebar-menu {
    max-height: 0; opacity: 0; overflow: hidden; pointer-events: none;
    transition: max-height .28s cubic-bezier(.4, 0, .2, 1), opacity .18s ease;
}
.sidebar-section.active .sidebar-menu { max-height: 600px; opacity: 1; pointer-events: auto; }
.sidebar-section.active .acc-icon { transform: rotate(180deg); }
.sidebar-link { color: var(--muted); display: flex; align-items: center; gap: 12px; border-radius: 99px; padding: 7px 16px 7px 8px; margin: 10px 0; font-size: 12px; font-weight: 650; transition: .2s ease; }
.sidebar-link:hover { background: var(--canvas); color: var(--ink); }
.sidebar-link.active { background: #E86C45; color: white; }
.sidebar-icon { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 16px; color: #9da8a6; transition: .2s ease; }
.sidebar-icon i { display: flex; line-height: 1; margin-top: 2px; }
.sidebar-link:hover .sidebar-icon { color: var(--primary); }
.sidebar-link.active .sidebar-icon { background: var(--surface); color: #E86C45; box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
.sidebar-link:not(:has(.sidebar-icon))::before { content: "\f054"; width: 32px; height: 32px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-family: uicons-regular-rounded !important; color: #9da8a6; }
.sidebar-credit { margin: auto 8px 4px; padding: 12px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); color: var(--muted); font-size: 11px; line-height: 1.35; display: flex; align-items: center; gap: 8px; box-shadow: 0 4px 15px rgba(0,0,0,.025); }
.sidebar-credit span { min-width: 0; }
.sidebar-credit-name { color: var(--primary); font-weight: 700; text-decoration: none; }
.sidebar-credit-name:hover { text-decoration: underline; }
/* Icon-only link is redundant once the name itself is clickable; it exists purely as a
   collapsed-mode affordance, where the <span> (and the name link inside it) is hidden. */
.sidebar-credit-icon { display: none; }
body.sidebar-collapsed .sidebar-credit-icon { width: 28px; height: 28px; border-radius: 50%; background: var(--canvas); color: var(--primary); display: grid; place-items: center; flex: 0 0 auto; }
.app-main { min-width: 0; }
.right-panel { background: var(--right-panel-bg); padding: 18px 18px; height: 100vh; position: sticky; top: 0; overflow-y: auto; border-left: 1px solid var(--line); transition: background-color 0.3s ease, border-color 0.3s ease, padding .35s cubic-bezier(.4, 0, .2, 1); }
.right-panel-header { position: relative; display: block; margin-bottom: 18px; padding-left: 0; }
body.rightpanel-collapsed .right-panel { padding: 0; overflow: hidden; border-left: none; }
.rightpanel-handle { display: none; position: fixed; right: 0; top: 50%; transform: translateY(-50%); width: 32px; height: 64px; background: var(--primary); border: 1px solid var(--primary); border-right: none; border-radius: 10px 0 0 10px; align-items: center; justify-content: center; cursor: pointer; color: #fff; box-shadow: -4px 0 16px rgba(0, 0, 0, .18); z-index: 500; font-size: 16px; transition: filter .2s ease; }
.rightpanel-handle:hover { filter: brightness(1.1); }
body.rightpanel-collapsed .rightpanel-handle { display: flex; }
.rightpanel-inline-handle { position: fixed; top: 50%; transform: translateY(-50%); right: var(--right-w, 300px); width: 28px; height: 60px; background: var(--surface); border: 1px solid var(--line); border-right: none; border-radius: 10px 0 0 10px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--muted); box-shadow: -4px 0 12px rgba(0,0,0,.08); z-index: 45; transition: color .2s ease, right .35s cubic-bezier(.4, 0, .2, 1); }
.rightpanel-inline-handle:hover { color: var(--primary); border-color: var(--primary); }
.rp-profile-card { display: flex; align-items: center; gap: 10px; width: 100%; min-width: 0; background: var(--surface); padding: 10px 12px 10px 10px; border-radius: 999px; box-shadow: 0 4px 15px rgba(0,0,0,0.03); transition: background-color 0.3s; }
/* No dedicated "Profil Saya" sidebar entry anymore — this whole avatar+name block is the entry
   point into /profile instead (see resources/views/partials/right-panel.blade.php). */
.rp-profile-identity { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; color: inherit; text-decoration: none; border-radius: 999px; transition: background-color .15s ease; }
.rp-profile-identity:hover { background: var(--canvas); }
.rp-profile-identity:hover .rp-profile-meta strong { color: var(--primary); }
.rp-profile-avatar { width: 44px; height: 44px; font-size: 15px; box-shadow: 0 0 0 4px var(--canvas); }
.rp-profile-meta { flex: 1; min-width: 0; }
.rp-profile-meta strong { font-size: 13px; color: var(--ink); display: block; line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-profile-meta small { color: var(--muted); font-size: 11px; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
.rp-profile-logout { margin-left: 8px; border-left: 1px solid var(--line); padding-left: 12px; flex: 0 0 auto; }
/* padding:0 matters here: the browser's UA-default button padding was silently eating into the
   40x40 box, on top of an icon glyph whose own "ink" already leans right (arrow head) — a
   permanent soft ring (not just on hover) gives the eye a stable circle to judge as centered
   against, rather than a bare floating glyph next to the divider line. */
.rp-profile-logout button { width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: var(--canvas); cursor: pointer; font-size: 19px; color: var(--danger); display: grid; place-items: center; transition: background-color .2s ease, transform .2s cubic-bezier(.34, 1.56, .64, 1), box-shadow .2s ease; }
.rp-profile-logout button i { transition: transform .2s ease; }
.rp-profile-logout button:hover { background: var(--danger-soft); transform: scale(1.08); box-shadow: 0 4px 14px rgba(183, 53, 53, .28); }
.rp-profile-logout button:hover i { transform: translateX(2px); }
.rp-profile-logout button:active { transform: scale(.92); box-shadow: none; }
@media (prefers-reduced-motion: reduce) {
    .rp-profile-logout button, .rp-profile-logout button i { transition: none; }
    .rp-profile-logout button:hover { transform: none; }
}
.hero-banner { background: linear-gradient(135deg, #14A24B, #0E7668); color: white; border-radius: 20px; padding: 34px 38px; display: flex; align-items: center; justify-content: flex-start; gap: 24px; position: relative; overflow: hidden; margin-bottom: 26px; min-height: 220px; }
/* Rounded-rectangle (24px), not a circle — matches .hero-banner's own 20px corner language
   instead of fighting it with an unrelated shape language. */
/* Now a link into /profile (no dedicated sidebar entry — see layouts/app.blade.php) — the
   pencil badge only appears on hover so the welcome card doesn't look "editable" at a glance,
   just discoverable once you're near it. */
.hero-profile { position: relative; z-index: 3; width: 108px; height: 108px; border-radius: 24px; border: 4px solid rgba(255,255,255,.45); background: rgba(255,255,255,.18); display: grid; place-items: center; overflow: hidden; flex: 0 0 auto; box-shadow: 0 16px 32px rgba(0,0,0,.12); cursor: pointer; transition: transform .2s cubic-bezier(.34, 1.56, .64, 1), border-color .2s ease; }
.hero-profile:hover { transform: scale(1.05); border-color: rgba(255,255,255,.8); }
.hero-profile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero-profile span { font-size: 42px; font-weight: 900; }
.hero-profile-edit-badge { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(11,47,43,.55); color: white; font-size: 24px; opacity: 0; transition: opacity .2s ease; }
.hero-profile:hover .hero-profile-edit-badge { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
    .hero-profile { transition: none; }
    .hero-profile:hover { transform: none; }
}
/* Small, deliberately understated — sits at rest until hovered, tucked in the corner so it
   doesn't compete with the welcome message for attention. Same [data-tour-start] hook as the
   "Mulai Tur Panduan" button on the profile page (see app.js), just a second entry point. */
.hero-tour-restart-btn { position: absolute; top: 16px; right: 16px; z-index: 3; width: 32px; height: 32px; border-radius: 50%; border: 1px solid rgba(255,255,255,.35); background: rgba(255,255,255,.12); color: white; display: grid; place-items: center; cursor: pointer; font-size: 13px; opacity: .7; transition: opacity .2s ease, background-color .2s ease, transform .2s ease; }
.hero-tour-restart-btn:hover { opacity: 1; background: rgba(255,255,255,.22); transform: scale(1.08) rotate(-12deg); }
.hero-tour-restart-btn:active { transform: scale(.94); }
@media (prefers-reduced-motion: reduce) {
    .hero-tour-restart-btn { transition: none; }
    .hero-tour-restart-btn:hover { transform: none; }
}
.hero-banner-content { position: relative; z-index: 2; max-width: min(620px, calc(100% - 132px)); }
.hero-banner h2 { font-size: clamp(24px, 4vw, 36px); letter-spacing: -.03em; margin: 0 0 12px; line-height: 1.1; }
.hero-banner p { font-size: 15px; color: rgba(255,255,255,.85); margin: 0 0 20px; }
.hero-banner-art { position: absolute; right: -20px; bottom: -40px; font-size: 180px; line-height: 1; transform: rotate(-15deg); opacity: 0.2; user-select: none; }
/* A card that doesn't fully fit was hard-clipped flush against the container edge (no padding,
   no fade) — read as "broken/cut off" rather than "scroll for more". The trailing mask fades
   it out instead, the standard affordance for this kind of row.
   padding-top: overflow-x:auto here forces the *used* value of overflow-y to auto too (per the
   CSS overflow spec, a non-visible value on one axis converts 'visible' on the other axis to
   'auto') — so this box clips vertically as well, even though only horizontal scrolling was
   ever wanted. .card-hover's translateY(-4px) hover lift was getting its top sliced off by
   that clip with no room to rise into; this padding is exactly its travel distance. */
.horizontal-scroll {
    display: flex; gap: 16px; overflow-x: auto; padding-top: 8px; padding-bottom: 16px; scroll-snap-type: x mandatory;
    mask-image: linear-gradient(to right, black calc(100% - 32px), transparent 100%);
    -webkit-mask-image: linear-gradient(to right, black calc(100% - 32px), transparent 100%);
}
.horizontal-scroll > * { flex: 0 0 170px; scroll-snap-align: start; }
.horizontal-scroll::-webkit-scrollbar { height: 6px; }

/* "Dokumen Terbaru Saya" cards. Icon animation is hover-triggered transform/opacity only (no
   continuously-running animation across up to 6 cards at once) — cheap regardless of how many
   are on screen, and only costs anything while a card is actually being looked at. */
.doc-card { display: flex; flex-direction: column; gap: 8px; padding: 10px; }
.doc-card-thumb {
    aspect-ratio: 16/10; background: var(--canvas); border-radius: 8px; display: grid; place-items: center;
    font-size: 38px; color: var(--primary); overflow: hidden;
}
.doc-card-thumb i { display: inline-flex; transition: transform .35s cubic-bezier(.34, 1.56, .64, 1); }
.doc-card:hover .doc-card-thumb i { transform: scale(1.18) rotate(-6deg); }
.doc-card-category { display: block; font-size: 9px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--primary); margin-bottom: 3px; }
.doc-card-title { margin: 0 0 6px; font-size: 12px; line-height: 1.35; }
.doc-card-title a {
    color: var(--ink); display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.doc-card-meta { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
/* Long status labels ("Menunggu Penetapan Reviewer") wrap to two lines here — the default
   .badge is a full pill (border-radius: 999px), which on a two-line box resolves to a large
   effective corner radius that pinches in from both sides and crowds the wrapped text. A small
   fixed radius keeps it a rounded rectangle instead, with even breathing room on every line. */
.doc-card-meta .badge { font-size: 9.5px; font-weight: 800; padding: 5px 8px; white-space: normal; text-align: left; border-radius: 8px; line-height: 1.4; }
.doc-card-date { font-size: 9.5px; color: var(--muted); }
@media (prefers-reduced-motion: reduce) {
    .doc-card-thumb i { transition: none; }
}
.horizontal-scroll::-webkit-scrollbar-thumb { background: #cbd5d1; border-radius: 10px; }
.rp-card { background: var(--surface); border-radius: 14px; padding: 14px; margin-bottom: 12px; box-shadow: 0 4px 15px rgba(0,0,0,.03); transition: background-color 0.3s ease; }
/* gap is the fix here, not justify-content alone: .rp-card-toggle's margin-left:auto (below)
   grabs ALL free space in the row to push itself to the far right, which — without a gap —
   left zero space for anything between the title text and an unread-count badge, so the badge
   sat flush against the text (measured 0px gap) instead of space-between splitting it evenly. */
/* font-size matches .sidebar-label (11px) — same role, a header grouping a list of items below
   it, just styled sentence-case here instead of the sidebar's uppercase treatment. Box padding,
   list icon, and item text below are all scaled down to match — a small header sitting over
   full-size content looked mismatched. */
.rp-card-title { font-size: 11px; font-weight: 800; margin: 0 0 12px; color: var(--ink); display: flex; justify-content: space-between; align-items: center; gap: 8px; }
/* Everything after the title lives in one .rp-card-body wrapper so opening/closing can animate
   as a single max-height + opacity transition — same technique (and the same reasoning) as
   .sidebar-menu: display:none/block has no transition, so that alone only ever animated open
   and snapped shut instantly on close. */
.rp-card-body { max-height: 600px; opacity: 1; overflow: hidden; transition: max-height .28s cubic-bezier(.4, 0, .2, 1), opacity .18s ease; }
.rp-card.is-collapsed .rp-card-body { max-height: 0; opacity: 0; pointer-events: none; }
.rp-card.is-collapsed .rp-card-title { margin-bottom: 0; }
@media (prefers-reduced-motion: reduce) {
    .rp-card-body { transition: none; }
}
.rp-card-toggle { border: 0; background: transparent; color: var(--muted); width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; cursor: pointer; flex: 0 0 auto; margin-left: auto; }
.rp-card-toggle:hover { color: var(--primary); background: var(--canvas); }
.rp-card-toggle i { transition: transform .2s ease; display: flex; line-height: 1; }
.rp-card.is-collapsed .rp-card-toggle i { transform: rotate(-90deg); }
.rp-list-item { display: flex; gap: 10px; align-items: center; padding: 8px 0; border-bottom: 1px dashed var(--line); }
.rp-list-item:last-child { border-bottom: 0; padding-bottom: 0; }
/* Matches .sidebar-icon's 32px/16px proportions (was 40px/18px) — same "small icon next to a
   label" role as the sidebar's own menu icons. */
.rp-list-item strong { font-size: 12px; }
.rp-list-item small { font-size: 11px; }
.rp-list-icon { width: 32px; height: 32px; border-radius: 9px; background: var(--primary-soft); color: var(--primary); display: grid; place-items: center; font-size: 15px; flex-shrink: 0; }
.rp-scroll-list { max-height: 200px; overflow-y: auto; padding-right: 4px; overscroll-behavior: contain; }
.rp-notes-scroll { max-height: 280px; }
.search-bar {
    background: var(--canvas); border: none; border-radius: 14px; padding: 10px 12px;
    display: flex; align-items: center; gap: 9px; width: calc(100% - 16px); margin: 0 8px 14px;
    box-shadow: inset 0 2px 5px rgba(0,0,0,.08), inset 0 -1px 0 rgba(255,255,255,.65);
    transition: box-shadow .2s ease, background-color .3s ease;
}
.search-bar:focus-within { box-shadow: inset 0 2px 5px rgba(0,0,0,.1), inset 0 -1px 0 rgba(255,255,255,.65), 0 0 0 3px var(--primary-soft); }
.search-bar span { color: var(--muted); font-size: 16px; display: flex; line-height: 1; transition: color .2s ease; }
.search-bar:focus-within span { color: var(--primary); }
.search-bar input { border: none; background: transparent; padding: 0; width: 100%; outline: none; font-size: 13px; color: var(--ink); min-width: 0; }
.search-bar input:focus { box-shadow: none; }
html[data-theme="dark"] .search-bar { box-shadow: inset 0 2px 5px rgba(0,0,0,.35), inset 0 -1px 0 rgba(255,255,255,.04); }
html[data-theme="dark"] .search-bar:focus-within { box-shadow: inset 0 2px 5px rgba(0,0,0,.4), inset 0 -1px 0 rgba(255,255,255,.04), 0 0 0 3px var(--primary-soft); }

/* GLOBAL SEARCH BALLOON: a speech-bubble popover triggered from the sidebar-tools pill (see
   app.js). Rendered outside .app-shell (sibling of #sidebar-flyout) on purpose — anything with
   position:fixed nested inside the .app-shell CSS grid paints under grid siblings like
   .right-panel regardless of z-index, the same stacking-context bug fixed earlier for the
   upload-guide popup and the "Info Dokumen" panel. */
.search-balloon {
    position: fixed; z-index: 80; width: min(340px, calc(100vw - 24px)); max-height: min(420px, calc(100vh - 24px));
    background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
    box-shadow: 0 18px 40px rgba(0,0,0,.18); display: flex; flex-direction: column; overflow: hidden;
    opacity: 0; transform: translateY(-6px) scale(.98); pointer-events: none;
    transition: opacity .18s ease, transform .18s ease;
}
.search-balloon.active { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.search-balloon[hidden] { display: none; }
/* Speech-bubble tail: a rotated square on the balloon's left edge, pointing back at the icon
   that opened it. The balloon always opens rightward (see app.js) since the sidebar it's
   triggered from is pinned to the left edge, so there's only ever one direction to draw this in. */
.search-balloon-arrow {
    position: absolute; top: 14px; left: -7px; width: 12px; height: 12px; background: var(--surface);
    border-left: 1px solid var(--line); border-bottom: 1px solid var(--line); transform: rotate(45deg);
}
.search-balloon-input { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--line); flex-shrink: 0; }
.search-balloon-input i { color: var(--muted); font-size: 15px; }
.search-balloon-input input { flex: 1; border: none; outline: none; background: transparent; font-size: 13px; color: var(--ink); min-width: 0; }
.search-balloon-clear { border: none; background: none; color: var(--muted); width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center; cursor: pointer; flex-shrink: 0; font-size: 11px; padding: 0; transition: color .15s ease, background-color .15s ease; }
.search-balloon-clear[hidden] { display: none; }
.search-balloon-clear:hover { color: var(--danger); background: var(--danger-soft); }
.search-balloon-results { overflow-y: auto; padding: 8px; }
.search-balloon-hint { padding: 14px 10px; margin: 0; text-align: center; font-size: 12.5px; color: var(--muted); }
.search-balloon-group { margin-bottom: 6px; }
.search-balloon-group-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: 6px 8px 2px; }
.search-balloon-item { display: flex; align-items: center; gap: 10px; padding: 8px; border-radius: 10px; text-decoration: none; color: var(--ink); transition: background-color .15s ease; }
.search-balloon-item:hover { background: var(--canvas); }
.search-balloon-item i { color: var(--primary); font-size: 15px; width: 20px; text-align: center; flex-shrink: 0; }
.search-balloon-item span { display: flex; flex-direction: column; min-width: 0; }
.search-balloon-item strong { font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-balloon-item small { font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
html[data-theme="dark"] .search-balloon { box-shadow: 0 18px 40px rgba(0,0,0,.5); }
/* z-index 65 (not 30): the sidebar/right-panel mobile drawers sit at z-index 60, so at 30 the
   topbar — and both its own open/close toggle buttons — used to vanish underneath whichever
   drawer was open, with no way to see or click a close control. */
.topbar { height: 0; min-height: 0; background: transparent; border-bottom: 0; display: flex; align-items: center; gap: 16px; padding: 0; position: relative; top: 0; z-index: 65; overflow: visible; transition: background-color 0.3s ease, border-color 0.3s ease; }
.topbar-title { font-weight: 800; }
.topbar-user { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.avatar { width: 38px; height: 38px; display: grid; place-items: center; border-radius: 50%; background: var(--primary-soft); color: var(--primary); font-weight: 900; overflow: hidden; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.app-content { padding: 18px 26px 26px; width: min(100%, 1440px); margin-inline: auto; animation: fade-in 0.3s ease-out forwards; }
.page-header { display: flex; justify-content: space-between; align-items: start; gap: 20px; margin-bottom: 24px; }
.page-header h1 { margin: 0; }
.page-header p { color: var(--muted); margin: 5px 0 0; }
.stat-card { padding: 20px; }
.stat-value { font-size: 34px; font-weight: 850; letter-spacing: -.04em; line-height: 1.05; }
.stat-label { color: var(--muted); font-size: 13px; margin-top: 7px; }
.stat-kicker { width: 38px; height: 38px; display: grid; place-items: center; border-radius: 11px; background: var(--primary-soft); color: var(--primary); margin-bottom: 18px; }
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); transition: background-color 0.3s ease, border-color 0.3s ease; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { text-align: left; color: var(--muted); font-size: 11px; letter-spacing: .07em; text-transform: uppercase; background: var(--canvas); padding: 13px 15px; border-bottom: 1px solid var(--line); transition: background-color 0.3s ease, border-color 0.3s ease; }
td { padding: 14px 15px; border-bottom: 1px solid var(--line); vertical-align: top; }
tr:last-child td { border-bottom: 0; }
tr:hover td { background: var(--canvas); }
.table-actions { display: flex; gap: 7px; flex-wrap: wrap; }
.form-card { max-width: 920px; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.field { display: flex; flex-direction: column; gap: 7px; }
.field-full { grid-column: 1 / -1; }
label { font-size: 13px; font-weight: 750; }
.help { color: var(--muted); font-size: 12px; }
form[method="GET"].card, form[method="get"].card { padding: 10px !important; margin-bottom: 14px !important; max-width: none !important; display: flex; align-items: flex-end; gap: 10px; flex-wrap: nowrap; overflow-x: auto; }
form[method="GET"].card.form-grid, form[method="get"].card.form-grid, form[method="GET"].card .form-grid, form[method="get"].card .form-grid { display: flex; align-items: flex-end; gap: 10px; flex-wrap: nowrap; flex: 1 1 auto; min-width: 0; }
form[method="GET"].card .field, form[method="get"].card .field { flex: 1 1 140px; min-width: 118px; gap: 4px; }
form[method="GET"].card .field-full, form[method="get"].card .field-full { grid-column: auto; }
form[method="GET"].card label, form[method="get"].card label { font-size: 12px; line-height: 1.1; }
form[method="GET"].card .actions, form[method="get"].card .actions { flex: 0 0 auto; margin: 0 !important; align-self: flex-end !important; gap: 8px; flex-wrap: nowrap; }
form[method="GET"].card input[type=text], form[method="GET"].card input[type=email], form[method="GET"].card input[type=date], form[method="GET"].card input[type=url], form[method="GET"].card select,
form[method="get"].card input[type=text], form[method="get"].card input[type=email], form[method="get"].card input[type=date], form[method="get"].card input[type=url], form[method="get"].card select { min-height: 38px; padding: 7px 10px; border-radius: 8px; }
.api-preview { margin: 0; max-height: 260px; overflow: auto; border: 1px solid var(--line); border-radius: 10px; background: var(--canvas); color: var(--ink); padding: 12px; font-size: 12px; white-space: pre-wrap; word-break: break-word; }
input[type=text], input[type=email], input[type=password], input[type=number], input[type=date], input[type=datetime-local], input[type=url], input[type=file], select, textarea {
    width: 100%; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); color: var(--ink); padding: 10px 12px; outline: none; transition: border .15s, box-shadow .15s, background-color 0.3s;
}
textarea { resize: vertical; min-height: 120px; }
input:focus, select:focus, textarea:focus { border-color: var(--primary-2); box-shadow: 0 0 0 3px rgba(14,118,104,.12); }
/* Belt-and-suspenders for the native <select> popup: color-scheme (set on :root above) makes
   the browser pick a matching palette for the parts it renders itself, but not every engine
   fully honors that for <option> rows, so we also color them explicitly to guarantee contrast
   in both themes. --surface-solid (not --surface) because the popup list can't render a
   gradient background. */
select option { background-color: var(--surface-solid); color: var(--ink); }
select option:checked, select option:hover { background-color: var(--primary); color: #fff; }
select option:disabled { color: var(--muted); }
/* Show/hide password toggle — app.js wraps every input[type=password] in this at runtime. */
.password-field { position: relative; }
.password-field input { padding-right: 42px; }
.password-toggle {
    position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
    width: 30px; height: 30px; border: none; background: none; color: var(--muted);
    display: grid; place-items: center; cursor: pointer; border-radius: 7px; transition: color .15s, background-color .15s;
}
.password-toggle:hover { color: var(--primary); background: var(--canvas); }
.check { display: flex; align-items: center; gap: 9px; }
.check input { width: 17px; height: 17px; }
.profile-photo-editor { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: 18px; align-items: start; padding: 14px; border: 1px solid var(--line); border-radius: 14px; background: var(--canvas); }
.profile-photo-stage { position: relative; width: 180px; aspect-ratio: 1; border-radius: 50%; overflow: hidden; background: var(--surface); border: 1px solid var(--line); display: grid; place-items: center; }
.profile-photo-stage canvas { width: 100%; height: 100%; display: block; }
.profile-photo-empty { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; gap: 8px; color: var(--muted); background: var(--surface); text-align: center; font-size: 12px; }
.profile-photo-empty i { font-size: 30px; line-height: 1; }
.profile-photo-stage.has-image .profile-photo-empty { display: none; }
.profile-photo-controls { min-width: 0; display: grid; gap: 12px; }
/* Fine-tune controls (scale/geser/rotate/flip) only matter once a photo is actually loaded —
   showing them alongside an empty "Pilih foto profil" placeholder was pure clutter competing
   with the password card next to it. .has-image is toggled by the avatar editor JS the moment
   an existing or newly-picked photo loads into the canvas. */
.avatar-range-grid, .profile-photo-actions { display: none; }
.profile-photo-editor:has(.profile-photo-stage.has-image) .avatar-range-grid { display: grid; }
.profile-photo-editor:has(.profile-photo-stage.has-image) .profile-photo-actions { display: flex; }
.avatar-range-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.avatar-range-grid label { display: grid; gap: 6px; color: var(--muted); font-size: 12px; }
.avatar-range-grid input { width: 100%; }
.profile-photo-actions { gap: 8px; flex-wrap: wrap; }
.alert { border-radius: 11px; padding: 13px 15px; margin-bottom: 18px; border: 1px solid; animation: pop-in 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; transform-origin: top center; opacity: 0; }
.alert-success { color: var(--success); background: var(--success-soft); border-color: #c3e7d2; }
.alert-error { color: var(--danger); background: var(--danger-soft); border-color: #f0caca; }
.alert-warning { color: var(--warning); background: var(--warning-soft); border-color: #eddcaa; }
.empty { text-align: center; padding: 46px 25px; color: var(--muted); }
.detail-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, .8fr); gap: 22px; align-items: start; }
.stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; min-width: 0; }
.timeline { position: relative; margin-left: 9px; }
.timeline-item { border-left: 2px solid var(--line); padding: 0 0 24px 25px; position: relative; }
.timeline-item:before { content: ""; position: absolute; width: 11px; height: 11px; border-radius: 50%; background: var(--primary); left: -6.5px; top: 5px; }
.timeline-item:last-child { border-left-color: transparent; }
.discussion { display: flex; gap: 12px; padding-block: 16px; border-bottom: 1px solid var(--line); }
.discussion:last-child { border-bottom: 0; }
.discussion-body { flex: 1; min-width: 0; }
.discussion-head { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
.login-page { min-height: 100vh; display: grid; grid-template-columns: 1.1fr .9fr; background: var(--surface); }
.login-side { background: linear-gradient(145deg, #073f39, #0e7668); color: white; padding: 70px; display: flex; flex-direction: column; justify-content: space-between; gap: 28px; }
.login-side h1 { font-size: clamp(38px, 5vw, 64px); letter-spacing: -.045em; line-height: 1.06; }
.login-form { display: grid; place-items: center; padding: 40px; }
.login-form .card { width: min(440px, 100%); padding: 34px; box-shadow: var(--shadow); }

/* Login mini-slider: plain CSS transform track (see app.js), image or muted-autoplay YouTube
   per slide, whole-card click-through. aspect-ratio keeps it a fixed, light shape at any
   screen size instead of a fixed pixel height. */
.mini-slider { position: relative; width: 100%; max-width: 420px; border-radius: 16px; overflow: hidden; box-shadow: 0 20px 50px rgba(0,0,0,.25); }
.mini-slider-track { display: flex; transition: transform .5s cubic-bezier(.4,0,.2,1); }
.mini-slide { position: relative; flex: 0 0 100%; aspect-ratio: 16/9; background: rgba(255,255,255,.08); }
.mini-slide-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0; }
/* .mini-slide-video shares .mini-slide-media's sizing (fills the 16:9 .mini-slide box), but
   object-fit is a no-op on the wrapper <div> — it only matters for the <img> case. The child
   iframe itself had no sizing rule at all before, so give it one, oversized + centered like
   the hero background video, to also crop out YouTube's internal letterbox bars. */
.mini-slide-video { overflow: hidden; }
.mini-slide-video iframe { position: absolute; top: 50%; left: 50%; width: 100%; height: 100%; border: 0; transform: translate(-50%, -50%) scale(1.35); pointer-events: none; }
.mini-slide-caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 14px 16px; background: linear-gradient(to top, rgba(0,0,0,.72), transparent); pointer-events: none; }
.mini-slide-caption strong { display: block; font-size: 14px; color: white; }
.mini-slide-caption span { display: block; font-size: 12px; color: rgba(255,255,255,.82); margin-top: 2px; }
.mini-slide-click { position: absolute; inset: 0; z-index: 5; }
.mini-slider-dots { position: absolute; bottom: 10px; right: 14px; display: flex; gap: 6px; z-index: 6; }
.mini-slider-dots button { width: 7px; height: 7px; border-radius: 50%; border: none; background: rgba(255,255,255,.45); cursor: pointer; padding: 0; transition: background-color .2s, width .2s; }
.mini-slider-dots button.active { background: white; width: 18px; border-radius: 4px; }
.mini-slider-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 6; width: 30px; height: 30px; border-radius: 50%; border: none; background: rgba(8,20,17,.4); color: white; display: grid; place-items: center; cursor: pointer; opacity: 0; transition: opacity .18s, background-color .18s; }
.mini-slider:hover .mini-slider-nav { opacity: 1; }
.mini-slider-nav:hover { background: rgba(8,20,17,.65); }
.mini-slider-nav i { font-size: 15px; }
.mini-slider-prev { left: 10px; }
.mini-slider-next { right: 10px; }
@media (max-width: 1280px) {
    .mini-slider { max-width: 340px; }
}
@media (hover: none) {
    /* No hover on touch devices — keep the arrows reachable instead of permanently invisible. */
    .mini-slider-nav { opacity: 1; }
}
.invoice, .ticket-paper { max-width: 820px; margin: 30px auto; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 36px; transition: background-color 0.3s ease, border-color 0.3s ease; }
.ticket-code { font-size: clamp(26px, 6vw, 52px); font-weight: 900; letter-spacing: .08em; text-align: center; padding: 25px; border: 2px dashed var(--primary); border-radius: var(--radius); color: var(--primary); }
.pagination { display: flex; gap: 7px; list-style: none; padding: 0; margin: 20px 0; }
.pagination a, .pagination span { display: block; padding: 7px 11px; background: var(--surface); border: 1px solid var(--line); border-radius: 7px; transition: background-color 0.3s ease, border-color 0.3s ease; }
.mobile-sidebar-toggle, .mobile-rightpanel-toggle { display: none; }
hr { border: 0; border-top: 1px solid var(--line); margin: 22px 0; }
code { background: #eef3f2; border-radius: 5px; padding: 2px 5px; }

@media (max-width: 1020px) {
    .grid-4 { grid-template-columns: repeat(2, 1fr); }
    .grid-3 { grid-template-columns: repeat(2, 1fr); }
    .detail-grid { grid-template-columns: 1fr; }
    .hero-grid { grid-template-columns: 1fr; }
    /* Keep mobile hero light: no autoplaying background video/image, just the gradient + text. */
    .hero-slide-bg { display: none; }
    .app-shell { grid-template-columns: 1fr; }
    .app-shell.has-right-panel { grid-template-columns: 1fr; }
    /* Right panel becomes an off-canvas drawer (same mechanic as .sidebar below) instead of disappearing. */
    .right-panel { position: fixed; top: 0; right: -100%; z-index: 60; width: min(340px, 88vw); height: 100vh; transition: right .25s ease; border-left: none; box-shadow: -4px 0 24px rgba(0,0,0,.1); }
    body.rightpanel-mobile-open .right-panel { right: 0; }
    .sidebar { position: fixed; left: -290px; z-index: 60; width: 270px; transition: left .2s ease; border-right: none; box-shadow: 4px 0 24px rgba(0,0,0,.1); }
    body.sidebar-open .sidebar { left: 0; }
    .mobile-sidebar-toggle, .mobile-rightpanel-toggle { display: inline-flex; }
    /* .rightpanel-inline-handle (not just .rightpanel-handle — different button, different job):
       it's positioned via right: var(--right-w, 300px), assuming the right panel is still
       in-flow at its normal desktop width. Below 1020px the panel becomes an off-canvas
       drawer instead, so that math no longer matches anything on screen and the handle was
       floating loose in the middle of the page, overlapping content. */
    .sidebar-collapse-toggle, .rightpanel-handle, .rightpanel-inline-handle { display: none !important; }
    /* Give the topbar a real header-bar treatment for the whole off-canvas range (760-1020px
       previously fell through the cracks: 0 height, transparent, non-sticky — so the two
       drawer-toggle buttons had no bar to sit in and floated directly over page content). */
    .topbar { height: 58px; padding: 0 14px; justify-content: space-between; position: sticky; top: 0; background: var(--surface); border-bottom: 1px solid var(--line); overflow: visible; }
    /* Dims the page behind an open drawer so it reads as a temporary overlay layer (and gives
       a large, obvious click-to-close target) instead of just "content got covered". */
    .drawer-backdrop { position: fixed; inset: 0; background: rgba(8, 15, 13, .45); z-index: 55; opacity: 0; pointer-events: none; transition: opacity .25s ease; }
    body.sidebar-open .drawer-backdrop, body.rightpanel-mobile-open .drawer-backdrop { opacity: 1; pointer-events: auto; }
    .sidebar-tools { justify-content: flex-end; }
    .login-page { grid-template-columns: 1fr; }
    .login-side { display: none; }
}
@media (max-width: 760px) {
    /* opacity/transform (not display:none/flex) so open AND close both animate — same fix as
       the sidebar accordion and AI chat balloon elsewhere in this file. */
    .public-links {
        display: flex; position: absolute; top: 71px; left: 0; right: 0; background: var(--surface); padding: 18px;
        border-bottom: 1px solid var(--line); flex-direction: column; align-items: stretch;
        box-shadow: 0 14px 34px rgba(0,0,0,.12); z-index: 40;
        opacity: 0; transform: translateY(-10px); pointer-events: none;
        transition: opacity .22s ease, transform .22s cubic-bezier(.34,1.56,.64,1);
    }
    body.public-menu-open .public-links { opacity: 1; transform: translateY(0); pointer-events: auto; }
    .btn.mobile-menu { display: inline-flex; margin-left: auto; }
    .nav-actions .btn-outline { display: none; }
    .grid-2, .grid-3, .grid-4, .form-grid, .footer-grid { grid-template-columns: 1fr; }
    form[method="GET"].card, form[method="get"].card { flex-wrap: wrap; overflow-x: visible; }
    form[method="GET"].card.form-grid, form[method="get"].card.form-grid, form[method="GET"].card .form-grid, form[method="get"].card .form-grid { flex-wrap: wrap; }
    form[method="GET"].card .field, form[method="get"].card .field { flex-basis: 100%; }
    .feature-strip .card { grid-template-columns: 1fr; }
    .feature-item + .feature-item { border-left: 0; border-top: 1px solid var(--line); }
    .section { padding-block: 50px; }
    .hero { min-height: 520px; }
    .page-header, .section-heading { flex-direction: column; align-items: stretch; }
    .app-content { padding: 18px 14px; }
    .topbar-user small { display: none; }
    .hero-banner { padding: 24px 20px; min-height: 0; flex-direction: column; align-items: flex-start; border-radius: 16px; gap: 18px; }
    .hero-profile { width: 86px; height: 86px; }
    .hero-banner-content { max-width: 100%; }
    .hero-banner-art { font-size: 130px; right: -28px; bottom: -36px; }
    .profile-photo-editor { grid-template-columns: 1fr; }
    .profile-photo-stage { width: min(220px, 100%); margin-inline: auto; }
    .avatar-range-grid { grid-template-columns: 1fr; }
    .login-form { padding: 20px; }
    .invoice, .ticket-paper { margin: 0; border-radius: 0; border: 0; padding: 22px; }
    /* Fixed 260px cards left a random, mid-content sliver of the next card peeking past the
       edge (e.g. a badge chopped off mid-word) — reads as broken, not "swipe for more". Sizing
       relative to the viewport makes the peek a deliberate, consistent proportion instead, and
       the wider fade below (56px vs. the desktop 32px) makes sure that whole peek actually fades
       to transparent rather than staying opaque right up to the cut. */
    .horizontal-scroll > * { flex-basis: 82%; }
    .horizontal-scroll { mask-image: linear-gradient(to right, black calc(100% - 56px), transparent 100%); -webkit-mask-image: linear-gradient(to right, black calc(100% - 56px), transparent 100%); }
}
@media print {
    .no-print, .public-header, .public-footer, .sidebar, .topbar { display: none !important; }
    body, .app-main, .app-content { background: white; padding: 0; }
    .invoice, .ticket-paper { border: 0; box-shadow: none; margin: 0 auto; }
}

/* --- ANIMATIONS & CUSTOM MODAL --- */

/* Page Transitions */
/* Page Transitions */
@keyframes fade-in {
    0% { opacity: 0; }
    100% { opacity: 1; }
}

/* Pop In (Alerts & Modals) */
@keyframes pop-in {
    0% { opacity: 0; transform: scale(0.85) translateY(10px); }
    100% { opacity: 1; transform: scale(1) translateY(0); }
}

/* DASHBOARD POPUP: bounce in on open, bounce out on close (Super Admin-managed announcement,
   see superadmin/dashboard-settings). Multi-stage keyframes (rather than pop-in's single
   overshoot) so the bounce reads clearly rather than as a subtle ease — this is a deliberate,
   attention-getting announcement, not a routine confirm dialog. transform/opacity only, so it's
   cheap (GPU-composited, no layout/paint cost) regardless of how much rich-text content is
   inside the box. */
@keyframes dashboard-popup-bounce-in {
    0% { opacity: 0; transform: scale(.4) translateY(50px); }
    55% { opacity: 1; transform: scale(1.06) translateY(-8px); }
    75% { transform: scale(.96) translateY(3px); }
    100% { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes dashboard-popup-bounce-out {
    0% { opacity: 1; transform: scale(1) translateY(0); }
    30% { transform: scale(1.05) translateY(-6px); }
    100% { opacity: 0; transform: scale(.4) translateY(40px); }
}
.dashboard-popup-overlay {
    position: fixed; inset: 0; z-index: 210; display: grid; place-items: center; padding: 20px;
    background: rgba(11, 47, 43, 0.45); backdrop-filter: blur(4px);
    opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.dashboard-popup-overlay.active { opacity: 1; pointer-events: auto; }
.dashboard-popup-overlay[hidden] { display: none; }
.dashboard-popup-box {
    background: var(--surface); border-radius: 18px; padding: 28px; width: min(560px, 100%);
    max-height: min(80vh, 720px); overflow-y: auto; position: relative;
    box-shadow: 0 24px 60px rgba(0,0,0,.22);
    animation: dashboard-popup-bounce-in .55s cubic-bezier(.34, 1.56, .64, 1) both;
}
.dashboard-popup-box.is-closing { animation: dashboard-popup-bounce-out .4s cubic-bezier(.36, 0, .66, -0.56) both; }
.dashboard-popup-close {
    position: absolute; top: 14px; right: 14px; width: 30px; height: 30px; border-radius: 50%;
    border: none; background: var(--canvas); color: var(--muted); font-size: 18px; line-height: 1;
    cursor: pointer; display: grid; place-items: center; transition: color .15s ease, background-color .15s ease;
}
.dashboard-popup-close:hover { background: var(--danger-soft); color: var(--danger); }
.dashboard-popup-title { margin: 0 32px 12px 0; font-size: 20px; font-weight: 800; letter-spacing: -.01em; }
.dashboard-popup-body { font-size: 15px; }
.dashboard-popup-body:empty { display: none; }
@media (max-width: 640px) {
    .dashboard-popup-box { padding: 20px; border-radius: 14px; max-height: 85vh; }
}
@media (prefers-reduced-motion: reduce) {
    .dashboard-popup-box, .dashboard-popup-box.is-closing { animation: pop-in .15s ease both; }
}

/* DASHBOARD RUNNING TEXT: pure CSS marquee (no JS animation loop) — two copies of the same text
   sit side by side in a flex track that scrolls left by exactly one copy's width (-50%), so the
   loop is seamless without needing to measure text width in JS. transform-only animation, cheap
   regardless of viewport size or text length. */
.dashboard-marquee {
    margin-top: 18px; overflow: hidden; background: var(--surface); border: 1px solid var(--line);
    border-radius: 999px; padding: 10px 0; box-shadow: 0 4px 15px rgba(0,0,0,.03);
}
.dashboard-marquee-track {
    display: flex; width: max-content; gap: 80px; animation: dashboard-marquee-scroll 22s linear infinite;
}
.dashboard-marquee-track span {
    white-space: nowrap; font-size: 13.5px; font-weight: 600; color: var(--ink);
}
.dashboard-marquee:hover .dashboard-marquee-track { animation-play-state: paused; }
@keyframes dashboard-marquee-scroll {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
    .dashboard-marquee { overflow-x: auto; }
    .dashboard-marquee-track { animation: none; }
    .dashboard-marquee-track span:last-child { display: none; }
}

/* APPLICATION TOUR (onboarding + on-demand replay, see app.js setupTour()). The overlay itself
   blocks all clicks (pointer-events: auto) so the highlighted element can't be clicked through
   by accident mid-tour (e.g. clicking a spotlighted nav link would navigate away and strand the
   tour) — only the tooltip's own Lanjut/Kembali/Lewati controls work. The spotlight is a single
   small positioned box using the box-shadow: 0 0 0 9999px trick for the dimmed cutout, rather
   than a real image mask — cheap, and it animates smoothly between targets with a plain
   top/left/width/height transition. z-index sits above the dashboard announcement popup (210)
   since the tour is the more actively-guided experience of the two if both ever appear. */
/* z-index 960: found by testing, not guessing — the "Panel Kanan" step's tooltip can land in the
   bottom-right corner where the Simpi mascot floats fixed at z-index 950, and the mascot was
   winning that stack-order fight and intercepting clicks meant for the tour's own Lanjut button.
   Also hide the mascot outright for the tour's duration (body.tour-active below) rather than
   just out-ranking it, since a floating cat behind the tour's spotlight/tooltip is visual noise
   regardless of whether it's clickable. */
.tour-overlay { position: fixed; inset: 0; z-index: 960; pointer-events: auto; opacity: 0; transition: opacity .2s ease; }
body.tour-active .ai-mascot-wrap { opacity: 0; pointer-events: none; transition: opacity .2s ease; }
.tour-overlay.active { opacity: 1; }
.tour-overlay[hidden] { display: none; }
/* Default (no inline overrides) is a zero-size box centered on screen: its box-shadow spread
   still dims the whole viewport uniformly with no cutout — exactly what a centered, no-target
   step (welcome/closing) needs. positionOnTarget() overrides top/left/width/height inline to
   move+resize it into a real cutout around the current target; positionCentered() clears those
   inline styles back to this default rather than using the `hidden` attribute — it never
   actually stops rendering (its shadow always paints), so `hidden` would be a misleading name
   for what's really just "no cutout, dim everything" (see this file's other `[hidden]` fixes —
   that attribute means "not rendered", which doesn't apply here). */
.tour-spotlight {
    position: fixed; top: 50%; left: 50%; width: 0; height: 0; pointer-events: none; border-radius: 14px;
    box-shadow: 0 0 0 9999px rgba(11, 31, 28, .68);
    transition: top .3s cubic-bezier(.4, 0, .2, 1), left .3s cubic-bezier(.4, 0, .2, 1),
                width .3s cubic-bezier(.4, 0, .2, 1), height .3s cubic-bezier(.4, 0, .2, 1);
}
.tour-tooltip {
    position: fixed; z-index: 2; background: var(--surface); border-radius: 14px; padding: 18px 20px;
    box-shadow: 0 20px 50px rgba(0,0,0,.25); width: min(340px, calc(100vw - 24px));
    animation: pop-in .3s cubic-bezier(.175, .885, .32, 1.275) both;
}
/* .tour-tooltip-center itself carries no positioning — top/left are computed and set inline by
   positionCentered() in app.js instead of a transform:translate(-50%,-50%) trick, because the
   pop-in animation above already animates `transform` (scale/translateY); a plain (non-!important)
   `transform` here would lose that fight against the animation's own filled end-state and the
   tooltip would render at its un-recentered top-left origin — off-screen on narrow viewports.
   Computing real pixel top/left avoids fighting over the same CSS property entirely. */
.tour-tooltip-step { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--primary); margin-bottom: 6px; }
.tour-tooltip-title { margin: 0 0 8px; font-size: 17px; font-weight: 800; letter-spacing: -.01em; }
.tour-tooltip-body { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--muted); }
.tour-tooltip-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 16px; }
.tour-skip { border: none; background: none; color: var(--muted); font-size: 12.5px; font-weight: 600; cursor: pointer; padding: 4px 0; }
.tour-skip:hover { color: var(--danger); }
.tour-tooltip-nav { display: flex; gap: 8px; }
.tour-tooltip-nav [data-tour-prev][hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
    .tour-overlay { transition: none; }
    .tour-spotlight { transition: none; }
    .tour-tooltip { animation: none; }
}

/* Ripple Effect */
.ripple {
    position: absolute;
    border-radius: 50%;
    transform: scale(0);
    animation: ripple-anim 0.5s linear;
    background: rgba(255, 255, 255, 0.4);
    pointer-events: none;
}
.btn-outline .ripple, .btn-ghost .ripple { background: rgba(0, 0, 0, 0.08); }
@keyframes ripple-anim {
    to { transform: scale(4); opacity: 0; }
}

/* Custom Confirm Modal */
.custom-modal-overlay {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: rgba(11, 47, 43, 0.4); backdrop-filter: blur(4px);
    display: flex; align-items: center; justify-content: center;
    z-index: 9999; opacity: 0; transition: opacity 0.25s;
    padding: 20px;
}
.custom-modal-overlay.active { opacity: 1; }
.custom-modal-box {
    background: var(--surface); border-radius: 16px; padding: 24px;
    width: min(400px, 100%); box-shadow: 0 20px 50px rgba(0,0,0,0.15);
    animation: pop-in 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
    text-align: center; transition: background-color 0.3s ease;
}
.custom-modal-icon {
    width: 48px; height: 48px; background: var(--warning-soft); color: var(--warning);
    border-radius: 50%; display: grid; place-items: center; font-size: 24px;
    margin: 0 auto 16px;
}
.custom-modal-title { font-size: 18px; font-weight: 800; margin: 0 0 8px; color: var(--ink); }
.custom-modal-text { font-size: 14px; color: var(--muted); margin: 0 0 24px; }
.custom-modal-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.custom-modal-box .btn { padding: 12px; font-size: 14px; }

/* Shiny Button Effect */
.btn::after {
    content: ""; position: absolute; top: 0; left: -100%; width: 50%; height: 100%;
    background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0) 100%);
    transform: skewX(-25deg); pointer-events: none;
}
.btn:hover::after {
    animation: shine 0.65s ease-out forwards;
}
.btn-outline::after, .btn-ghost::after { display: none; }
@keyframes shine {
    0% { left: -100%; }
    100% { left: 200%; }
}

/* --- NOTES CARD (right panel) --- */
.rp-note-item { padding: 8px 0; border-bottom: 1px dashed var(--line); }
.rp-note-item:last-child { border-bottom: 0; padding-bottom: 0; }
.rp-note-item-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.rp-note-item-head strong { font-size: 12px; color: var(--ink); }
.rp-note-item p { margin: 4px 0 0; font-size: 11px; color: var(--muted); }
.rp-note-actions { display: flex; gap: 2px; flex-shrink: 0; }
.rp-note-actions button { background: none; border: none; cursor: pointer; color: var(--muted); font-size: 12px; padding: 4px; border-radius: 6px; line-height: 1; }
.rp-note-actions button:hover { color: var(--ink); background: var(--canvas); }
.rp-note-actions button.active { color: var(--accent); }
.rp-notification-item { margin: 0; border-bottom: 1px dashed var(--line); }
.rp-notification-item:last-child { border-bottom: 0; }
.rp-notification-item button { width: 100%; border: 0; background: transparent; padding: 8px 0; display: flex; align-items: center; gap: 10px; text-align: left; color: inherit; cursor: pointer; }
.rp-notification-item button:hover { color: var(--primary); }
.rp-notification-item.unread .rp-list-icon { background: var(--info-soft); color: var(--info); }
.rp-notification-item strong { display: block; font-size: 12px; color: var(--ink); }
.rp-notification-item small { display: block; font-size: 11px; color: var(--muted); line-height: 1.35; margin-top: 2px; }

/* --- AI ASSISTANT MASCOT --- */
.ai-mascot-wrap {
    position: fixed; right: 28px; bottom: 24px; z-index: 950;
    display: flex; flex-direction: column; align-items: flex-end; gap: 12px;
}
.ai-mascot-btn {
    position: relative; width: 68px; height: 68px; border-radius: 50%; border: none; padding: 0; cursor: pointer;
    background: linear-gradient(160deg, #d97a4a, #b1502a);
    box-shadow: 0 10px 26px rgba(150, 60, 20, .35), 0 2px 0 rgba(255,255,255,.25) inset;
    display: grid; place-items: center;
    transition: transform .2s cubic-bezier(.34,1.56,.64,1), box-shadow .2s;
}
.ai-mascot-btn:hover { transform: translateY(-3px) scale(1.04); box-shadow: 0 14px 30px rgba(150,60,20,.4), 0 2px 0 rgba(255,255,255,.25) inset; }
.ai-mascot-btn:active { transform: scale(.94); }
html[data-theme="dark"] .ai-mascot-btn { background: linear-gradient(160deg, #c9663a, #8f3d1d); box-shadow: 0 10px 26px rgba(0,0,0,.5), 0 2px 0 rgba(255,255,255,.12) inset; }

/* --- CAT MASCOT (character + expression states ported from the provided prototype) --- */
.cat-scale-wrap { width: 68px; height: 68px; display: flex; align-items: center; justify-content: center; overflow: visible; }
.cat-head {
    --cat-primary: #FF9F43; --cat-secondary: #EE5253; --cat-white: #FFFFFF;
    --cat-dark: #222F3E; --cat-pink: #FF9FF3;
    position: relative; width: 200px; height: 180px; flex-shrink: 0;
    transform: scale(.27); transform-origin: center;
    transition: transform .15s ease-out;
}
.cat-head.idle { animation: cat-breathe 3s ease-in-out infinite; }
.cat-head.cheer { animation: cat-jump .6s ease-in-out infinite; }
.cat-head.sad { animation: cat-droop 3s ease-in-out infinite; }

.ear { position: absolute; width: 70px; height: 70px; background-color: var(--cat-primary); top: -20px; z-index: -1; border-radius: 15px 15px 0 0; overflow: hidden; transition: transform .3s ease; }
.ear.left { left: 10px; transform: rotate(-30deg) skewX(-15deg); }
.ear.right { right: 10px; transform: rotate(30deg) skewX(15deg); }
.is-near .ear.left { transform: rotate(-38deg) skewX(-15deg); }
.is-near .ear.right { transform: rotate(38deg) skewX(15deg); }
.ear-inner { position: absolute; width: 40px; height: 50px; background-color: var(--cat-pink); bottom: 5px; left: 15px; border-radius: 10px 10px 0 0; }

.face { position: absolute; width: 100%; height: 100%; background-color: var(--cat-primary); border-radius: 50% 50% 45% 45% / 55% 55% 45% 45%; overflow: hidden; box-shadow: inset -15px -15px 20px rgba(0,0,0,.1), 0 15px 25px rgba(0,0,0,.2); }
.white-fur { position: absolute; background-color: var(--cat-white); border-radius: 50%; }
.white-fur.left { width: 120px; height: 120px; bottom: -30px; left: -20px; }
.white-fur.right { width: 120px; height: 120px; bottom: -30px; right: -20px; }
.white-fur.bottom { width: 140px; height: 100px; bottom: -20px; left: 50%; transform: translateX(-50%); }

.cat-eyebrow { position: absolute; width: 30px; height: 8px; background-color: var(--cat-secondary); border-radius: 10px; top: 50px; opacity: 0; transition: all .3s ease; z-index: 3; }
.cat-eyebrow.left { left: 40px; transform: rotate(-10deg); }
.cat-eyebrow.right { right: 40px; transform: rotate(10deg); }

.eyes { position: absolute; top: 65px; width: 100%; display: flex; justify-content: space-evenly; padding: 0 30px; box-sizing: border-box; z-index: 2; }
.eye { position: relative; width: 45px; height: 45px; background-color: var(--cat-white); border-radius: 50%; box-shadow: 0 3px 0 var(--cat-secondary); display: flex; justify-content: center; align-items: center; overflow: hidden; transition: all .3s ease; }
/* Idle blink: only while resting (idle with no expression state active — a happy/angry/etc.
   flash already reshapes .eye for its own purpose, so blinking on top of that would fight it).
   :not([class*="state-"]) works because setCatState() keeps the "idle" class alongside
   "state-X" for most expressions rather than removing it, so .cat-head.idle alone would still
   match during those too. transform:scaleY only, so it's as cheap as the existing gaze-tracking
   transform right below it — no continuous cost beyond a periodic 200ms squash-and-release. */
@keyframes cat-blink { 0%, 92%, 100% { transform: scaleY(1); } 95% { transform: scaleY(.08); } }
.cat-head.idle:not([class*="state-"]) .eye { animation: cat-blink 6s ease-in-out infinite; transform-origin: center; }
.cat-head.idle:not([class*="state-"]) .eye.right { animation-delay: -.08s; }
@media (prefers-reduced-motion: reduce) {
    .eye { animation: none !important; }
}
.pupil { position: absolute; width: 30px; height: 30px; background-color: var(--cat-dark); border-radius: 50%; transform: translate(var(--pupil-x, 0px), var(--pupil-y, 0px)); transition: transform .12s ease-out, width .3s, height .3s, background .3s; }
.sparkle { position: absolute; width: 10px; height: 10px; background-color: white; border-radius: 50%; top: 4px; left: 4px; }

.muzzle { position: absolute; top: 110px; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; z-index: 3; }
.nose { width: 20px; height: 14px; background-color: var(--cat-pink); border-radius: 50% 50% 50% 50% / 30% 30% 70% 70%; margin-bottom: 5px; transition: background .3s; }
.mouth-container { display: flex; justify-content: center; position: relative; transition: all .3s; }
.mouth { width: 15px; height: 12px; border-bottom: 3px solid var(--cat-dark); border-radius: 0 0 15px 15px; }
.mouth.left { border-left: 3px solid var(--cat-dark); border-right: 1.5px solid transparent; border-bottom-left-radius: 15px; }
.mouth.right { border-right: 3px solid var(--cat-dark); border-left: 1.5px solid transparent; border-bottom-right-radius: 15px; }
.mouth-open { position: absolute; top: 8px; width: 14px; height: 16px; background: var(--cat-secondary); border-radius: 0 0 15px 15px; opacity: 0; transition: opacity .3s; }

.whiskers { position: absolute; top: 10px; width: 40px; height: 30px; transition: transform .3s; }
.whiskers.left { right: 35px; }
.whiskers.right { left: 35px; }
.whisker { width: 40px; height: 2px; background-color: rgba(0,0,0,.15); position: absolute; border-radius: 2px; }
.whiskers.left .whisker.top { top: 0; transform: rotate(10deg); }
.whiskers.left .whisker.mid { top: 10px; transform: rotate(0deg); }
.whiskers.left .whisker.bot { top: 20px; transform: rotate(-10deg); }
.whiskers.right .whisker.top { top: 0; transform: rotate(-10deg); }
.whiskers.right .whisker.mid { top: 10px; transform: rotate(0deg); }
.whiskers.right .whisker.bot { top: 20px; transform: rotate(10deg); }

/* Expression states, applied to #cat-head by app.js and mapped to real events (see the AI ASSISTANT MASCOT section there):
   happy = click reaction, sick = AI error/daily limit reached, sad = logout farewell,
   sleep = idle escalation, shocked = waking back up, angry = clicked 5x rapidly (easter egg), cheer = first-login welcome. */
.state-happy .eye { border-radius: 50% 50% 10px 10px; height: 25px; top: 10px; box-shadow: none; border-bottom: 5px solid var(--cat-primary); }
.state-happy .mouth-container { transform: scale(1.2) translateY(-2px); }
.state-happy .whiskers.left { transform: rotate(-10deg); }
.state-happy .whiskers.right { transform: rotate(10deg); }

.state-cheer .eye { transform: scale(1.1); }
.state-cheer .pupil { width: 35px; height: 35px; }
.state-cheer .sparkle { width: 14px; height: 14px; }
.state-cheer .mouth { border-color: transparent; }
.state-cheer .mouth-open { opacity: 1; height: 24px; width: 20px; }

.state-angry .cat-eyebrow { opacity: 1; }
.state-angry .cat-eyebrow.left { transform: rotate(25deg) translateY(5px); }
.state-angry .cat-eyebrow.right { transform: rotate(-25deg) translateY(5px); }
.state-angry .eye { border-top: 8px solid var(--cat-secondary); border-radius: 10px 10px 50% 50%; }
.state-angry .pupil { width: 15px; height: 15px; }
.state-angry .ear.left { transform: rotate(-60deg) translateY(10px); }
.state-angry .ear.right { transform: rotate(60deg) translateY(10px); }
.state-angry .mouth-container { transform: scale(.8); }

.cat-head.state-sleep .eye { height: 4px; background-color: var(--cat-dark); border-radius: 2px; top: 20px; box-shadow: none; }
.state-sleep .pupil { display: none; }
.state-sleep .ear.left { transform: rotate(-45deg); }
.state-sleep .ear.right { transform: rotate(45deg); }
.cat-head.state-sleep { animation: cat-breathe-sleep 4s ease-in-out infinite; }

.state-sick .eye { background-color: #BADC58; }
.state-sick .pupil { animation: cat-spin 1.5s linear infinite; width: 20px; height: 20px; }
.state-sick .ear { transform: rotate(0) translateY(10px); }
.state-sick .mouth-container { transform: rotate(15deg); }
.state-sick .nose { background-color: #7ed6df; }

.state-sad .cat-eyebrow { opacity: 1; background-color: var(--cat-dark); }
.state-sad .cat-eyebrow.left { transform: rotate(-20deg) translateY(-5px); }
.state-sad .cat-eyebrow.right { transform: rotate(20deg) translateY(-5px); }
.state-sad .eye { height: 35px; top: 5px; }
.state-sad .pupil { width: 25px; height: 25px; bottom: 0; top: auto; }
.state-sad .mouth { transform: rotate(180deg) translateY(5px); }
.state-sad .ear.left { transform: rotate(-50deg) translateY(5px); }
.state-sad .ear.right { transform: rotate(50deg) translateY(5px); }

.state-shocked .eye { width: 55px; height: 55px; top: -5px; }
.state-shocked .pupil { width: 10px; height: 10px; }
.state-shocked .mouth { border-color: transparent; }
.state-shocked .mouth-open { opacity: 1; border-radius: 50%; height: 15px; width: 15px; top: 0; background: var(--cat-dark); }
.state-shocked .ear { transform: translateY(-10px); }

.ai-mascot-zzz { position: absolute; top: -6px; right: 2px; display: flex; gap: 1px; font-size: 9px; font-weight: 800; color: var(--muted); pointer-events: none; }
.ai-mascot-zzz span { opacity: 0; }

.ai-mascot-notify {
    position: absolute; top: 2px; right: 2px; width: 14px; height: 14px;
    border-radius: 50%; background: var(--danger); border: 2px solid var(--surface-solid);
}
.ai-mascot-notify:not([hidden]) { animation: rp-notify-pulse 1.4s ease-in-out infinite; }

.ai-mascot-wrap.is-asleep .ai-mascot-zzz span { animation: rp-zzz-float 2.4s ease-in infinite; }
.ai-mascot-wrap.is-asleep .ai-mascot-zzz span:nth-child(1) { animation-delay: 0s; }
.ai-mascot-wrap.is-asleep .ai-mascot-zzz span:nth-child(2) { animation-delay: .5s; }
.ai-mascot-wrap.is-asleep .ai-mascot-zzz span:nth-child(3) { animation-delay: 1s; }

.ai-mascot-wrap.is-entering .cat-scale-wrap { animation: rp-entrance-hop .7s cubic-bezier(.34,1.56,.64,1) both; }
.ai-mascot-wrap.is-farewell .cat-scale-wrap { animation: rp-farewell-fade .8s ease-in forwards; }
.ai-mascot-wrap.is-fidget .cat-scale-wrap { animation: rp-fidget-peek 1.6s ease-in-out; }
.ai-mascot-wrap.is-thinking-state .eye { transition-duration: .15s; }

@keyframes cat-breathe { 0%, 100% { transform: scale(.27) translateY(0); } 50% { transform: scale(.27) translateY(-6px); } }
@keyframes cat-breathe-sleep { 0%, 100% { transform: scale(.27) translateY(0); } 50% { transform: scale(.27) translateY(-9px); } }
@keyframes cat-jump { 0%, 100% { transform: scale(.27) translateY(0); } 50% { transform: scale(.27) translateY(-16px); } }
@keyframes cat-droop { 0%, 100% { transform: scale(.27) translateY(4px); } 50% { transform: scale(.27) translateY(8px); } }
@keyframes cat-spin { 100% { transform: rotate(360deg); } }
@keyframes rp-zzz-float { 0% { opacity: 0; transform: translate(0, 0) scale(.6); } 15% { opacity: 1; } 100% { opacity: 0; transform: translate(10px, -22px) scale(1.1); } }
@keyframes rp-entrance-hop { 0% { transform: translateY(60px) scale(.6); opacity: 0; } 55% { transform: translateY(-14px) scale(1.05); opacity: 1; } 75% { transform: translateY(4px) scale(.98); } 100% { transform: translateY(0) scale(1); } }
@keyframes rp-farewell-fade { 0% { transform: translateY(0) rotate(0deg); opacity: 1; } 100% { transform: translateY(6px) rotate(-4deg); opacity: .35; } }
@keyframes rp-fidget-peek { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes rp-notify-pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.3); opacity: .7; } }

/* Chat balloon */
.ai-chat-balloon {
    position: absolute; right: 0; bottom: 82px;
    width: min(340px, calc(100vw - 48px)); max-height: 460px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 18px;
    box-shadow: 0 20px 50px rgba(0,0,0,.18);
    display: flex; flex-direction: column;
    opacity: 0; transform: translateY(14px) scale(.96); pointer-events: none;
    transform-origin: bottom right;
    transition: opacity .22s ease, transform .22s cubic-bezier(.34,1.56,.64,1), background-color .3s ease, border-color .3s ease;
    overflow: hidden;
}
.ai-chat-balloon.active { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.ai-chat-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; background: linear-gradient(120deg, var(--primary), var(--primary-2)); color: white; flex-shrink: 0; }
.ai-chat-title { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 14px; }
.ai-chat-head-actions { display: flex; align-items: center; gap: 8px; }
.ai-chat-history-btn, .ai-chat-close { background: rgba(255,255,255,.18); border: none; color: white; width: 26px; height: 26px; border-radius: 50%; cursor: pointer; font-size: 16px; line-height: 1; display: grid; place-items: center; }
.ai-chat-history-btn { font-size: 12px; }
.ai-chat-history-btn:hover, .ai-chat-close:hover { background: rgba(255,255,255,.3); }
.ai-chat-history-btn.active { background: white; color: var(--primary); }
/* Dropdown of past chat days — its own scroll, capped so it can't push the message list and
   input off the bottom of a short viewport. */
.ai-chat-history-panel { border-bottom: 1px solid var(--line); background: var(--canvas); flex-shrink: 0; max-height: 200px; overflow-y: auto; }
.ai-chat-history-panel[hidden] { display: none; }
.ai-chat-history-label { margin: 0; padding: 10px 16px 4px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.ai-chat-history-list { display: flex; flex-direction: column; padding: 0 8px 8px; }
.ai-chat-history-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; border: none; background: none; text-align: left; padding: 8px; border-radius: 8px; cursor: pointer; font-size: 12.5px; color: var(--ink); transition: background-color .15s ease; }
.ai-chat-history-item:hover { background: var(--surface); }
.ai-chat-history-item small { color: var(--muted); font-size: 11px; }
.ai-chat-history-empty { padding: 10px 16px 12px; margin: 0; font-size: 12px; color: var(--muted); }
/* Shown instead of the panel above once a specific day is picked — read-only reminder that
   this isn't the live conversation, with the one way back to it. */
.ai-chat-history-banner { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 16px; background: var(--primary-soft); color: var(--primary); font-size: 12px; font-weight: 600; flex-shrink: 0; }
.ai-chat-history-banner[hidden] { display: none; }
.ai-chat-history-banner button { border: none; background: var(--primary); color: white; font-size: 11px; font-weight: 700; padding: 5px 10px; border-radius: 999px; cursor: pointer; flex-shrink: 0; }
.ai-chat-history-banner button:hover { background: var(--primary-2); }
.ai-chat-messages { flex: 1; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; min-height: 180px; max-height: 320px; }
.ai-chat-form.is-readonly { opacity: .55; pointer-events: none; }
.ai-chat-quota { font-size: 11px; color: var(--muted); padding: 0 16px 8px; text-align: right; }
.ai-chat-msg { max-width: 85%; padding: 9px 12px; border-radius: 14px; font-size: 13px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.ai-chat-msg.from-user { align-self: flex-end; background: var(--primary); color: white; border-bottom-right-radius: 4px; }
.ai-chat-msg.from-assistant { align-self: flex-start; background: var(--canvas); color: var(--ink); border-bottom-left-radius: 4px; }
.ai-chat-msg.is-thinking { display: inline-flex; gap: 4px; align-items: center; padding: 12px; }
.ai-chat-msg.is-thinking span { width: 5px; height: 5px; border-radius: 50%; background: var(--muted); animation: rp-notify-pulse 1s ease-in-out infinite; }
.ai-chat-msg.is-thinking span:nth-child(2) { animation-delay: .15s; }
.ai-chat-msg.is-thinking span:nth-child(3) { animation-delay: .3s; }
.ai-chat-form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); flex-shrink: 0; }
.ai-chat-form input { flex: 1; border: 1px solid var(--line); border-radius: 10px; padding: 9px 12px; font-size: 13px; background: var(--canvas); color: var(--ink); }
.ai-chat-form button { border: none; background: var(--primary); color: white; width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center; cursor: pointer; flex-shrink: 0; }
.ai-chat-form button:hover { background: var(--primary-2); }

/* Quip bubble: canned double-click/spam-click replies. Deliberately lighter than the full chat
   balloon (no header/input) since it never calls the AI backend, just flashes a static message. */
.ai-mascot-quip {
    position: absolute; right: 0; bottom: 82px;
    /* Explicit width (not just max-width) is required here: .ai-mascot-wrap is a flex column
       whose auto width is driven by the 68px mascot button (the balloon/quip are position:
       absolute, so they don't contribute to that auto width) — without a real width, this
       element's shrink-to-fit sizing collapses to that ~68px containing block and wraps every
       word onto its own line. width:max-content lets it hug the text up to max-width instead. */
    width: max-content;
    max-width: min(240px, calc(100vw - 48px));
    background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
    padding: 10px 14px; font-size: 13px; line-height: 1.5; color: var(--ink);
    box-shadow: 0 14px 34px rgba(0,0,0,.16);
    opacity: 0; transform: translateY(10px) scale(.94); pointer-events: none;
    transform-origin: bottom right;
    transition: opacity .2s ease, transform .2s cubic-bezier(.34,1.56,.64,1), background-color .3s ease, border-color .3s ease;
}
.ai-mascot-quip.active { opacity: 1; transform: translateY(0) scale(1); }
.ai-mascot-quip::after {
    content: ''; position: absolute; right: 22px; bottom: -7px; width: 14px; height: 14px;
    background: var(--surface); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
    transform: rotate(45deg);
}

/* Prayer invite bubble: separate from both .ai-chat-balloon (full chat panel) and
   .ai-mascot-quip (auto-fading canned reply) — it has its own close button and stays until
   dismissed, since a prayer reminder shouldn't vanish on its own after a few seconds. */
.ai-mascot-prayer-bubble {
    position: absolute; right: 0; bottom: 82px;
    width: max-content; max-width: min(260px, calc(100vw - 48px));
    background: var(--surface); border: 1px solid var(--primary); border-radius: 14px;
    padding: 12px 34px 12px 14px; font-size: 13px; line-height: 1.5; color: var(--ink);
    box-shadow: 0 14px 34px rgba(0,0,0,.16);
    transform-origin: bottom right;
    animation: pop-in .3s cubic-bezier(.175,.885,.32,1.275) both;
}
.ai-mascot-prayer-bubble[hidden] { display: none; }
.ai-mascot-prayer-bubble::after {
    content: ''; position: absolute; right: 22px; bottom: -7px; width: 14px; height: 14px;
    background: var(--surface); border-right: 1px solid var(--primary); border-bottom: 1px solid var(--primary);
    transform: rotate(45deg);
}
.ai-mascot-prayer-close {
    position: absolute; top: 8px; right: 8px; width: 20px; height: 20px; border-radius: 50%;
    border: none; background: var(--canvas); color: var(--muted); font-size: 15px; line-height: 1;
    cursor: pointer; display: grid; place-items: center; transition: background-color .15s, color .15s;
}
.ai-mascot-prayer-close:hover { background: var(--danger-soft); color: var(--danger); }
@media (prefers-reduced-motion: reduce) {
    .ai-mascot-prayer-bubble { animation: none; }
}

/* Peci: only visible during the "pray" expression, sat on top of the head. */
.peci {
    display: none;
    position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
    width: 95px; height: 58px; z-index: 4;
    background: linear-gradient(160deg, #34343f, #17171f);
    border-radius: 48px 48px 10px 10px;
    box-shadow: 0 5px 10px rgba(0,0,0,.32), inset 0 -5px 8px rgba(255,255,255,.06);
}
.peci::after {
    content: ''; position: absolute; left: 10px; right: 10px; bottom: 12px; height: 2px;
    background: rgba(255,255,255,.1); border-radius: 2px;
}
.cat-head.state-pray .peci { display: block; }
.cat-head.state-pray .ear { opacity: 0; } /* fully covered by the peci at this position anyway — avoids stray edges peeking out */
.state-pray .eye { border-radius: 50% 50% 15px 15px; height: 16px; top: 20px; box-shadow: none; border-bottom: 4px solid var(--cat-primary); }
.state-pray .mouth-container { transform: scale(1.05) translateY(1px); }
.state-pray .cat-eyebrow { opacity: 0; }

@media (max-width: 640px) {
    .ai-mascot-wrap { right: 16px; bottom: 16px; }
    .ai-chat-balloon { right: -4px; }
    .ai-mascot-quip { right: -4px; }
    .ai-mascot-prayer-bubble { right: -4px; }
}

/* --- DOCUMENT REVIEW CHAT FEED --- */
.chat-card { display: flex; flex-direction: column; }
.chat-scroll {
    max-height: calc(100vh - 340px); min-height: 320px; overflow-y: auto; padding: 10px 8px; margin-bottom: 14px; border-radius: 12px;
    background-color: var(--canvas);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'%3E%3Cg fill='none' stroke='%23375973' stroke-opacity='0.06' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 24h26v32H20zM24 32h18M24 39h18M24 46h12'/%3E%3Cpath d='M96 20l7 7-19 19-9 2 2-9z'/%3E%3Cpath d='M150 26l8 8-4 12-12 4-8-8z'/%3E%3Ccircle cx='190' cy='40' r='13'/%3E%3Cpath d='M184 40l4 4 8-8'/%3E%3Cpath d='M26 96h34v24a4 4 0 01-4 4H30a4 4 0 01-4-4z'/%3E%3Cpath d='M26 96l17 14 17-14'/%3E%3Cpath d='M104 92h30v38H104zM110 101h18M110 108h18M110 115h11'/%3E%3Cpath d='M182 100a16 16 0 11-32 0 16 16 0 0132 0z'/%3E%3Cpath d='M170 92v8l6 4'/%3E%3Cpath d='M22 164h32l8 10-8 10H22z'/%3E%3Ccircle cx='96' cy='178' r='14'/%3E%3Cpath d='M90 178l4 4 8-8'/%3E%3Cpath d='M154 160h32v22a4 4 0 01-4 4h-24a4 4 0 01-4-4z'/%3E%3Cpath d='M154 160l16 13 16-13'/%3E%3C/g%3E%3C/svg%3E");
    background-repeat: repeat; background-size: 220px 220px;
}
html[data-theme="dark"] .chat-scroll {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'%3E%3Cg fill='none' stroke='%2394a3b8' stroke-opacity='0.08' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 24h26v32H20zM24 32h18M24 39h18M24 46h12'/%3E%3Cpath d='M96 20l7 7-19 19-9 2 2-9z'/%3E%3Cpath d='M150 26l8 8-4 12-12 4-8-8z'/%3E%3Ccircle cx='190' cy='40' r='13'/%3E%3Cpath d='M184 40l4 4 8-8'/%3E%3Cpath d='M26 96h34v24a4 4 0 01-4 4H30a4 4 0 01-4-4z'/%3E%3Cpath d='M26 96l17 14 17-14'/%3E%3Cpath d='M104 92h30v38H104zM110 101h18M110 108h18M110 115h11'/%3E%3Cpath d='M182 100a16 16 0 11-32 0 16 16 0 0132 0z'/%3E%3Cpath d='M170 92v8l6 4'/%3E%3Cpath d='M22 164h32l8 10-8 10H22z'/%3E%3Ccircle cx='96' cy='178' r='14'/%3E%3Cpath d='M90 178l4 4 8-8'/%3E%3Cpath d='M154 160h32v22a4 4 0 01-4 4h-24a4 4 0 01-4-4z'/%3E%3Cpath d='M154 160l16 13 16-13'/%3E%3C/g%3E%3C/svg%3E");
}
.chat-feed { display: flex; flex-direction: column; gap: 14px; }
.chat-system-note { align-self: center; font-size: 12px; color: var(--muted); background: var(--canvas); border-radius: 99px; padding: 5px 14px; text-align: center; }
.chat-message-row { display: flex; align-items: flex-start; gap: 10px; max-width: 86%; }
.chat-message-row.mine { align-self: flex-end; flex-direction: row-reverse; }
.chat-message-row.theirs { align-self: flex-start; }
.chat-avatar, .chat-composer-avatar { width: 40px; height: 40px; flex: 0 0 40px; font-size: 13px; border: 1px solid var(--line); box-shadow: 0 0 0 3px var(--surface-solid); }
.chat-bubble { min-width: 0; padding: 12px 14px; border-radius: 14px; background: var(--surface); border: 1px solid var(--line); box-shadow: 0 2px 8px rgba(0,0,0,.04); }
.chat-bubble.theirs { border-bottom-left-radius: 4px; }
.chat-bubble.mine { background: var(--primary-soft); border-color: transparent; border-bottom-right-radius: 4px; }
.chat-bubble.review { border-left: 3px solid var(--accent); }
.chat-bubble.pinned { box-shadow: inset 0 0 0 1px rgba(217,154,43,.35), 0 6px 18px rgba(217,154,43,.08); }
.chat-bubble-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 11px; color: var(--muted); margin-bottom: 6px; }
.chat-bubble-meta strong { color: var(--ink); font-size: 12px; }
.chat-pin-btn { width: 24px; height: 24px; border: 0; border-radius: 7px; background: transparent; color: var(--muted); display: grid; place-items: center; cursor: pointer; flex: 0 0 auto; }
.chat-pin-btn:hover, .chat-pin-btn.active { color: var(--accent); background: var(--warning-soft); }
.chat-bubble-content p { margin: 0 0 6px; font-size: 14px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; }
.chat-bubble-content p:last-child { margin-bottom: 0; }
.chat-review-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.chat-rubric { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 8px; font-size: 12px; color: var(--muted); }
.chat-rubric strong { color: var(--ink); }
.chat-attachment { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 650; }
.chat-file-card { display: flex; align-items: center; gap: 10px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; }
.chat-file-icon { width: 34px; height: 34px; border-radius: 8px; background: var(--primary-soft); color: var(--primary); display: grid; place-items: center; font-size: 15px; flex-shrink: 0; }
.chat-file-info { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.chat-file-info strong { font-size: 13px; }
.chat-file-info span { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-file-download { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; background: var(--canvas); color: var(--ink); flex-shrink: 0; }
.chat-file-download:hover { background: var(--primary-soft); color: var(--primary); }
.chat-composer { border-top: 1px solid var(--line); padding-top: 14px; }
.chat-composer form { display: flex; align-items: center; gap: 8px; }
.chat-composer input[type=text] { flex: 1; border-radius: 99px; }
.chat-attach-btn { width: 40px; height: 40px; border-radius: 50%; background: var(--canvas); border: 1px solid var(--line); display: grid; place-items: center; cursor: pointer; flex-shrink: 0; color: var(--muted); transition: .2s ease; }
.chat-attach-btn:hover { color: var(--primary); border-color: var(--primary); }
.chat-composer button[type=submit] { width: 40px; height: 40px; border-radius: 50%; border: none; background: var(--primary); color: white; display: grid; place-items: center; cursor: pointer; flex-shrink: 0; }
.chat-composer button[type=submit]:hover { background: var(--primary-2); }
.chat-attach-preview { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); margin-top: 8px; background: var(--canvas); border-radius: 8px; padding: 6px 10px; }
.chat-attach-preview[hidden] { display: none; }
.chat-attach-preview button { background: none; border: none; color: var(--danger); cursor: pointer; font-size: 13px; margin-left: auto; }

.custom-modal-box.wide { width: min(640px, 100%); }
.custom-modal-box.wide .custom-modal-actions { grid-template-columns: 1fr 1fr; }

/* Document detail slide-over: keeps the chat feed full-width and un-cluttered. */
.doc-info-panel { position: fixed; top: 0; right: -420px; width: min(400px, 92vw); height: 100vh; background: var(--surface); box-shadow: -8px 0 24px rgba(0, 0, 0, .15); z-index: 200; overflow-y: auto; padding: 24px; transition: right .3s cubic-bezier(.4, 0, .2, 1), background-color .3s ease; }
.doc-info-panel.active { right: 0; }
.doc-info-panel-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; }
