/* ============================================================================
   auth-shell.css
   Shared shell for the logged-OUT pages: Login + Register.
   Single source of truth so both pages share one identity (uniform with the
   logged-in app's navy header). Linked AFTER the Metronic bundle.

   Fragments that consume this file:
     WEB-INF/view/auth/Login.jsp
     WEB-INF/view/auth/Register.jsp
     WEB-INF/view/auth/_header.jsp        (navy header markup)
     WEB-INF/view/auth/_notifications.jsp (static notice list, right column)
     WEB-INF/view/auth/_footer.jsp        (info-board footer)
   ============================================================================ */

/* ===================== TOKENS (light) ===================== */
:root{
  --fog:#edf3f9; --fog-2:#e3ecf4;
  --surface:#ffffff; --surface-sub:#f5f9fc; --surface-3:#eef4fa;
  --hair:#dce6ef; --hair-2:#e8eff6;
  --ink:#0e2233; --ink-2:#3a5468; --ink-3:#6b8398;
  --blue:#0079c1; --blue-deep:#005a9c; --blue-ink:#04304f;
  --cyan:#29abe2; --cyan-soft:#e3f3fb;
  --amber:#f5a623; --amber-deep:#e08a12; --amber-soft:#fdf0d8;
  --ok:#1f9d57; --bad:#d64560;
  --input-bg:#ffffff; --input-border:#d2dfea;
  /* aliases consumed by the shared container-search component */
  --card-bg:var(--surface); --card-bg-soft:var(--surface-sub); --card-border:var(--hair);
  --text-strong:var(--ink); --text-muted:var(--ink-2);
  --shadow-sm:0 1px 3px rgba(14,34,51,.06);
  --shadow:0 10px 30px -12px rgba(14,34,51,.18);
  --shadow-amber:0 10px 24px -8px rgba(224,138,18,.45);
  --water:linear-gradient(180deg,#bfe0f2 0%, #7cc3e6 45%, #3a97c9 100%);
  --sky:radial-gradient(120% 120% at 85% -10%, #dff0fb 0%, var(--fog) 55%);
  --photo-filter:saturate(.82) brightness(1.06) contrast(.97);
  /* Background stage = gradient (ganti foto harbour ~760KB → 0 byte, load instan) */
  --stage-bg:radial-gradient(1100px 480px at 80% -8%, rgba(96,160,214,.20), transparent 62%), radial-gradient(900px 520px at 4% 110%, rgba(64,150,168,.13), transparent 58%), linear-gradient(180deg,#e8eff7 0%,#f1f5fa 42%,#f6f9fc 100%);
  --stage-scrim:linear-gradient(180deg, rgba(240,246,251,.30) 0%, rgba(239,245,250,.55) 40%, rgba(237,243,249,.86) 100%);
  --glass:rgba(255,255,255,.72); --glass-border:rgba(255,255,255,.78);
  --hb-shadow:0 2px 24px rgba(255,255,255,.6);
  /* navy header gradient — identical to #kt_app_header::before (Head.jsp) */
  --hdr-grad:linear-gradient(180deg, transparent 46%, rgba(4,13,26,.50) 100%),
             linear-gradient(90deg, #2f66a8 0%, #173d67 34%, #123458 50%, #173d67 66%, #2f66a8 100%);
}
/* ===================== TOKENS (dark) ===================== */
body.dark-mode{
  --fog:#0a1622; --fog-2:#0c1a28;
  --surface:#10202f; --surface-sub:#0d1b28; --surface-3:#132638;
  --hair:#1e3345; --hair-2:#183044;
  --ink:#e7eef4; --ink-2:#a9bccb; --ink-3:#7d94a6;
  --blue:#3fb0e6; --blue-deep:#1d8fce; --blue-ink:#bfe2f5;
  --cyan:#43c1f0; --cyan-soft:#0f2c3f;
  --amber:#f7b23f; --amber-deep:#f5a623; --amber-soft:#2c2311;
  --ok:#34c38f; --bad:#e4707f;
  --input-bg:#0c1a28; --input-border:#25405a;
  --card-bg:var(--surface); --card-bg-soft:var(--surface-sub); --card-border:var(--hair);
  --text-strong:var(--ink); --text-muted:var(--ink-2);
  --shadow-sm:0 1px 3px rgba(0,0,0,.4);
  --shadow:0 14px 34px -14px rgba(0,0,0,.6);
  --shadow-amber:0 10px 26px -10px rgba(224,138,18,.4);
  --water:linear-gradient(180deg,#123247 0%, #0e2a3d 50%, #0a2030 100%);
  --sky:radial-gradient(120% 120% at 85% -10%, #10293b 0%, var(--fog) 55%);
  --photo-filter:saturate(.78) brightness(.40) contrast(1.08);
  --stage-bg:radial-gradient(1100px 480px at 80% -8%, rgba(46,96,150,.40), transparent 60%), radial-gradient(900px 520px at 4% 110%, rgba(28,110,120,.22), transparent 55%), linear-gradient(180deg,#0d1c2b 0%,#0b1725 55%,#0a1521 100%);
  --stage-scrim:linear-gradient(180deg, rgba(10,22,34,.30) 0%, rgba(10,21,32,.62) 40%, rgba(10,20,30,.90) 100%);
  --glass:rgba(16,31,46,.58); --glass-border:rgba(255,255,255,.09);
  --hb-shadow:0 2px 26px rgba(0,0,0,.6);
  --hdr-grad:linear-gradient(180deg, transparent 46%, rgba(0,0,0,.50) 100%),
             linear-gradient(90deg, #255a94 0%, #103459 34%, #0c2646 50%, #103459 66%, #255a94 100%);
}

/* Archivo Black — WEBACCESS wordmark (self-hosted; relative to this CSS file). */
@font-face{font-family:'Archivo Black'; font-style:normal; font-weight:400;
  src:url('../fonts/archivo-black/latin-400-normal.woff2') format('woff2'); font-display:swap;}

*{box-sizing:border-box;}
html,body{margin:0;}
body{
  background:var(--sky); color:var(--ink); min-height:100vh;
  display:flex; flex-direction:column;
  font-family:var(--ff-body);
  -webkit-font-smoothing:antialiased; font-feature-settings:"ss01";
}
body input,body button,body select,body textarea{font-family:inherit;}

/* SHARED gutter — header, ribbon, hero, board, footer all use .wrap, so every
   left edge (logo, "Himbauan" badge, cards) lines up to the same page margin. */
.wrap{width:100%; max-width:1760px; margin-inline:auto; padding-inline:clamp(18px,4vw,64px);}

/* ===================== UNIFIED NAVY HEADER ===================== */
/* Mirrors the logged-in app header (Menu.jsp / #kt_app_header) but single row,
   with no search / quick-access / user-avatar / nav-menu (none apply pre-login).
   Right side = Rates · Support · theme toggle · Pelindo. */
/* 2026-07-17: header freeze — 'position:relative' lama menimpa sticky shg tak pernah aktif. */
.wa-appbar{position:sticky; top:0; z-index:40;
  background:var(--hdr-grad); background-size:cover; background-position:center top;
  box-shadow:0 4px 20px rgba(0,0,0,.30);}
/* padding-BLOCK only. The `padding:12px 0` shorthand used to reset padding-inline
   to 0, overriding .wrap's gutter (it outranks .wrap), which pushed the Danantara
   and Pelindo logos 64px outside the line every other section sits on. */
/* Same structure as the authenticated shell's .wa-brandbar (Menu.jsp), at every
   width, so the logged-out and logged-in headers read identically:
     row 1   Danantara (logo + text)   Webaccess - Online Transaction   Pelindo
     row 2                                            Rates - Support - theme
   1fr auto 1fr (not auto 1fr auto): the logos differ in width, so only equal side
   tracks put the wordmark on the page's centre line. */
.wa-appbar .row-in{display:grid; grid-template-columns:1fr auto 1fr;
  grid-template-areas:"dnt title pel"
                      "act act act";
  align-items:center; column-gap:12px; row-gap:6px; min-height:74px; padding-block:12px;}
.wa-appbar .row-in > *{min-width:0;}
.wa-appbar .row-in > .wa-brand-dnt{grid-area:dnt; justify-self:start;}
.wa-appbar .row-in > .wa-title{grid-area:title; justify-self:center; text-align:center;}
.wa-appbar .row-in > .wa-brand-pel{grid-area:pel; justify-self:end;}
.wa-appbar .row-in > .wa-actions{grid-area:act; justify-self:end;}
/* Dividers + the old flex spacer have no job in the grid. */
.wa-appbar .row-in > .wa-div, .wa-appbar .row-in > .wa-sp{display:none;}
.wa-brand{display:flex; align-items:center; text-decoration:none; flex-shrink:0;}
.wa-brand-dnt{gap:10px;}
/* Match the logged-in shell exactly. Note the shell's own rules say 34px/23px but
   main-landing.css wins there with
     #kt_app_header_container a[href="/webaccess"] img{height:42px}
   an ID+attribute selector that blanket-sizes BOTH images — so what the shell
   actually renders is 42px (32px <=900px). Mirror the rendered result, since that
   is the header users see after login. */
.wa-brand-dnt .dnt-sym{height:42px; display:block;}
.wa-brand-dnt .dnt-word{height:42px; display:block; filter:brightness(0) invert(1);}
.wa-div{width:1px; height:32px; background:rgba(255,255,255,.28); flex-shrink:0;}
/* Structure ours (the ".ot" suffix); gradient + tracking kept from origin/main
   (151316c). The parent clips its own fill to transparent for the gradient, so
   .ot must restate -webkit-text-fill-color or it inherits transparent and vanishes. */
/* Wordmark elegan (identik dengan header setelah-login / Menu.jsp): "Web" + aksen
   "access", di bawahnya tagline ONLINE TRANSACTION berbingkai hairline. */
.wa-title{display:inline-flex; flex-direction:column; align-items:center; gap:4px;
  text-decoration:none; line-height:1; white-space:nowrap;}
.wa-name{font-family:'Sora',var(--ff-display),'Segoe UI',sans-serif; font-weight:800;
  letter-spacing:.3px; font-size:clamp(18px,1.9vw,26px); color:#fff; line-height:1;}
.wa-name .wa-accent{font-weight:600; color:#8fc4f5;}
.wa-title:hover .wa-name{color:#eaf3ff;}
.wa-title:hover .wa-name .wa-accent{color:#bcdcff;}
.wa-title .ot{display:inline-flex; align-items:center; gap:8px;
  font-family:var(--ff-body),'Hanken Grotesk',sans-serif; font-weight:600; font-size:10px;
  color:rgba(255,255,255,.72); letter-spacing:2px; text-transform:uppercase; line-height:1;}
.wa-title .ot-hair{width:16px; height:1px; background:rgba(255,255,255,.4);
  display:inline-block; flex:0 0 auto;}
@media (max-width:900px){ .wa-title .ot{display:none;} }
.wa-sp{flex:1;}
/* Desktop: a transparent flex row, so the header reads exactly as before. On
   mobile it becomes a single grid item (row 2, right-aligned). */
.wa-actions{display:flex; align-items:center; gap:14px; min-width:0;}
.wa-clock{display:flex; flex-direction:column; align-items:flex-end; line-height:1.1;
  padding-right:14px; margin-right:2px; border-right:1px solid rgba(255,255,255,.24);}
.wa-clock .t{font:600 var(--fs-md)/1 var(--ff-mono); color:#fff;}
.wa-clock .d{font-size:var(--fs-2xs); letter-spacing:.14em; text-transform:uppercase; color:#bcd4ea; margin-top:3px;}
.wa-nav{color:#e6f0fb; font-weight:600; font-size:var(--fs-md); text-decoration:none; padding:8px 12px; border-radius:8px;
  display:inline-flex; align-items:center; gap:7px;}
.wa-nav:hover{color:#fff; background:rgba(255,255,255,.12);}
.wa-tgl{display:inline-flex; align-items:center; gap:7px; cursor:pointer;
  background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.75); color:#fff;
  border-radius:999px; padding:8px 13px; font-weight:600; font-size:var(--fs-sm);}
.wa-tgl:hover{background:rgba(255,255,255,.18); border-color:#fff;}
.wa-pelindo{height:32px; display:block; filter:brightness(0) invert(1); opacity:.95;}

/* ===================== ANNOUNCEMENTS (static notice panel) =====================
   Replaces the old running-text ribbon (UAT: notices must stand still and stay
   readable). Lives in .hero-right.

   Two layouts, driven by whether an announcement image exists. .hero-right gets
   .has-poster from Component_announcement.jsp once it has an image to show:
     no poster  -> the poster is hidden and .notif takes the whole column (flex:1)
     has poster -> poster keeps the top (flex:1) and .notif is fixed to the
                   Container Tracking card's height (set in JS), so the left and
                   right columns line up card-for-card.
   The card no longer expands in place — clicking opens .nmodal instead — so it is
   a plain flex child again rather than a bottom-anchored overlay. */
.notif{display:flex; flex-direction:column; overflow:hidden; flex:1 1 auto; min-height:0;}
/* No poster is the default: only reveal it once there is an image. */
/* The poster is its own hero column now; it only exists when there is an image
   (Component_announcement.jsp adds .has-poster to #hero_grid). */

.notif-h{display:flex; align-items:center; gap:10px; padding:12px 16px;
  border-bottom:1px solid var(--hair-2); flex:0 0 auto;}
.notif-h .ni{position:relative; width:28px; height:28px; border-radius:8px;
  background:var(--amber-soft); color:var(--amber-deep);
  display:flex; align-items:center; justify-content:center; font-size:var(--fs-sm); flex-shrink:0;}
.notif-h h3{margin:0; flex:1; font:700 var(--fs-sm)/1 var(--ff-mono); letter-spacing:.12em;
  text-transform:uppercase; color:var(--ink-2);}

/* ── Attention pulse on the announcements icon ────────────────────────────────
   Runs only while .notif.has-unread (JS: a notice the reader has not opened
   yet); it stops for good once every notice has been read.

   Safe-zone rules this obeys:
   • Nothing here changes layout. The halo is an ::after overlay and the icon
     scales via transform, so no sibling moves and no tap target shifts.
   • pointer-events:none on the halo — it can never eat a touch.
   • The whole thing lives inside .notif-h's own padding, clear of the pager
     buttons on the opposite edge.
   • ~0.4Hz, well under the 3Hz photosensitivity threshold, and the global
     prefers-reduced-motion rule at the foot of this file kills it outright.
   Each 3.4s cycle is quiet for the first ~60%: it nudges, then leaves you be. */
.notif-h .ni::after{content:""; position:absolute; inset:0; border-radius:inherit;
  border:2px solid var(--amber-deep); opacity:0; pointer-events:none;}
.notif.has-unread .notif-h .ni{animation:ni-pulse 3.4s ease-in-out infinite;}
.notif.has-unread .notif-h .ni::after{animation:ni-halo 3.4s ease-out infinite;}
.notif.has-unread .notif-h .ni > i{animation:ni-shake 3.4s ease-in-out infinite;
  transform-origin:60% 65%;}

/* Halo: a ring that expands past the icon and fades. Capped at 1.4 (≈6px bleed)
   so it never reaches the heading text beside it. */
@keyframes ni-halo{
  0%{transform:scale(.92); opacity:0;}
  62%{transform:scale(.92); opacity:0;}
  68%{opacity:.6;}
  92%,100%{transform:scale(1.4); opacity:0;}
}
/* The chip itself: a single soft colour blink + a hair of scale. */
@keyframes ni-pulse{
  0%,60%,100%{transform:scale(1); background:var(--amber-soft); color:var(--amber-deep);}
  70%{transform:scale(1.1); background:var(--amber-deep); color:#fff;}
  84%{transform:scale(1); background:var(--amber-soft); color:var(--amber-deep);}
}
/* Bullhorn wiggle, damped. */
@keyframes ni-shake{
  0%,62%,100%{transform:rotate(0);}
  66%{transform:rotate(-11deg);}
  70%{transform:rotate(8deg);}
  74%{transform:rotate(-6deg);}
  78%{transform:rotate(4deg);}
  82%{transform:rotate(0);}
}
/* Reading a notice should feel like it worked: the chip settles immediately. */
.notif-h .ni{transition:background .2s, color .2s;}

/* Pager: "1 / 3" + up/down. */
.notif-pager{display:flex; align-items:center; gap:6px; flex-shrink:0;}
.notif-idx{font:700 var(--fs-2xs)/1 var(--ff-mono); color:var(--ink-3); min-width:34px; text-align:right;}
.notif-pager button{width:24px; height:24px; border-radius:6px; cursor:pointer;
  border:1px solid var(--input-border); background:var(--input-bg); color:var(--ink-3);
  display:flex; align-items:center; justify-content:center; font-size:var(--fs-micro);
  transition:background .15s, color .15s, border-color .15s;}
.notif-pager button:hover:not(:disabled){background:var(--amber-deep); border-color:var(--amber-deep); color:#fff;}
.notif-pager button:disabled{opacity:.4; cursor:default;}

/* Body scrolls; JS creeps scrollTop when the notice overflows (pauses on hover). */
.notif-b{overflow-y:auto; flex:1 1 auto; min-height:0; scrollbar-width:none;}
.notif-b::-webkit-scrollbar{width:0; height:0;}

/* Option C: this notice is the whole point of the column, so it is set at reading
   size rather than as a caption stranded in a big box. --fs-xl / --fs-md keep it on
   the shared type scale (the mockup's 14px body is not a scale step). */
.notif-item{padding:24px 26px 26px; cursor:pointer;
  border-left:3px solid var(--amber-deep); transition:background .12s;}
.notif-item:hover{background:var(--surface-sub);}
.notif-t{font-family:var(--ff-display); font-weight:700; font-size:var(--fs-xl); color:var(--ink);}
.notif-d{font-size:var(--fs-md); line-height:1.85; color:var(--ink-2); margin-top:10px; white-space:pre-line;}

.notif-empty{display:flex; flex-direction:column; align-items:center; justify-content:center; gap:8px;
  text-align:center; padding:26px 18px; color:var(--ink-3); height:100%;}
.notif-empty i{font-size:var(--fs-xl); opacity:.5;}
.notif-empty span{font-size:var(--fs-sm);}

/* ---- Full-text popup (vanilla: Register shadows jQuery, so no Bootstrap modal) ---- */
.nmodal{position:fixed; inset:0; z-index:1080; display:none;}
.nmodal.open{display:block;}
.nmodal-back{position:absolute; inset:0; background:rgba(6,18,30,.55); backdrop-filter:blur(2px);}
.nmodal-card{position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  width:min(720px, 92vw); max-height:82vh; display:flex; flex-direction:column;
  box-shadow:0 30px 80px -20px rgba(6,18,30,.6); animation:nmodal-in .18s ease-out;}
@keyframes nmodal-in{from{opacity:0; transform:translate(-50%,-46%);} to{opacity:1; transform:translate(-50%,-50%);}}
@media (prefers-reduced-motion:reduce){ .nmodal-card{animation:none;} }
.nmodal-h{display:flex; align-items:center; gap:10px; padding:15px 18px;
  border-bottom:1px solid var(--hair-2); flex:0 0 auto;}
.nmodal-h .ni{width:32px; height:32px; border-radius:9px; background:var(--amber-soft); color:var(--amber-deep);
  display:flex; align-items:center; justify-content:center; font-size:var(--fs-md); flex-shrink:0;}
.nmodal-h h3{margin:0; flex:1; font:800 var(--fs-lg)/1.2 var(--ff-display); color:var(--ink);}
.nmodal-x{width:32px; height:32px; border:0; border-radius:8px; flex-shrink:0; cursor:pointer;
  background:var(--surface-3); color:var(--ink-2); display:flex; align-items:center; justify-content:center;}
.nmodal-x:hover{background:var(--hair); color:var(--ink);}
.nmodal-b{padding:18px; overflow-y:auto; flex:1 1 auto; min-height:0;}
.nmodal-text{font-size:var(--fs-md); line-height:1.7; color:var(--ink-2); white-space:pre-line;}

/* ===================== MAIN STAGE (photo background) ===================== */
.stage{position:relative; isolation:isolate; overflow:hidden; flex:1 0 auto;}
.stage::before{content:""; position:absolute; inset:0; z-index:-2;
  background:var(--stage-bg); background-attachment:fixed;}
.stage::after{content:""; position:absolute; inset:0; z-index:-1; background:var(--stage-scrim);}
.stage .panel, .stage .poster, .stage .col{
  background:var(--glass);
  -webkit-backdrop-filter:blur(16px) saturate(1.2); backdrop-filter:blur(16px) saturate(1.2);
  border:1px solid var(--glass-border); box-shadow:0 16px 40px -18px rgba(9,24,40,.35);}

/* ===================== HERO ===================== */
/* New layout (2026-07): row 1 is a 2-col grid [ sign in | 16:9 slider ]; the
   Container Tracking bar and the Announcement cards are full-width rows BELOW the
   grid. This removes the old 3-column "tanggung" gap on the right entirely. */
.hero{padding:clamp(22px,3.4vw,44px) 0 clamp(16px,2.4vw,26px);}
.hero-grid{display:grid; grid-template-columns:minmax(0,420px) minmax(0,1fr);
  gap:clamp(18px,2.4vw,32px); align-items:stretch;}
.hero-grid > *{min-width:0;}
/* col 2: announcement slider fills the left rail's height (Sign in + Container
   Tracking) — whole image kept via the blurred backdrop; click opens the full
   poster. No empty right-hand gap, and the search stays compact in the rail. */
.hero-stage{display:flex; min-width:0;}
.poster.hero-poster{width:100%; height:100%; border-radius:18px;}
/* Desktop: absolute-fill the slider so ONLY the rail (Sign in + Tracking) sizes the
   hero row — a tall poster image then cover-fits to that height instead of
   stretching the row past the rail. Mobile uses aspect-ratio instead (below). */
@media (min-width:1041px){
  .hero-stage{position:relative;}
  .hero-stage > .poster.hero-poster{position:absolute; inset:0; height:auto;}
}

/* ---- hero slider caption overlay (bottom gradient + title + CTA) ---- */
.poster-ov{position:absolute; inset:auto 0 0 0; z-index:3; padding:clamp(16px,2vw,26px);
  background:linear-gradient(to top, rgba(6,16,28,.84) 0%, rgba(6,16,28,.5) 42%, transparent 100%);
  color:#fff; pointer-events:none;}
.poster-ov-in{max-width:52ch;}
.poster-ov-k{font:600 var(--fs-2xs)/1 var(--ff-mono); letter-spacing:.16em; text-transform:uppercase; opacity:.85; margin-bottom:8px;}
.poster-ov-t{font-family:var(--ff-display); font-weight:800; font-size:clamp(15px,1.55vw,22px); line-height:1.2;
  text-shadow:0 2px 12px rgba(0,0,0,.45); display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden;
  overflow-wrap:anywhere;}
.poster-ov-btn{margin-top:14px; pointer-events:auto; display:inline-flex; align-items:center; gap:8px;
  border:0; border-radius:11px; cursor:pointer; padding:10px 16px;
  background:linear-gradient(135deg,var(--amber),var(--amber-deep)); color:#3a2405;
  font:800 var(--fs-sm)/1 var(--ff-display); letter-spacing:.01em; box-shadow:var(--shadow-amber);}
.poster-ov-btn i{transition:transform .15s;} .poster-ov-btn:hover i{transform:translateX(3px);}
/* Petunjuk halus pengganti "Read more" utk pengumuman yang hanya gambar. */
.poster-ov-hint{margin-top:12px; display:inline-flex; align-items:center; gap:7px;
  font:600 var(--fs-xs)/1 var(--ff-body); letter-spacing:.02em; color:rgba(255,255,255,.9);
  background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.22); border-radius:50rem;
  padding:6px 13px; backdrop-filter:blur(2px);}
.poster-ov-hint i{font-size:var(--fs-sm); opacity:.95;}

/* Slide pengumuman TANPA gambar (404/hilang di mount): latar branded, bukan ikon rusak.
   Scrim + teks/Read more dari .poster-ov tetap terbaca di atasnya. */
.poster-slide.noimg .poster-bg{display:none;}
.poster-slide.noimg{background:
    radial-gradient(115% 95% at 88% -12%, rgba(64,168,190,.55), transparent 56%),
    radial-gradient(95% 90% at 2% 118%, rgba(18,74,128,.62), transparent 58%),
    linear-gradient(135deg,#0b3a63 0%,#0e4c6f 48%,#0f6172 100%);}
body.dark-mode .poster-slide.noimg{background:linear-gradient(135deg,#071f34 0%,#0a3145 48%,#0b4450 100%);}
/* Lightbox pengumuman tanpa gambar: kotak placeholder netral (bukan ikon rusak). */
.wa-anc-slide.noimg{min-height:240px; display:flex; align-items:center; justify-content:center;
    background:linear-gradient(135deg,#0b3a63,#0f6172); color:#cfe4ef; border-radius:12px;}
.wa-anc-slide.noimg::after{content:"Gambar pengumuman tidak tersedia"; font-size:13px; opacity:.9;}

/* ---- Hero CSS murni (pengganti foto harbour.jpg): branded, theme-aware, responsif ----
   Dipakai oleh slide fallback (buildFallback) saat tidak ada pengumuman. Nol byte gambar. */
.poster-slide.wa-hero-css{cursor:default;
  background:
    radial-gradient(115% 95% at 88% -12%, rgba(64,168,190,.55), transparent 56%),
    radial-gradient(95% 90% at 2% 118%, rgba(18,74,128,.62), transparent 58%),
    linear-gradient(135deg,#0b3a63 0%,#0e4c6f 48%,#0f6172 100%);}
/* tekstur garis diagonal halus (memudar ke atas) */
.poster-slide.wa-hero-css::before{content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:repeating-linear-gradient(118deg, rgba(255,255,255,.06) 0 1.5px, transparent 1.5px 30px);
  -webkit-mask-image:linear-gradient(to top, transparent 6%, #000 55%);
          mask-image:linear-gradient(to top, transparent 6%, #000 55%);}
/* pita "container yard" tipis di dasar (identitas pelabuhan, tanpa gambar) */
.poster-slide.wa-hero-css::after{content:""; position:absolute; left:0; right:0; bottom:0; height:10px; z-index:1; pointer-events:none;
  background:repeating-linear-gradient(90deg, var(--amber) 0 22px,#37a6b8 22px 44px,#eef4f8 44px 66px,#2f7fb8 66px 88px);
  opacity:.45;}
/* MODE GELAP: turunkan kilau supaya menyatu dengan stage gelap */
body.dark-mode .poster-slide.wa-hero-css{
  background:
    radial-gradient(115% 95% at 88% -12%, rgba(40,120,140,.42), transparent 56%),
    radial-gradient(95% 90% at 2% 118%, rgba(14,52,92,.55), transparent 58%),
    linear-gradient(135deg,#071f34 0%,#0a3145 48%,#0b4450 100%);}
body.dark-mode .poster-slide.wa-hero-css::after{opacity:.30;}
body.dark-mode .poster-slide.wa-hero-css::before{background:repeating-linear-gradient(118deg, rgba(255,255,255,.045) 0 1.5px, transparent 1.5px 30px);}
/* MOBILE: pita lebih tipis */
@media (max-width:1040px){ .poster-slide.wa-hero-css::after{height:8px;} }

/* ---- Hero FOTO default (fallback saat tak ada pengumuman) ----
   Foto terminal asli (harbour.jpg, self-host). Kalau foto gagal load, gradient
   di bawah ini tetap tampil (robust). Scrim legibilitas dari .poster-ov (bawah). */
.poster-slide.wa-hero-photo{cursor:default;
  background:
    radial-gradient(115% 95% at 88% -12%, rgba(64,168,190,.55), transparent 56%),
    radial-gradient(95% 90% at 2% 118%, rgba(18,74,128,.62), transparent 58%),
    linear-gradient(135deg,#0b3a63 0%,#0e4c6f 48%,#0f6172 100%);}
/* Foto full-bleed & TAJAM: override blur/opacity/scale bawaan .poster-bg. */
.poster-slide.wa-hero-photo .poster-bg{
  background-image:url('../img/bg/harbour.jpg');
  filter:none; transform:none; opacity:1; z-index:0;}
/* scrim kiri tambahan supaya teks putih tetap kontras di atas langit terang */
.poster-slide.wa-hero-photo::after{content:""; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(90deg, rgba(6,16,28,.66) 0%, rgba(6,16,28,.28) 40%, transparent 68%);}
/* Judul hero di TENGAH (vertikal), rata kiri, tipografi lebih besar & rapi (gaya Pelindo Hub).
   Scoped ke slide hero foto -> slide pengumuman TETAP ter-anchor di bawah. */
.poster-slide.wa-hero-photo .poster-ov{inset:0; display:flex; align-items:center;
  padding:clamp(22px,4vw,58px);
  background:linear-gradient(90deg, rgba(6,16,28,.70) 0%, rgba(6,16,28,.30) 44%, transparent 74%);}
.poster-slide.wa-hero-photo .poster-ov-in{max-width:min(90%,700px);}
.poster-slide.wa-hero-photo .poster-ov-k{font-size:clamp(11px,.85vw,13px); letter-spacing:.24em;
  opacity:.92; margin-bottom:16px;}
.poster-slide.wa-hero-photo .poster-ov-k::after{content:""; display:block; width:44px; height:3px; margin-top:10px;
  border-radius:2px; background:linear-gradient(90deg,var(--amber),var(--amber-deep));}
.poster-slide.wa-hero-photo .poster-ov-t{font-size:clamp(24px,2.9vw,42px); line-height:1.1;
  letter-spacing:-.012em; display:block; -webkit-line-clamp:none; overflow:visible;
  overflow-wrap:normal; word-break:normal; text-shadow:0 3px 18px rgba(0,0,0,.5);}
/* MOBILE: kembalikan ke bawah supaya tak menutup tengah foto pendek */
@media (max-width:1040px){
  .poster-slide.wa-hero-photo .poster-ov{inset:auto 0 0 0; align-items:flex-end;
    background:linear-gradient(to top, rgba(6,16,28,.84) 0%, rgba(6,16,28,.5) 42%, transparent 100%);}
  .poster-slide.wa-hero-photo .poster-ov-t{font-size:clamp(22px,6vw,30px);}
  .poster-slide.wa-hero-photo .poster-ov-t br{display:none;}
}
/* MODE GELAP: sedikit redupkan foto agar menyatu dgn stage gelap */
body.dark-mode .poster-slide.wa-hero-photo{
  background:linear-gradient(135deg,#071f34 0%,#0a3145 48%,#0b4450 100%);}
body.dark-mode .poster-slide.wa-hero-photo .poster-bg{filter:brightness(.82) saturate(.96);}
/* MOBILE: pakai varian ringan */
@media (max-width:1040px){
  .poster-slide.wa-hero-photo .poster-bg{background-image:url('../img/bg/harbour-mobile.jpg');}
}

/* ===================== ANNOUNCEMENT CARDS (full-width strip) ===================== */
.anncards{margin-top:clamp(16px,2vw,26px);}
.anc-head{display:flex; align-items:center; gap:10px; margin-bottom:12px;}
.anc-head .ni{width:30px; height:30px; border-radius:9px; background:var(--amber-soft); color:var(--amber-deep);
  display:flex; align-items:center; justify-content:center; font-size:var(--fs-md); flex-shrink:0;}
.anc-head h3{margin:0; font:700 var(--fs-sm)/1 var(--ff-mono); letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2);}
.anc-head .cnt{font:700 var(--fs-2xs)/1 var(--ff-mono); color:var(--ink-3); background:var(--surface-3); border-radius:999px; padding:5px 9px;}
/* Mobile-first: horizontal swipe strip with scroll-snap. */
.anc-strip{display:flex; gap:14px; overflow-x:auto; padding:6px 4px 8px;
  scroll-snap-type:x proximity; scrollbar-width:none; -webkit-overflow-scrolling:touch;}
.anc-strip::-webkit-scrollbar{height:0;}
.anc-card{flex:0 0 82vw; max-width:340px; scroll-snap-align:start; cursor:pointer; position:relative;
  display:flex; flex-direction:column; min-height:154px;
  border-radius:14px; padding:15px 17px; overflow:hidden;
  background:var(--glass); -webkit-backdrop-filter:blur(16px) saturate(1.2); backdrop-filter:blur(16px) saturate(1.2);
  border:1px solid var(--glass-border); box-shadow:0 12px 30px -18px rgba(9,24,40,.35);
  border-left:4px solid var(--amber-deep); transition:transform .12s, box-shadow .15s;}
.anc-card:hover{transform:translateY(-2px); box-shadow:0 18px 42px -18px rgba(9,24,40,.45);}
.anc-card.sev-high{border-left-color:var(--bad);}
/* top row: severity icon chip (left) + badge (right) */
.anc-card-top{display:flex; align-items:center; gap:10px; margin-bottom:11px;}
.anc-ico{width:34px; height:34px; border-radius:10px; flex-shrink:0; display:flex; align-items:center; justify-content:center;
  background:var(--amber-soft); color:var(--amber-deep); font-size:var(--fs-md);}
.anc-card.sev-high .anc-ico{background:color-mix(in srgb,var(--bad) 14%,transparent); color:var(--bad);}
.anc-badge{display:inline-flex; align-items:center; gap:6px; font:700 var(--fs-2xs)/1 var(--ff-mono);
  letter-spacing:.07em; text-transform:uppercase; padding:5px 9px; border-radius:999px; margin-left:auto;
  background:var(--amber-soft); color:var(--amber-deep);}
.anc-badge.b-high{background:color-mix(in srgb,var(--bad) 14%,transparent); color:var(--bad);}
.anc-t{font-family:var(--ff-display); font-weight:800; font-size:var(--fs-md); color:var(--ink); line-height:1.3;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;}
.anc-d{margin-top:6px; font-size:var(--fs-sm); line-height:1.5; color:var(--ink-2);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;}
.anc-more{margin-top:auto; padding-top:12px; display:inline-flex; align-items:center; gap:7px;
  font:800 var(--fs-sm)/1 var(--ff-display); color:var(--blue-deep); letter-spacing:.01em;}
.anc-card.sev-high .anc-more{color:var(--bad);}
.anc-more i{transition:transform .15s;} .anc-card:hover .anc-more i{transform:translateX(3px);}
/* ---- IMPORTANT announcements: gentle "breathing" glow so a critical notice is
   noticed at a glance. ~0.4Hz (well under the 3Hz photosensitivity threshold),
   settles on hover, and the global prefers-reduced-motion rule kills it outright.
   box-shadow renders outside the border-box, so .anc-card overflow:hidden is fine. */
@keyframes ancGlow{
  0%,100%{box-shadow:0 12px 30px -18px rgba(9,24,40,.35), 0 0 0 0 rgba(214,69,96,0);}
  50%    {box-shadow:0 14px 34px -16px rgba(9,24,40,.42), 0 0 0 4px color-mix(in srgb,var(--bad) 22%,transparent);}
}
.anc-card.sev-high{animation:ancGlow 2.4s ease-in-out infinite;}
.anc-card.sev-high:hover{animation:none;}
@keyframes ancBadgePulse{0%,100%{opacity:1;} 50%{opacity:.5;}}
.anc-card.sev-high .anc-badge{animation:ancBadgePulse 2.4s ease-in-out infinite;}
/* Header bullhorn rings while any IMPORTANT announcement is present (#notif gets
   .has-important from _notifications.jsp). */
@keyframes ancHeadPing{
  0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--bad) 45%,transparent);}
  70%,100%{box-shadow:0 0 0 10px rgba(214,69,96,0);}
}
.anc.has-important .anc-head .ni{background:color-mix(in srgb,var(--bad) 14%,transparent); color:var(--bad);
  animation:ancHeadPing 2s ease-out infinite;}

/* ---- Header announcement shortcut (bullhorn + count badge) ----
   Hidden until _notifications.jsp finds notices; the badge pulses and the icon
   goes amber while an IMPORTANT notice is present. Sticky header = always visible. */
.wa-anc-btn{position:relative; display:none;}
.wa-anc-btn.show{display:inline-flex;}
/* Two-class selector so it outranks `.wa-nav span{display:none}` (mobile ≤860). */
.wa-anc-btn .wa-anc-badge{position:absolute; top:-3px; right:-5px; display:block;
  min-width:17px; height:17px; padding:0 5px;
  border-radius:999px; background:var(--bad); color:#fff; font:800 10px/17px var(--ff-mono); text-align:center;
  box-shadow:0 0 0 2px rgba(6,20,38,.92);}
@keyframes ancBtnPulse{0%,100%{transform:scale(1);} 50%{transform:scale(1.18);}}
.wa-anc-btn.is-important .wa-anc-badge{animation:ancBtnPulse 1.6s ease-in-out infinite;}
.wa-anc-btn.is-important i{color:var(--amber);}
/* Desktop: count-aware — 1 = featured (wider, more teaser), 2/3 = equal columns,
   4+ = 4-up grid that wraps. A single card never looks stubby or full-bleed. */
@media (min-width:1041px){
  .anc-strip{display:grid; gap:16px; overflow:visible; grid-template-columns:repeat(4,minmax(0,1fr));}
  .anc-card{flex:none; max-width:none;}
  .anc-strip.n-1{grid-template-columns:minmax(0,560px);}
  .anc-strip.n-2{grid-template-columns:repeat(2,minmax(0,1fr));}
  .anc-strip.n-3{grid-template-columns:repeat(3,minmax(0,1fr));}
  .anc-strip.n-1 .anc-t{font-size:var(--fs-lg);}
  .anc-strip.n-1 .anc-d{-webkit-line-clamp:3;}
}

/* ===== Smart Digest: 1 sorotan + daftar ringkas + "Lihat semua" (skala 1..banyak) ===== */
.anc-digest{display:grid; gap:14px; grid-template-columns:1fr;}          /* mobile: tumpuk */
.anc-card.is-featured{flex:none; max-width:none; cursor:pointer;}
.anc-card.is-featured .anc-t{font-size:var(--fs-lg);}
.anc-card.is-featured .anc-d{-webkit-line-clamp:3;}
.anc-list{display:flex; flex-direction:column; gap:8px; min-width:0;}
.anc-li{display:flex; align-items:center; gap:10px; width:100%; text-align:left; font:inherit; color:var(--ink);
  background:var(--glass); border:1px solid var(--glass-border); border-radius:12px;
  padding:11px 13px; cursor:pointer; transition:transform .12s, box-shadow .15s, border-color .15s;}
.anc-li:hover{transform:translateY(-1px); box-shadow:0 12px 26px -16px rgba(9,24,40,.42); border-color:color-mix(in srgb,var(--blue-deep) 45%,var(--glass-border));}
.anc-li-dot{flex:0 0 8px; width:8px; height:8px; border-radius:50%; background:var(--blue-deep);}
.anc-li.sev-high .anc-li-dot{background:var(--bad);}
.anc-li-t{flex:1 1 auto; min-width:0; font:700 var(--fs-sm)/1.35 var(--ff-display); color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
.anc-li-tag{flex:0 0 auto; font:800 var(--fs-2xs)/1 var(--ff-mono); letter-spacing:.05em; color:var(--bad);
  background:color-mix(in srgb,var(--bad) 13%,transparent); border-radius:50rem; padding:3px 8px;}
.anc-li-arw{flex:0 0 auto; color:var(--ink-3); font-size:11px;}
.anc-seeall{justify-content:center; gap:8px; border-style:dashed; color:var(--blue-deep);
  background:color-mix(in srgb,var(--blue-deep) 7%,transparent);}
.anc-seeall .anc-li-t{flex:0 0 auto; color:var(--blue-deep);}
.anc-seeall .anc-li-arw{color:var(--blue-deep);}
@media (min-width:1041px){
  .anc-digest{grid-template-columns:minmax(0,420px) minmax(0,1fr); align-items:start;}
  .anc-digest.only-featured{grid-template-columns:minmax(0,560px);}
}

/* Modal "Semua Pengumuman" — daftar item yang bisa diklik utk buka teks penuh */
.nmodal-list{display:flex; flex-direction:column; gap:9px;}
.nmodal-li{display:flex; align-items:flex-start; gap:11px; width:100%; text-align:left; cursor:pointer;
  font:inherit; color:var(--ink); background:var(--card-bg); border:1px solid var(--card-border);
  border-radius:12px; padding:12px 14px; transition:border-color .15s, background .15s;}
.nmodal-li:hover{border-color:color-mix(in srgb,var(--blue-deep) 45%,var(--card-border)); background:var(--card-bg-soft);}
.nmodal-li .nli-dot{flex:0 0 8px; width:8px; height:8px; margin-top:6px; border-radius:50%; background:var(--blue-deep);}
.nmodal-li.sev-high .nli-dot{background:var(--bad);}
.nli-main{flex:1 1 auto; min-width:0;}
.nli-t{display:block; font:700 var(--fs-md)/1.3 var(--ff-display); color:var(--ink);}
.nli-d{display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  font-size:var(--fs-sm); line-height:1.45; color:var(--ink-2); margin-top:3px;}
.nli-arrow{flex:0 0 auto; color:var(--ink-3); margin-top:4px; font-size:12px;}
.nmodal-back{display:inline-flex; align-items:center; gap:7px; background:none; border:0; cursor:pointer;
  color:var(--blue-deep); font:800 var(--fs-sm)/1 var(--ff-display); padding:0 0 12px;}
/* Wordmark: full-width band above the columns. */
.hero-brand{margin-bottom:20px; text-align:right;}
/* The hero lockup (.hero-brand/.hb-name/.hb-rule) was removed — the wordmark now
   lives in the header only — so both sides of this rule are dead and were dropped. */

/* ---- announcement poster (fixed-height inline carousel, cover fit) ----
   The poster fills its middle grid cell and shares the hero row height. Images
   are cover-fit into the fixed frame (may crop); the whole, uncropped image is
   available in the lightbox on click. */
.poster{border-radius:18px; overflow:hidden; display:flex; flex-direction:column; height:100%; position:relative;}
.poster-h{display:flex; align-items:center; gap:10px; padding:13px 18px; border-bottom:1px solid var(--hair-2); flex:0 0 auto;}
.poster-h .qi{width:30px; height:30px; border-radius:9px; background:var(--amber-soft); color:var(--amber-deep);
  display:flex; align-items:center; justify-content:center; font-size:var(--fs-md);}
.poster-h .q{font:600 var(--fs-sm)/1 var(--ff-mono); letter-spacing:.12em; color:var(--ink-2);}
.poster-h .live{margin-left:auto; display:inline-flex; align-items:center; gap:7px;
  font:600 var(--fs-2xs)/1 var(--ff-mono); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3);}
.poster-h .live .dot{width:7px; height:7px; border-radius:50%; background:var(--amber); box-shadow:0 0 0 3px rgba(245,166,35,.2);}
/* Frame clips the cover-fit carousel and fills the remaining poster height. */
.poster-frame{position:relative; flex:1 1 auto; min-height:0; overflow:hidden;
  display:flex; align-items:center; justify-content:center; background:var(--surface-sub);}
/* Carousel track: all slides side by side, translated by JS. */
.poster-track{display:flex; width:100%; height:100%; transition:transform .4s ease;}
.poster-slide{position:relative; min-width:100%; height:100%; overflow:hidden; cursor:pointer;}
/* Blurred copy of the same image behind, so the contain letterbox reads as a
   soft halo rather than empty bars when the image ratio differs from the frame. */
.poster-slide .poster-bg{position:absolute; inset:0; background-size:cover; background-position:center;
  filter:blur(24px) saturate(1.1); transform:scale(1.18); opacity:.5;}
/* Contain fit: shows the WHOLE poster (no crop) inside the rail-height frame;
   the blurred .poster-bg fills the letterbox on the short axis. */
.poster-slide .poster-img{position:relative; z-index:1; display:block; width:100%; height:100%; object-fit:contain;}
@media (prefers-reduced-motion:reduce){ .poster-track{transition:none;} }
/* inline carousel controls */
.poster-nav{position:absolute; top:50%; transform:translateY(-50%); z-index:4; width:40px; height:40px;
  border:0; border-radius:11px; cursor:pointer; color:#fff; background:rgba(8,20,34,.42);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  display:flex; align-items:center; justify-content:center; font-size:14px; transition:background .15s;}
.poster-nav:hover{background:rgba(8,20,34,.66);}
.poster-nav.prev{left:12px;} .poster-nav.next{right:12px;}
.poster-nav.hide{display:none;}
.poster-dots{position:absolute; left:50%; bottom:14px; transform:translateX(-50%); z-index:4;
  display:flex; gap:7px;}
.poster-dots.hide{display:none;}
.poster-dots .d{width:8px; height:8px; border-radius:50%; border:0; padding:0; cursor:pointer;
  background:rgba(255,255,255,.55); box-shadow:0 0 0 1px rgba(8,20,34,.25);}
.poster-dots .d.on{background:var(--amber,#f5a623);}
.poster-ph{display:flex; flex-direction:column; align-items:center; gap:10px; text-align:center; padding:24px; color:var(--ink-3);}
.poster-ph i{font-size:30px; opacity:.5; color:var(--amber-deep);}
.poster-ph .t{font-family:var(--ff-display); font-weight:700; font-size:var(--fs-lg); color:var(--ink-2);}
.poster-ph .s{font-size:var(--fs-sm); max-width:34ch;}
.poster.is-empty{opacity:.62; filter:saturate(.85);}
.poster.is-empty .poster-frame{background:repeating-linear-gradient(135deg, var(--surface-sub) 0 16px, var(--surface-3) 16px 32px);}
/* register page: poster sits beside the taller register card */
body.auth-register .poster{min-height:520px;}

/* ===================== LEFT RAIL: cards ===================== */
.rail{display:flex; flex-direction:column; gap:16px;}
.panel{border-radius:18px; overflow:hidden;}
.signin, .register{padding:24px 24px 22px; position:relative;}
.signin::before, .register::before{content:""; position:absolute; inset:0 0 auto 0; height:3px;
  background:linear-gradient(90deg,var(--blue),var(--cyan) 60%,var(--amber));}
.signin .kick, .register .kick{font:600 var(--fs-2xs)/1 var(--ff-mono); letter-spacing:.2em; text-transform:uppercase; color:var(--ink-3);}
.signin h2, .register h2{font-family:var(--ff-display); font-weight:800; font-size:var(--fs-xl); margin:9px 0 3px; color:var(--ink); letter-spacing:-.01em;}
.signin .sub, .register .sub{font-size:var(--fs-md); color:var(--ink-2); margin:0 0 18px;}
.field{margin-bottom:12px;}
.field label{display:block; font-size:var(--fs-xs); font-weight:600; color:var(--ink-2); margin-bottom:6px; letter-spacing:.02em;}
.field .req{color:var(--bad);}
.field .box{position:relative;}
.field .box .ic{position:absolute; left:13px; top:50%; transform:translateY(-50%); color:var(--ink-3); font-size:var(--fs-md);}
.field input{width:100%; height:46px; border-radius:11px; border:1px solid var(--input-border);
  background:var(--input-bg); color:var(--ink); padding:0 42px; font-size:var(--fs-md); outline:none;
  transition:border-color .12s, box-shadow .12s;}
.field.no-ic input{padding:0 14px;}
.field input::placeholder{color:var(--ink-3);}
.field input:focus{border-color:var(--blue); box-shadow:0 0 0 4px rgba(0,121,193,.14);}
.field input:-webkit-autofill,.field input:-webkit-autofill:hover,.field input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--ink); -webkit-box-shadow:0 0 0 1000px var(--input-bg) inset;
  caret-color:var(--ink); transition:background-color 9999s ease-out 0s;}
.field .eye{position:absolute; right:8px; top:50%; transform:translateY(-50%); background:none; border:0;
  color:var(--ink-3); cursor:pointer; padding:8px;}
.forgot{display:flex; justify-content:space-between; align-items:center; margin:2px 0 16px;}
.forgot .help{font-size:var(--fs-sm); color:var(--ink-3);}
.forgot a{font-size:var(--fs-sm); font-weight:700; color:var(--blue-deep); text-decoration:none; cursor:pointer;}
.forgot a:hover{text-decoration:underline;}
.btn-cta{width:100%; height:50px; border:0; border-radius:12px; cursor:pointer;
  background:linear-gradient(135deg,var(--amber),var(--amber-deep)); color:#3a2405;
  font-family:var(--ff-display); font-weight:800; font-size:var(--fs-lg); letter-spacing:.01em;
  display:flex; align-items:center; justify-content:center; gap:10px; box-shadow:var(--shadow-amber);
  transition:transform .1s, filter .15s;}
.btn-cta:hover{filter:brightness(1.05);} .btn-cta:active{transform:translateY(1px);}
/* ---- pesan login inline (Sisa N percobaan / blok sementara) — theme-aware + mobile ---- */
.login-alert{display:flex; gap:.55rem; align-items:flex-start; margin-top:14px; padding:11px 13px;
  border-radius:11px; font-size:var(--fs-sm); line-height:1.45; border:1px solid transparent;}
.login-alert i{margin-top:.15rem; flex-shrink:0; font-size:.95rem;}
.login-alert b{font-weight:800;}
.login-alert em{display:block; font-style:italic; font-size:var(--fs-2xs); opacity:.82; margin-top:3px;}
.login-alert.err{color:#b42318; background:#fef3f2; border-color:#fecdca;}
.login-alert.block{color:#b54708; background:#fffaeb; border-color:#fedf89;}
.login-alert.warn{color:#854d0e; background:#fefce8; border-color:#fde68a;}
body.dark-mode .login-alert.err{color:#fda29b; background:rgba(180,35,24,.16); border-color:rgba(253,162,155,.34);}
body.dark-mode .login-alert.block{color:#fdb022; background:rgba(181,71,8,.18); border-color:rgba(253,223,137,.32);}
body.dark-mode .login-alert.warn{color:#fde047; background:rgba(133,77,14,.20); border-color:rgba(253,230,138,.30);}
@media (max-width:560px){ .login-alert{font-size:var(--fs-2xs); padding:10px 12px;} }
.btn-cta:disabled{opacity:.5; cursor:not-allowed; box-shadow:none;}
.btn-cta i{transition:transform .15s; width:26px; height:26px; border-radius:50%; background:rgba(58,36,5,.18);
  display:inline-flex; align-items:center; justify-content:center; font-size:.82em;}
.btn-cta:hover i{transform:translateX(3px);}
.btn-ghost{width:100%; height:44px; border:1px solid var(--input-border); border-radius:11px;
  background:transparent; color:var(--ink-2); font:700 13px/1 inherit; cursor:pointer; margin-top:8px;}
.newcust{margin:15px 0 0; padding-top:14px; border-top:1px dashed var(--hair);
  font-size:var(--fs-sm); color:var(--ink-2); text-align:center;}
.newcust a{color:var(--blue-deep); font-weight:700; text-decoration:none;}
#wa_forgot{display:none;}
#wa_forgot h3{font-family:var(--ff-display); margin:0 0 4px; font-size:18px; font-weight:800; color:var(--ink);}
#wa_forgot p{margin:0 0 14px; font-size:var(--fs-sm); color:var(--ink-2);}

/* ---- register-specific ---- */
.reg-row{display:flex; gap:9px;}
.btn-find{height:46px; border:0; border-radius:11px; background:var(--blue-deep); color:#fff;
  font:700 13px/1 inherit; padding:0 18px; cursor:pointer; flex-shrink:0;}
.btn-find:hover{background:var(--blue);}
.btn-find:disabled{opacity:.6; cursor:default;}
.custbox{margin-top:12px; border:1px solid var(--hair); border-radius:12px; padding:2px 14px; display:none;
  background:color-mix(in srgb,var(--blue) 6%,transparent);}
.custbox.show{display:block;}
.custrow{display:flex; justify-content:space-between; gap:16px; padding:9px 0; border-bottom:1px dashed var(--hair); font-size:var(--fs-md);}
.custrow:last-child{border-bottom:0;}
.custrow .k{color:var(--ink-3);} .custrow .v{font-weight:600; text-align:right; color:var(--ink);}
.gate{opacity:.5; pointer-events:none; transition:opacity .2s;} .gate.on{opacity:1; pointer-events:auto;}
.rules{margin:8px 0 0; padding:12px 14px; border:1px solid var(--hair); border-radius:10px; background:var(--surface-sub);}
.rules .rt{font-size:var(--fs-xs); font-weight:700; color:var(--ink-3); text-transform:uppercase; letter-spacing:.05em; margin-bottom:7px;}
.rule{display:flex; align-items:center; gap:8px; font-size:var(--fs-sm); color:var(--ink-3); padding:2px 0;}
.rule .rc{width:16px; height:16px; border-radius:50%; flex-shrink:0; display:inline-flex; align-items:center; justify-content:center;
  font-size:var(--fs-2xs); background:var(--hair); color:var(--ink-3);}
.rule.pass{color:var(--ink);} .rule.pass .rc{background:var(--ok); color:#fff;}
.hint{font-size:var(--fs-xs); color:var(--ink-3); margin-top:6px; line-height:1.5;}
.hint a{color:var(--blue-deep); font-weight:600; text-decoration:none;}
.msg{font-size:var(--fs-sm); margin-top:6px; display:none; align-items:center; gap:6px;}
.msg.show{display:flex;} .msg.ok{color:var(--ok);} .msg.bad{color:var(--bad);}
/* Transient "checking..." state. A class, not an inline colour — an inline colour
   outranks .bad and left later failures rendering grey instead of red. */
.msg.busy{color:var(--ink-3);}
/* Failures are red AND shake, so a repeated mistake still registers. */
.msg.bad{font-weight:600;}
.msg.bad.shake{animation:msg-shake .4s cubic-bezier(.36,.07,.19,.97) both;}
@keyframes msg-shake{
  10%,90%{transform:translateX(-1px);}
  20%,80%{transform:translateX(2px);}
  30%,50%,70%{transform:translateX(-4px);}
  40%,60%{transform:translateX(4px);}
}
@media (prefers-reduced-motion:reduce){ .msg.bad.shake{animation:none;} }

/* Password reveal button (Register). The input sits in .pwd-wrap so the button can
   be positioned against it; .field .eye already handles the login's .box variant. */
.pwd-wrap{position:relative; display:block;}
.pwd-wrap input{width:100%; padding-right:42px !important;}
.pwd-wrap .eye{position:absolute; right:6px; top:50%; transform:translateY(-50%);
  background:none; border:0; color:var(--ink-3); cursor:pointer; padding:8px; line-height:1;}
.pwd-wrap .eye:hover{color:var(--blue-deep);}
/* Hide the browser's own reveal control — we ship our own, and Edge's native eye
   only appears while the field is focused+filled, which reads as a flaky icon. */
.pwd-wrap input::-ms-reveal, .pwd-wrap input::-ms-clear{display:none;}

/* "(Opsional)" label suffix — the counterpart to .req */
.field label .opt{font-weight:500; color:var(--ink-3); text-transform:none; letter-spacing:0;}
.reg-done{display:none; text-align:center; padding:16px 6px 6px;}
.reg-done.show{display:block;}
.reg-done .rd-ic{width:64px; height:64px; border-radius:50%; background:color-mix(in srgb,var(--ok) 15%,transparent);
  color:var(--ok); display:inline-flex; align-items:center; justify-content:center; font-size:32px; margin-bottom:14px;}
.reg-done h2{margin:0 0 6px; font:800 var(--fs-xl)/1.2 var(--ff-display); color:var(--ink);}
.reg-done p{margin:0 auto; max-width:40ch; font-size:var(--fs-md); color:var(--ink-2);}
.reg-done a{color:var(--blue-deep); font-weight:700; text-decoration:none;}

/* ---- container search component overrides (frosted blue) ---- */
.stage .wa-csearch{display:flex;}
.stage .wa-csearch .cs-v3{width:100%; margin:0; background:var(--glass);
  -webkit-backdrop-filter:blur(16px) saturate(1.2); backdrop-filter:blur(16px) saturate(1.2);
  border-color:var(--glass-border); box-shadow:0 16px 40px -18px rgba(9,24,40,.35);}
.stage .wa-csearch .cs-v3 .cs-header{background:linear-gradient(135deg, var(--cyan-soft), transparent); border-bottom-color:var(--hair-2);}
.stage .wa-csearch .cs-v3 .cs-header .ic{background:var(--cyan-soft); color:var(--blue-deep);}
.stage .wa-csearch .cs-v3 .cs-header h3{color:var(--blue-deep); text-shadow:none;}
.stage .wa-csearch .cs-v3 .cs-input:focus{border-color:var(--blue); box-shadow:0 0 0 3px rgba(0,121,193,.14);}
.stage .wa-csearch .cs-v3 .btn-search{background:var(--blue-deep);}
.stage .wa-csearch .cs-v3 .btn-search:hover{background:var(--blue);}
body.dark-mode .stage .wa-csearch .cs-v3 .cs-header{background:linear-gradient(135deg, rgba(41,171,226,.14), transparent);}
body.dark-mode .stage .wa-csearch .cs-v3 .cs-header .ic{background:rgba(41,171,226,.2); color:#7cc5ea;}
body.dark-mode .stage .wa-csearch .cs-v3 .cs-header h3{color:#7cc5ea;}

/* ===================== VESSELS BOARD ===================== */
/* Moved to assets/css/vessel-board.css — shared with the authenticated
   Vessel Schedule menu. Do not re-add board rules here. */

/* ===================== FOOTER (info board) ===================== */
.foot{background:var(--surface-sub); color:var(--ink-2); margin-top:auto; border-top:2px solid var(--cyan);}
body.dark-mode .foot{background:#0a1622; border-top-color:var(--blue-deep);}
.foot .fin{display:grid; grid-template-columns:repeat(4,1fr); gap:34px; padding-block:36px 28px;}
.foot h4{display:flex; align-items:center; gap:9px; font:700 var(--fs-sm)/1 var(--ff-body);
  letter-spacing:.05em; text-transform:uppercase; color:var(--blue-deep);
  padding-bottom:11px; margin:0 0 15px; border-bottom:1px solid var(--hair);}
.foot h4 i{color:var(--blue); font-size:var(--fs-md);}
.foot h5{font:700 var(--fs-xs)/1 var(--ff-body); letter-spacing:.04em; text-transform:uppercase;
  color:var(--ink-3); margin:18px 0 11px;}
.foot .frow{display:flex; align-items:flex-start; gap:9px; margin:0 0 9px; font-size:var(--fs-md); line-height:1.45;}
.foot .frow .fi{width:15px; flex-shrink:0; margin-top:2px; color:var(--ink-3); font-size:var(--fs-sm); text-align:center;}
.foot .frow .fl{color:var(--ink-3); min-width:70px; flex-shrink:0;}
.foot .frow .fv,.foot .frow a{color:var(--ink); font-weight:600; text-decoration:none;}
.foot .frow a:hover{color:var(--blue-deep); text-decoration:underline;}
.foot .fnote{margin:-4px 0 10px 24px; font-size:var(--fs-xs); font-style:italic; color:var(--ink-3);}
.foot .cp{border-top:1px solid var(--hair);}
.foot .cp-in{display:flex; align-items:center; justify-content:space-between; gap:18px 26px; flex-wrap:wrap; padding-block:18px;}
.foot .cp-dnt{display:flex; align-items:center; gap:11px;}
.foot .cp-dnt .dnt-sym{height:32px; display:block;}
.foot .cp-dnt .dnt-word{height:26px; display:block;}
body.dark-mode .foot .cp-dnt .dnt-word{filter:brightness(0) invert(1);}
.foot .cp-txt{flex:1 1 260px; text-align:center; font-size:var(--fs-xs); color:var(--ink-3);}
.foot .cp-pelindo{height:30px; display:block;}
body.dark-mode .foot .cp-pelindo{filter:brightness(0) invert(1) opacity(.92);}

/* ===================== RESPONSIVE ===================== */
@media (max-width:1040px){
  /* Stack: [sign in + tracking] -> slider (16:9 here, no rail to match) ->
     announcement cards -> board. */
  .hero-grid{grid-template-columns:1fr;}
  .rail{position:static;}
  .poster.hero-poster{height:auto; aspect-ratio:16/9;}
  .cols{grid-template-columns:repeat(2,1fr);}
  .stage::before{background-attachment:scroll;}
}
/* The full header's min-content is ~845px (brand+title+clock+2 nav+toggle+Pelindo
   and their gaps), so it must start collapsing at 860 — not 640. Between the two
   it used to overflow and clip the Pelindo logo off the right edge. */
@media (max-width:860px){
  .wa-clock{display:none;}
  .wa-appbar .row-in{min-height:54px; padding-block:8px; column-gap:8px;}
  .wa-nav{padding:8px 9px;}
  .wa-nav span{display:none;}            /* Rates/Support collapse to icons */
  .wa-pelindo{height:26px;}
  .wa-name{font-size:18px;}
  /* Header muat di layar sempit: sisakan simbol Danantara (wordmark & label 'Dark'
     disembunyikan) — total lebar item tadinya melebihi viewport -> overflow kanan. */
  /* Same step the shell takes at this width (42px -> 32px), text always kept. */
  .wa-brand-dnt .dnt-sym{height:32px;}
  .wa-brand-dnt .dnt-word{height:32px;}
  .wa-tgl span{display:none;}
  /* ---- 2026-07-17: penyesuaian halaman login di HP ---- */
  /* iOS Safari auto-zoom saat fokus bila input <16px -> paksa 16px di HP. */
  .field input{font-size:16px;}
  /* Poster placeholder ("Belum ada pengumuman") hanya buang ruang di layar kecil;
     sembunyikan KETIKA kosong saja — poster berisi tetap tampil. */
  .poster.is-empty{display:none;}
  /* Lockup Webaccess: rata tengah di satu kolom (rata kanan terlihat janggal). */
  .hero-brand{text-align:center; margin-bottom:14px;}
  .hb-rule{margin-top:8px;}
}
/* Footer: 4 columns hold until 640 today, but a cell has to fit
   "support.tpks@pelindo.co.id" — an unbreakable string — so the grid's min-content
   was ~481px and the page scrolled sideways on phones. Step down earlier AND let
   long addresses wrap. */
@media (max-width:900px){ .foot .fin{grid-template-columns:1fr 1fr;} }
@media (max-width:560px){ .foot .fin{grid-template-columns:1fr;} }
.foot .fin > div{min-width:0;}
.foot .frow{min-width:0;}
.foot .frow .fv, .foot .frow a{overflow-wrap:anywhere;}
@media (max-width:560px){
  .foot .cp-in{flex-direction:column; text-align:center; gap:14px;}
  /* Kolom: cegah teks memuai vertikal (flex-grow) yang membuat logo Pelindo
     terlempar jauh ke dasar dengan celah kosong. */
  .foot .cp-txt{flex:0 0 auto;}
}
@media (max-width:380px){
  /* Narrowest phones: keep all three marks, just smaller. */
  .wa-brand-dnt .dnt-sym{height:26px;}
  .wa-brand-dnt .dnt-word{height:26px;}
  .wa-name{font-size:15px;}
  .wa-pelindo{height:20px;}
  .wa-tgl span{display:none;}            /* theme toggle -> icon only */
  .wa-tgl{padding:8px 10px;}
}
/* Pagar pengaman: elemen apa pun yang kelebihan lebar tidak boleh menciptakan
   scroll horizontal / area kosong di kanan (kasus HP 2026-07-17).
   WAJIB 'clip' (bukan 'hidden'): overflow-x:hidden di html/body membuat scroll
   container baru yang MEMATIKAN position:sticky header. */
html, body{overflow-x:clip; max-width:100%;}
@supports not (overflow: clip){ html, body{overflow-x:hidden;} }
@media (prefers-reduced-motion:reduce){body *{transition:none !important; animation:none !important;}}
