
*,*::before,*::after{box-sizing:border-box}
:root{
  --navy:#1F3A5F; --navy-d:#16294472; --teal:#0F766E; --teal-d:#0B5A54;
  --ink:#0F172A; --body:#475569; --muted:#64748B;
  --soft:#EFF6F8; --tint:#E6F0F1; --line:#E2E8F0; --white:#fff;
  --live:#15803D; --live-tint:#DCFCE7; --live-ink:#BBF7D0;
  --gold:#D4A73A; --r:20px; --sh:0 1px 2px rgba(15,23,42,.05),0 8px 24px rgba(15,23,42,.06);
  --sh-h:0 2px 4px rgba(15,23,42,.06),0 18px 40px rgba(15,23,42,.10);
  --sh-soft:0 1px 2px rgba(15,23,42,.05),0 5px 14px rgba(15,23,42,.06);
  --max:1180px;
}
html{scroll-behavior:smooth}
body{margin:0;font:16px/1.7 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
     color:var(--body);background:var(--white);-webkit-font-smoothing:antialiased}
img{max-width:100%;display:block}
a{color:var(--teal);text-decoration:none}
a:hover{text-decoration:underline}
h1,h2,h3,h4{color:var(--navy);margin:0;line-height:1.15;letter-spacing:-.02em}
h1{font-size:clamp(2rem,4.6vw,3.05rem);font-weight:800}
h2{font-size:clamp(1.5rem,2.9vw,2.05rem);font-weight:800}
h3{font-size:1.12rem;font-weight:700}
p{margin:0 0 1.05em}
.wrap{max-width:var(--max);margin:0 auto;padding:0 24px}
.wrap.narrow{max-width:820px}
/* `clip` rather than `hidden`: `hidden` creates a scroll container, which makes every
   descendant's `animation-timeline: view()` resolve as already finished -- the fade-in was
   dead on every sectioned page because of this one line. `clip` cuts the ornaments that poke
   past the edge without becoming a scroll container. Fallback for old engines first. */
section{position:relative;overflow:hidden;padding:72px 0}
@supports (overflow:clip){section{overflow:clip}}
.wrap{position:relative}
/* overlay .lb memakai z-index:200; kalau .wrap juga ber-z-index, ia jadi stacking
   context dan header sticky (z-index:50) menutupi tombol tutup lightbox. */
/* ---- section ornament: same vocabulary as the hero, one per section ---- */
.orn{position:absolute;z-index:1;pointer-events:none}
/* ---- banded sections: the page is no longer one flat white ---- */
.band-soft{background:var(--soft);border-block:1px solid var(--tint)}
.band-dark{background:var(--navy);color:#C7D6E8;position:relative;overflow:hidden}
@supports (overflow:clip){.band-dark{overflow:clip}}
.band-dark h1,.band-dark h2{color:#fff}
/* a white card inside the dark band: its own titles must stay dark */
.band-dark .card h3{color:var(--navy)}
.band-dark .eyebrow{background:transparent;border:1px solid #7FD5CB}
.band-dark .eyebrow{background:transparent;border:1px solid #7FD5CB;color:var(--live-ink)}
.band-dark a{color:#8FE3D8}
/* ---- eyebrow as a chip, not loose text ---- */
.eyebrow{display:inline-block;background:var(--live-tint);color:var(--live);font-size:.72rem;font-weight:800;
         letter-spacing:.9px;text-transform:uppercase;padding:6px 14px;border-radius:100px;margin-bottom:18px}
/* ---- hero ---- */
.hero{position:relative;overflow:hidden;padding:78px 0 54px;background:linear-gradient(160deg,#FBFDFE,#F2F8F9)}
@supports (overflow:clip){.hero{overflow:clip}}
.hero-inner{display:grid;grid-template-columns:1fr auto;gap:56px;align-items:center;position:relative;z-index:2}
.hero h1{max-width:20ch;margin-bottom:20px}
.hero p{font-size:1.07rem;max-width:62ch;text-align:justify;hyphens:auto}
.hero-orn{position:absolute;inset:0;z-index:1;pointer-events:none}
/* ---- hero portrait: cut out of its background, breaking the circle ---- */
.portrait{position:relative;width:392px;height:392px;flex-shrink:0;border-radius:50%;overflow:hidden}
/* the source photograph already has a plain studio background, so it stays as shot:
   no cutout, no brightness lift, no halo -- a round frame is all it needs */
.portrait{box-shadow:0 18px 40px rgba(15,23,42,.16)}
.portrait img{width:100%;height:100%;object-fit:cover;object-position:center;border-radius:50%}
.portrait .arc-unused{display:none;
               border-radius:100px;background:var(--teal);opacity:.20;z-index:1}
/* ---- buttons ---- */
.btn{display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:0 24px;
     border-radius:12px;font-weight:700;font-size:.94rem;text-decoration:none;border:1.5px solid transparent}
.btn-p{background:var(--teal);color:#fff}
.btn-p:hover{background:var(--teal-d);text-decoration:none}
.btn-s{border-color:var(--line);color:var(--navy);background:#fff}
.btn-s:hover{border-color:var(--teal);color:var(--teal);text-decoration:none}
.cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:28px}
/* ---- header / nav (CSS only, no JavaScript) ---- */
/* Header carries the SAME palette as the footer (see .fbrand / .fsvg). A white bar on a white
   page left the two surfaces with no boundary, and the only separator was a --line hairline at
   ~1.2 contrast. Navy fixes the boundary and makes header and footer read as one system.
   Every ink inside had to move: .brand/nav were --navy on --navy (contrast 1.00). */
header{position:sticky;top:0;z-index:50;background:var(--navy);
       border-bottom:1px solid rgba(255,255,255,.14)}
.hdr{display:flex;align-items:center;justify-content:space-between;min-height:66px;gap:20px}
.brand{display:flex;align-items:center;gap:11px;font-weight:800;color:#fff;font-size:1rem;
       letter-spacing:-.01em;white-space:nowrap;text-decoration:none}
.brand:hover{text-decoration:none}
/* the whole name is ONE colour: no span inside the name gets its own ink */
.brand .bname{color:#fff}
/* the site label is a separate, quieter element, so it reads as a label rather than a name.
   The divider needs a visible ink: a hairline in --line measured ~1.2 contrast on white,
   which is the same trap the timeline rail fell into. On navy the divider goes light instead. */
.brand .btag{font-size:.62rem;font-weight:800;letter-spacing:1.1px;text-transform:uppercase;
             color:#8FA9C4;border-left:1px solid rgba(255,255,255,.28);padding-left:13px;margin-left:6px;
             align-self:center}
.mark{width:32px;height:32px;border-radius:10px;flex:none;display:grid;place-items:center;
      background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.22)}
.mark svg{width:19px;height:19px;display:block;vertical-align:middle;margin:auto}
nav ul{list-style:none;display:flex;gap:4px;margin:0;padding:0;align-items:center}
nav a{display:flex;align-items:center;min-height:44px;padding:0 14px;border-radius:10px;color:#C7D6E8;
      font-weight:600;font-size:.93rem}
nav a:hover{background:rgba(255,255,255,.10);text-decoration:none}
nav a[aria-current=page]{color:#8FE3D8;background:rgba(255,255,255,.12)}
.has-sub{position:relative}
.has-sub>a::after{content:"";width:6px;height:6px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;
                  transform:rotate(45deg) translateY(-2px);margin-left:8px;display:inline-block}
/* the ::after bridge keeps the pointer inside .has-sub while it travels to the panel */
.has-sub::after{content:"";position:absolute;left:0;right:0;top:100%;height:12px}
.sub{position:absolute;top:100%;margin-top:8px;left:0;background:#fff;border:1px solid var(--line);border-radius:14px;
     box-shadow:var(--sh-h);padding:8px;min-width:340px;max-width:min(92vw,480px);display:none;
     flex-direction:column;gap:2px}
.has-sub:hover .sub,.has-sub:focus-within .sub{display:flex}
.sub a{display:block;min-height:40px;font-weight:700;font-size:.88rem;white-space:normal;
       line-height:1.35;padding:9px 12px;color:var(--navy);border-radius:10px}
.sub a:hover{background:var(--soft);text-decoration:none}
.sub a small{display:block;font-weight:500;font-size:.76rem;color:var(--muted);margin-top:3px}
/* ---- metrics: centred, consistent, one dimension per card ---- */
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:22px}
.metric{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:30px 24px;
        box-shadow:var(--sh);transition:transform .22s,box-shadow .22s;text-align:center}
.metric:hover{transform:translateY(-4px);box-shadow:var(--sh-h)}
.metric b{display:block;font-size:2.05rem;line-height:1.05;color:var(--teal);font-weight:800;letter-spacing:-.03em}
.metric small{display:block;margin-top:10px;color:var(--muted);font-size:.85rem;line-height:1.55}
/* ---- cards ---- */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(285px,1fr));gap:22px;margin-top:34px}
.card{background:#fff;border:1px solid #D5E0EA;border-radius:var(--r);padding:26px;
      box-shadow:0 2px 4px rgba(15,23,42,.06),0 12px 28px rgba(15,23,42,.09);
      display:block;transition:transform .22s,box-shadow .22s,border-color .22s}
.card:hover{transform:translateY(-4px);box-shadow:var(--sh-h);border-color:var(--teal);text-decoration:none}
.card h3{margin-bottom:8px}
.card p{font-size:.9rem;margin:0;color:var(--body);text-align:justify;hyphens:auto}
.card .k{display:inline-block;margin-top:16px;background:var(--tint);color:var(--navy);font-weight:700;
         font-size:.8rem;padding:5px 13px;border-radius:100px;line-height:1.5;white-space:nowrap}
/* a card that is itself a link to another page: the CTA must read as clickable, not pale */
a.card>.k{background:var(--teal);color:#fff}
a.card:hover>.k{background:var(--teal-d);color:#fff}
a.card>p+ul,.card ul.bul{margin:10px 0 0;padding-left:18px;font-size:.9rem;color:var(--body)}
a.card>ul.bul li,.card ul.bul li{margin-bottom:6px}
.chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:16px}
/* a chip label may be long ("liaison across ministries and regional governments"): measured
   5.3px past the card edge with nowrap. Wrap the text inside the chip instead of letting it
   overhang -- only .chips, so the short CTA labels elsewhere keep their single line. */
.chips .k{margin-top:0;background:var(--soft);border:1px solid var(--tint);white-space:normal}
/* a tag is a label: give it a surface so it sits on the page instead of dissolving into it */
/* Measured: the pill box aligned with the heading, but its text sat 12px right of the
   heading's text (11px padding + 1px border). Negative margin cancels the padding so the
   label reads flush with the heading; the pill keeps its own background. */
.ktag{display:inline-block;font-size:.66rem;font-weight:800;letter-spacing:.9px;
      text-transform:uppercase;color:var(--teal-d);background:var(--tint);border:1px solid #CFE3E4;
      padding:4px 11px;border-radius:100px;margin-bottom:12px}
/* ---- timeline ---- */
.tl{position:relative;display:grid;gap:14px;margin-top:38px;padding-left:32px}
.tl::before{content:"";position:absolute;left:9px;top:14px;bottom:14px;width:3px;
            background:linear-gradient(180deg,var(--teal) 0%,var(--navy) 100%);
            border-radius:3px;opacity:.55}
.tl-item::after{content:"";position:absolute;left:-29px;top:26px;width:17px;height:17px;
                border-radius:50%;background:#fff;border:3px solid var(--teal);
                box-shadow:0 0 0 4px #fff;z-index:1}
.tl-item.now::after{background:var(--live);border-color:var(--live)}
.tl-item{position:relative;background:#fff;border:1px solid var(--line);border-radius:16px;padding:20px 24px;
         box-shadow:var(--sh);transition:transform .22s,box-shadow .22s}
.tl-item:hover{transform:translateY(-3px);box-shadow:var(--sh-h)}
.tl-item.now{border-color:var(--teal)}
.tl-item::before{content:"";position:absolute;left:0;top:20px;bottom:20px;width:3px;border-radius:0 3px 3px 0;
                 background:var(--line)}
.tl-item.now::before{background:var(--teal)}
.tl-when{display:block;font-size:.74rem;font-weight:800;letter-spacing:.8px;text-transform:uppercase;
         color:var(--live);margin-bottom:7px}
.tl-role{font-weight:800;color:var(--navy);font-size:1.18rem;line-height:1.25}
.tl-org{font-size:.92rem;color:var(--navy);font-weight:600}
.tl-org em{font-style:normal;color:var(--body);font-weight:400}
.tl p{margin:8px 0 0;font-size:.9rem;text-align:justify;hyphens:auto}
.tl .more{display:inline-block;margin-top:10px;font-weight:700;font-size:.86rem}
/* ---- callout: puts a box around a claim instead of loose prose ---- */
/* the contact page opened with a bare heading where every other page shows a face; the hero
   portrait already exists, so reuse it as a small round avatar beside the heading. */
.contact-head{display:flex;align-items:center;justify-content:space-between;flex-direction:row-reverse;gap:22px;flex-wrap:wrap}
.contact-photo{width:132px;height:132px;border-radius:50%;object-fit:cover;object-position:center;
  flex:none;box-shadow:0 10px 26px rgba(15,23,42,.16)}
.callout{background:var(--soft);border-left:4px solid var(--teal);border-radius:0 14px 14px 0;
         padding:22px 26px;margin:26px 0}
.callout p{margin:0;text-align:justify;hyphens:auto}
.callout strong{color:var(--navy)}
.dark-callout{background:rgba(255,255,255,.07);border-left-color:#5EEAD4;border-radius:0 14px 14px 0;
              padding:22px 26px;margin:26px 0}
.dark-callout p{margin:0;color:#E2ECF6;text-align:justify;hyphens:auto}
/* ---- numbered chapter labels inside a role section ---- */
.step{display:flex;gap:12px;align-items:center;margin:40px 0 16px}
.step i{font-style:normal;font-weight:800;color:var(--teal);font-size:.82rem;letter-spacing:1px}
.step h3,.subhead{display:inline-block;background:#fff;border:1px solid var(--line);border-radius:100px;
                  padding:6px 16px;font-size:.98rem;box-shadow:var(--sh-soft)}
.band-soft .step h3,.band-soft .subhead{background:#fff}
.subhead{font-size:.78rem;font-weight:800;letter-spacing:.8px;text-transform:uppercase;
         color:var(--navy);margin:26px 0 10px}
/* ---- bullet lists ---- */
ul.tick{list-style:none;margin:0;padding:0}
ul.tick li{position:relative;padding:0 0 12px 30px;text-align:justify;hyphens:auto}
/* one bullet colour everywhere: the solid/hollow mix read as random, not as a code */
ul.tick li::before{content:"";position:absolute;left:2px;top:.62em;width:9px;height:9px;border-radius:2px;
                   background:var(--teal);border:2px solid var(--teal);transform:rotate(45deg)}
ul.tick li.extra::after{content:"beyond the role";position:absolute;left:30px;bottom:4px;font-size:.68rem;
                        font-weight:800;letter-spacing:.6px;text-transform:uppercase;color:var(--live)}
ul.tick li.extra{padding-bottom:24px}
/* ---- photo collage: one caption per GROUP, not per tile ---- */
.panel{background:#fff;border:1px solid var(--tint);border-radius:20px;padding:34px 34px 40px;
       box-shadow:var(--sh-soft);margin-top:40px}
.panel:first-of-type{margin-top:0}
.panel .period{display:block;font-size:.74rem;font-weight:800;letter-spacing:.8px;text-transform:uppercase;
               color:var(--live);margin-bottom:8px}
.panel h2{font-size:1.5rem;line-height:1.2;margin:0;text-wrap:pretty}
.unitline{display:flex;flex-wrap:wrap;align-items:stretch;gap:8px;margin-top:12px}
.unitline .inst,.unitline .unit{align-self:center;vertical-align:middle}
.unitline .inst,.unitline .unit{display:inline-block;font-weight:800;font-size:.8rem;padding:5px 14px;
  border-radius:100px;line-height:1.5}
.unitline .inst{background:var(--tint);color:var(--navy)}
.unitline .unit{background:var(--live-tint);color:var(--live)}.panel .lead-in{color:var(--muted);font-size:.9rem;margin-bottom:0}
/* job descriptions live in .panel p, which had no justification rule and so sat ragged */
.panel p{text-align:justify;hyphens:auto}
.panel .lead-in{text-align:left}
.panel ul.tick em.when{font-style:normal;color:var(--live);font-weight:700;font-size:.82rem}
.totop{margin:30px 0 0;font-size:.84rem;font-weight:700}
.panel .unit{display:inline-block;background:var(--live-tint);color:var(--live);font-weight:800;
             font-size:.8rem;padding:5px 14px;border-radius:100px;margin-top:10px}
/* .panel .unit sets margin-top:10px for a unit chip standing alone in a panel body.
   Inside .unitline that same span sits beside .inst, and the 10px pushed it 5px lower
   (measured 247.9 vs 252.9 on every role page). Equal specificity, so this must come
   after the .panel rule to win. */
.unitline .unit{margin-top:0}
.casemeta{display:inline-block;background:var(--soft);border-left:3px solid var(--live);
          border-radius:0 10px 10px 0;padding:8px 15px;font-size:.78rem;font-weight:800;
          letter-spacing:.5px;text-transform:uppercase;color:var(--navy);margin-top:14px}
.grp{margin-top:30px}
.grp-head{display:flex;justify-content:space-between;gap:18px;align-items:baseline;flex-wrap:wrap;
          background:var(--soft);border:1px solid var(--tint);border-left:4px solid var(--teal);
          border-radius:0 14px 14px 0;padding:14px 18px;box-shadow:var(--sh-soft)}
.grp-head h3{margin:0}
.grp-cap{font-size:.9rem;color:var(--body);margin:12px 0 0;max-width:82ch;text-align:justify;hyphens:auto}
/* Fixed-width columns, centred. With `1fr` tracks a short last row always fills the grid and
   cannot be balanced; a computed track width plus justify-content:center centres the remainder,
   which is the rule Ian asked for: "center ke tengah ... biar ga berat sebelah". --c is set per
   group from the photo count. */
.collage{--g:12px;--c:4;display:grid;gap:var(--g);margin-top:18px;justify-content:center;
         grid-template-columns:repeat(var(--c),calc((100% - (var(--c) - 1) * var(--g)) / var(--c)))}
/* Every tile is a framed object: a real outline (not the hairline --line, which reads as
   contrast 1.2 on white and disappears), an inner white bevel, and a two-part shadow --
   contact shadow at the base plus a wide soft one -- so the tiles read as raised. */
.collage a{display:block;position:relative;overflow:hidden;border-radius:14px;
           border:1px solid #7089A0;
           background:var(--soft);
           box-shadow:inset 0 1px 0 rgba(255,255,255,.9),
                      0 1px 2px rgba(15,23,42,.16),
                      0 3px 6px rgba(15,23,42,.10),
                      0 14px 30px rgba(15,23,42,.13);
           transition:transform .22s,box-shadow .22s}
.collage a:hover{transform:translateY(-3px);
                 box-shadow:inset 0 1px 0 rgba(255,255,255,.9),
                            0 2px 4px rgba(15,23,42,.18),
                            0 8px 16px rgba(15,23,42,.12),
                            0 26px 48px rgba(15,23,42,.20)}
.collage img{width:100%;height:100%;object-fit:cover;aspect-ratio:4/3}
.collage.lead a:first-child{grid-column:span var(--span,2);grid-row:span 2}
.collage.lead a:first-child img{aspect-ratio:auto;height:100%}
.collage.single{grid-template-columns:minmax(0,420px);justify-content:center}
/* a case-study cover is one wide tile in the same 2:1 frame the documentation uses,
   so a cover never reads as a different shape from its group */
.collage.single.shot{grid-template-columns:minmax(0,760px)}
.shotgroup .collage.single a:first-child{aspect-ratio:2/1;flex-basis:760px;max-width:100%;
  padding:8px;background:#fff;display:flex;align-items:center;justify-content:center}
.collage.single.shot img{object-fit:contain;aspect-ratio:auto;height:auto;max-height:100%;max-width:100%}
.collage.single img{aspect-ratio:4/3}
/* A screenshot is a document: show it whole, never cropped, with a fixed frame so every
   tile in a row ends on the same line. Flex (not grid) because a grid fills a short last
   row from the left; flex with justify-content:center centres it, which is Ian's rule.
   The cover runs full width, the rest sit three across. */
.shotgroup .collage{display:flex;flex-wrap:wrap;align-items:stretch;justify-content:center}
.shotgroup .collage a{flex:0 0 calc((100% - 2 * var(--g)) / 3);
  aspect-ratio:2/1;display:flex;align-items:center;justify-content:center;
  padding:8px;background:#fff}
.shotgroup .collage a:first-child{flex-basis:100%;aspect-ratio:auto;padding:12px}
.shotgroup .collage.shot-portrait a:first-child img{max-height:620px;width:auto;margin:0 auto}

/* a two-image group has no row under the cover: giving the first one 100% left the second
   at 346px next to a 1062px cover, ragged and off-centre. Two images sit as an equal pair
   in the same 2:1 frame the rest of the shots use. */
.shotgroup .collage a:first-child:nth-last-child(2),
.shotgroup .collage a:nth-child(2):last-child{flex-basis:calc((100% - var(--g)) / 2);
  aspect-ratio:2/1;padding:8px}
.shotgroup .collage img{object-fit:contain;aspect-ratio:auto;height:auto;max-height:100%;
  max-width:100%;background:#fff;display:block}

/* ---- lightbox: CSS only, no JavaScript ------------------------------------------------
   Each gallery tile is <a href="#lb-...">; the matching overlay is a sibling with that id and is
   hidden until :target matches, so one visited URL opens exactly one image. The close button is a
   plain link back to `#`, which un-targets everything. The full-size <img> is not a data URI --
   it points at the original file in assets/, so nothing extra is downloaded until it is opened. */
.lb{position:fixed;inset:0;z-index:200;display:none;place-items:center;padding:28px;
    background:rgba(15,23,42,.92)}
.lb:target{display:grid}
/* Closing in JavaScript: history.replaceState clears the hash, but Chromium keeps :target
   matching the old element -- the URL is clean while the overlay stays on screen. The close
   handlers therefore flag the open overlay instead of trusting :target to stop matching.
   Specificity 0,3,0 beats .lb:target so no !important is needed. */
.lb:target.is-closed{display:none}
.lb img{max-width:100%;max-height:calc(100vh - 96px);object-fit:contain;border-radius:10px;
        box-shadow:0 24px 70px rgba(0,0,0,.55);background:#fff}
.lb .lb-x{position:fixed;top:16px;right:20px;width:44px;height:44px;display:grid;place-items:center;
          border-radius:50%;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.34);
          color:#fff;font-size:1.5rem;line-height:1;text-decoration:none;font-weight:400}
.lb .lb-x:hover{background:rgba(255,255,255,.26);text-decoration:none}
.lb .lb-cap{position:fixed;left:0;right:0;bottom:14px;text-align:center;color:#CBD5E1;
            font-size:.82rem;padding:0 24px}
@media print{.lb{display:none!important}}
@media (max-width:760px){
  .shotgroup .collage a{flex-basis:calc((100% - var(--g)) / 2)}
}
/* ---- case studies ---- */
.case{border:1px solid var(--line);border-radius:var(--r);padding:30px;background:#fff;box-shadow:var(--sh);margin-top:22px}
.case h3{margin-bottom:6px}
.case .meta{font-size:.8rem;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);margin-bottom:16px}
.case h4{font-size:.78rem;font-weight:800;letter-spacing:.8px;text-transform:uppercase;color:var(--navy);margin:22px 0 8px}
.case p{text-align:justify;hyphens:auto;margin:0}
/* ---- footer ---- */
footer{background:var(--navy);color:#C6D5E6;padding:56px 0 34px;font-size:.9rem}
footer a{color:#8FE3D8}
.foot-g{display:grid;grid-template-columns:1.3fr 1fr 1.4fr;gap:36px}
#ftitle{display:block;font-size:1.02rem;font-weight:800;color:#fff;margin:0 0 12px}
.fbrand{display:flex;align-items:center;gap:11px;margin-bottom:12px}
.fbrand .mark{background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.22)}
.fbrand .fname{font-size:1.02rem;font-weight:800;color:#fff;line-height:1.25}
.fbrand .ftag{display:block;font-size:.62rem;font-weight:800;letter-spacing:1.1px;text-transform:uppercase;
              color:#8FA9C4;margin-top:3px}
.fsvg{width:15px;height:15px;flex:none;stroke:#8FE3D8;fill:none;stroke-width:1.8;
      stroke-linecap:round;stroke-linejoin:round}
.fitem{display:flex;align-items:center;gap:9px}
.fitem svg{margin-top:1px}
footer a{color:#B9ECDF;font-weight:600}
footer a:hover{color:#fff}
footer h4{color:#fff;font-size:.82rem;letter-spacing:.8px;text-transform:uppercase;margin-bottom:14px}
footer ul{list-style:none;margin:0;padding:0}
footer li{margin-bottom:9px}
footer h4.mt{margin-top:24px}
.foot-b{margin-top:40px;padding-top:20px;border-top:1px solid rgba(255,255,255,.14);font-size:.82rem;
        color:#9FB4CC}
/* ---- motto: set like an inscription - a rule, air, one statement ---- */
.motto{background:var(--navy);color:#DCE7F3;position:relative;overflow:hidden}
@supports (overflow:clip){.motto{overflow:clip}}
.motto-in{display:grid;grid-template-columns:250px minmax(0,700px);gap:56px;align-items:center;
          justify-content:center;position:relative;z-index:2}
.motto figure{margin:0;width:250px}
.motto figure img{width:250px;height:310px;object-fit:cover;border-radius:16px;
                  box-shadow:0 18px 40px rgba(0,0,0,.28)}
.motto figcaption{margin-top:12px;font-size:.78rem;color:#9FBAD6;line-height:1.5}
.motto blockquote{margin:0;padding:0}
.motto blockquote::before{content:"";display:block;width:64px;height:3px;border-radius:3px;
                          background:#5EEAD4;margin-bottom:26px}
.motto q,.motto blockquote p{margin:0;font-size:clamp(1.3rem,2.6vw,1.85rem);line-height:1.42;
       color:#fff;font-weight:700;letter-spacing:-.015em;text-wrap:balance;quotes:'"' '"'}
.motto .msig{margin-top:22px;font-size:.82rem;font-weight:700;letter-spacing:.4px;
             color:#8FA9C4}
/* ---- responsive ---- */
/* ---- certificates: text cards, file linked (never embedded) ---- */
.cert .meta{display:block;font-size:.76rem;font-weight:700;letter-spacing:.5px;text-transform:uppercase;
            color:var(--muted);margin:7px 0 10px}
.cert p{font-size:.87rem}
.cert{position:relative}
.cert .stretch{position:absolute;inset:0;border-radius:var(--r)}
.cert:hover .k{text-decoration:underline}
/* Two fixes measured against the certs section:
   - the gap from a group title to its own cards was 34px (the cards carry margin-top:34px), so
     the label sat equidistant between the row above and the row below. Pull the cards up.
   - at .78rem the label was smaller and lighter than the .eyebrow chip above it (.72rem but
     green on tint). Navy at .86rem gives the section heading hierarchy. */
.group-title{display:inline-block;font-size:.66rem;font-weight:800;letter-spacing:.9px;
             text-transform:uppercase;color:var(--teal-d);background:var(--soft);
             border:1px solid var(--line);border-radius:100px;padding:7px 13px;margin:34px 0 0}
.group-title+.cards{margin-top:14px}
@media(max-width:900px){
  .orn{display:none}
  .motto-in{grid-template-columns:1fr;gap:30px}
  .motto figure{width:190px}
  .motto figure img{width:190px;height:236px}
  .hero-inner{grid-template-columns:1fr;gap:34px}
  .portrait{width:320px;height:320px;margin:0 auto}
  .foot-g{grid-template-columns:1fr 1fr}
  .collage{--c:2}
}
@media(max-width:680px){
  section{padding:52px 0}
  .hdr{flex-direction:column;align-items:stretch;padding:10px 24px 6px;gap:6px}
  nav ul{justify-content:space-between;flex-wrap:wrap}
  nav a{padding:0 10px;font-size:.88rem}
  .sub a{font-size:.86rem}
  .has-sub:hover .sub,.has-sub:focus-within .sub{position:static;box-shadow:none;border:0;padding:2px 0 0 10px}
  .sub{min-width:0;max-width:100%;background:transparent}
  /* Narrow screens: a tap leaves :hover on whatever it touched, so the panel opened and closed
     on its own and pushed the rows around while the finger was still down -- "the button keeps
     moving". Below this width the tap goes straight to Work; keyboard focus still opens the panel. */
  .has-sub:hover .sub{display:none}
  .has-sub:focus-within .sub{display:flex}
  .collage{--c:2}
  .collage.lead a:first-child{grid-column:span 2;grid-row:auto}
  .foot-g{grid-template-columns:1fr}
  footer{padding:40px 0 26px}
}
/* ---- reveal on scroll: a native scroll-driven animation, still zero JavaScript.
   Browsers without support, or with reduced motion, show the content immediately.

   The range ends at 'entry 100%' rather than inside 'cover'. With a range that ends
   during 'cover', an element whose entry never completes -- the last blocks on a page,
   or anything taller than the viewport -- keeps whatever partial value it reached:
   measured at 7 elements left stuck at opacity 0.24, and 2 more at 0.80/0.45, which
   reads as "some cards never appear". The trade is that the fade is quicker, which
   suits the requested effect: content arrives as the cursor brings it in.
   ponytail: the gradual range is 'entry 0% cover 30%'; it needs a JS IntersectionObserver
   fallback to avoid the stuck case, which this zero-JavaScript site does not have. ---- */
@keyframes fadeup{from{opacity:0;translate:0 30px}to{opacity:1;translate:0 0}}
@keyframes fadein{from{opacity:0}to{opacity:1}}
/* ---- reveal on scroll, driven by assets/js/reveal.js.
   Only active while <html class="js"> is present: the script deletes that class the moment it
   runs, so a visitor with JavaScript blocked, or a crawler, always sees the full page. The
   previous version used animation-timeline: view(), which is pure CSS but scrubs with scroll
   position -- content already on screen after a jump or a restore never animated, and stayed
   at 0.24 opacity. That was the "fade-in masih gagal" that kept coming back. ---- */
@media(prefers-reduced-motion:no-preference){
  html.js .fx{opacity:0;translate:0 18px;transition:opacity .6s ease,translate .6s ease}
  html.js .fx.in{opacity:1;translate:0 0}
  html.js .fx.soft{translate:none}
}
body.page-enter{animation:fadein .45s ease both}
body.page-leave{opacity:0;transition:opacity .12s ease}
@media(prefers-reduced-motion:reduce){
  html.js .fx{opacity:1;translate:none;transition:none}
}
/* ---- cross-document page transitions: still zero JavaScript.
   Moving between pages replaced the document in one frame, which reads as a hard cut. The
   @view-transition at-rule lets the browser cross-fade the old and new page itself. Browsers
   without support navigate exactly as before -- no fallback, no script. */
@view-transition{navigation:auto}
::view-transition-old(root){animation:fadein .18s linear both;animation-direction:reverse}
::view-transition-new(root){animation:fadein .22s linear both}
@media(prefers-reduced-motion:reduce){
  ::view-transition-old(root),::view-transition-new(root){animation:none}
}
@media print{
  .fx{animation:none!important}
  header,footer,.cta{display:none}
  section{padding:18px 0;page-break-inside:avoid}
  .card,.metric,.case,.collage a{box-shadow:none}
}
