/* GAFAS Group, advertising site (29 Oct 26).
   Broadsheet layout on white, in the logo's own colours only (client, 29 Oct 26: "C.I jangan ubah, ikut 3 kaler logo"):
   navy #192853, blue #0c5893, grey #44546a (the "Since 2004" line), on white. The logo is never recoloured. */
:root {
  --paper: #fff;
  --ink: #192853;
  --blue: #0c5893;
  --grey: #44546a;
  --rule: rgba(25, 40, 83, .14);
  --rule-2: rgba(25, 40, 83, .3);
  --wash: rgba(12, 88, 147, .05);
  /* one typeface, Montserrat (1 Nov 26: the client wanted plain type, a J with only a small hook; Dave picked it from
     seven). The names stay --serif (display) and --sans (text), so the rules below kept their places. */
  --serif: 'Montserrat Variable', 'Segoe UI', system-ui, sans-serif;
  --sans: 'Montserrat Variable', 'Segoe UI', system-ui, sans-serif;
  --pad: clamp(20px, 4.4vw, 64px);
  --max: 1320px;
  --ease: cubic-bezier(.2, .7, .2, 1);
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 96px; }
/* The grid columns are minmax(0, 1fr), not 1fr (9 Nov 26): Samsung Internet follows the phone's font size, and at
   115-130 % on a 320-360 px screen a long word, an e-mail or the phone number pushed its column past the screen, where
   the clip below cut it off. Now a column keeps to its share; the few things that can still be too long for a phone
   break inside themselves (headline words, values in .rows, the closing heading: see the phone rules further down). */
body { margin: 0; overflow-x: clip; background: var(--paper); color: var(--ink); font: 400 17px/1.6 var(--sans); -webkit-font-smoothing: antialiased; }
img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--pad); }
.label { font: 600 11.5px/1.2 var(--sans); letter-spacing: .17em; text-transform: uppercase; color: var(--grey); }
.label.blue { color: var(--blue); }
em { font-style: italic; }
/* in headings and the ticker the stressed words go light (and blue) rather than slanting */
:is(h1, h2, h3, .ticker) em { font-style: normal; font-weight: 300; }
.nw { white-space: nowrap; }
.skip { position: absolute; inset-inline-start: 12px; top: -60px; z-index: 80; background: var(--ink); color: #fff; padding: 10px 14px; font-weight: 600; }
.skip:focus { top: 12px; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }

/* ---------- languages: a small button in the header opens the six; on phones they sit in the menu ---------- */
.lang-pick { position: relative; }
.lang-pick summary { display: inline-flex; align-items: center; gap: 7px; height: 42px; padding: 0 12px; border-radius: 999px; list-style: none; color: var(--grey); font: 600 13.5px/1 var(--sans); letter-spacing: .04em; cursor: pointer; transition: color .2s, background .2s; }
.lang-pick summary::-webkit-details-marker { display: none; }
.lang-pick summary:hover, .lang-pick[open] summary { color: var(--ink); background: var(--wash); }
.lang-pick summary svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.lang-pick summary .chev { width: 13px; height: 13px; transition: transform .25s var(--ease); }
.lang-pick[open] summary .chev { transform: rotate(180deg); }
.lang-pick .langs { position: absolute; inset-inline-end: 0; top: calc(100% + 10px); z-index: 50; display: grid; min-width: 220px; padding: 6px; border: 1px solid var(--rule); border-radius: 12px; background: #fff; box-shadow: 0 24px 50px -24px rgba(25, 40, 83, .45); }
.langs a { display: flex; align-items: baseline; justify-content: space-between; gap: 18px; transition: color .2s, background .2s; }
.lang-pick .langs a { padding: 10px 12px; border-radius: 8px; font: 500 15px/1.2 var(--sans); }
.lang-pick .langs a b { font-size: 11.5px; font-weight: 600; letter-spacing: .06em; color: var(--grey); }
.lang-pick .langs a:hover { background: var(--wash); }
.lang-pick .langs a[aria-current] { background: var(--wash); color: var(--blue); }
.sheet .langs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.sheet .langs a { padding: 10px 14px; border: 1px solid var(--rule-2); border-radius: 999px; font: 600 14px/1 var(--sans); }
.sheet .langs a span { display: none; }
.sheet .langs a[aria-current] { border-color: var(--ink); background: var(--ink); color: #fff; }

/* Chinese and Cantonese pages: Montserrat still sets Latin letters and numbers, Noto Sans the characters;
   no negative tracking, no slanted characters (em stays blue), and a little more line height */
html:lang(zh-Hans) { --serif: 'Montserrat Variable', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif; --sans: 'Montserrat Variable', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif; }
html:lang(zh-Hant) { --serif: 'Montserrat Variable', 'Noto Sans TC', 'PingFang TC', 'Microsoft JhengHei', sans-serif; --sans: 'Montserrat Variable', 'Noto Sans TC', 'PingFang TC', 'Microsoft JhengHei', sans-serif; }
html:lang(yue) { --serif: 'Montserrat Variable', 'Noto Sans HK', 'PingFang HK', 'Microsoft JhengHei', sans-serif; --sans: 'Montserrat Variable', 'Noto Sans HK', 'PingFang HK', 'Microsoft JhengHei', sans-serif; }
html:is(:lang(zh), :lang(yue)) body { line-height: 1.8; }
html:is(:lang(zh), :lang(yue)) :is(h1, h2, h3, .deck, .pull, .ticker span, .also, .places h3, .sites td) { letter-spacing: 0; }
html:is(:lang(zh), :lang(yue)) :is(em, .ticker span, .pull, .also, .deck, figcaption, .hook, .ft-brand p, .note) { font-style: normal; }
html:is(:lang(zh), :lang(yue)) :is(.label, .msi, .rows dt, .meta dt, .sites th) { letter-spacing: .08em; }
html:is(:lang(zh), :lang(yue)) :is(.hero h1, .phead h1, .map-text h2) { line-height: 1.15; }

/* ---------- header: logo, four links, language, WhatsApp; nothing else ----------
   It is 92px in the page and sticks with its top 16px above the screen, so 76px stay visible once you scroll.
   Shrinking it uses transforms only: changing its height while scrolling would make the page jump. */
.hdr { position: sticky; top: -16px; z-index: 40; height: 100px; background: rgba(255, 255, 255, .96); -webkit-backdrop-filter: saturate(1.4) blur(10px); backdrop-filter: saturate(1.4) blur(10px); border-bottom: 1px solid var(--rule); transition: box-shadow .35s var(--ease); }
.hdr.compact { box-shadow: 0 12px 30px -26px rgba(25, 40, 83, .5); }
.hdr .wrap { height: 100%; display: grid; grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr); align-items: center; gap: 24px; transition: transform .45s var(--ease); }
.hdr.compact .wrap { transform: translateY(8px); }
.logo { display: block; justify-self: start; }
.logo img { height: 80px; width: auto; max-width: none; transform-origin: left center; transition: transform .45s var(--ease); }
.hdr.compact .logo img { transform: scale(.8); }
.nav { display: flex; align-items: center; gap: 34px; font: 500 15px/1 var(--sans); }
.nav-r { justify-self: end; gap: 10px; grid-column: 3; }
.nav-main a { position: relative; padding: 8px 0; color: var(--grey); white-space: nowrap; transition: color .2s; }
.nav-main a:hover, .nav-main a[aria-current] { color: var(--ink); }
.nav-main a[aria-current]::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--blue); }
.pill { display: inline-flex; align-items: center; gap: 9px; height: 42px; padding: 0 18px; border-radius: 999px; background: var(--ink); color: #fff; font: 600 14px/1 var(--sans); transition: background .25s var(--ease); }
.pill:hover { background: var(--blue); }
.pill svg, .btn svg { width: 17px; height: 17px; flex: none; }
.menu-btn { display: none; align-items: center; gap: 8px; height: 42px; padding: 0 14px; border: 1px solid var(--rule-2); border-radius: 999px; background: #fff; font: 600 14px/1 var(--sans); cursor: pointer; }
.menu-btn i, .menu-btn i::before { display: block; width: 16px; height: 1.5px; background: currentColor; position: relative; }
.menu-btn i::before { content: ""; position: absolute; top: 5px; }
.menu-btn i { transform: translateY(-2.5px); }
/* six menu items since Ito's PPT V2 (7 Nov 26): each stays on one line and the logo keeps its size. A little closer
   together below 1300 px; below 1200 px they no longer fit beside the logo and the buttons in English, Malay or
   Indonesian (measured 7 Nov 26), so the Menu button takes over there, as on a phone */
@media (max-width: 1300px) { .nav-main { gap: 26px; } }
@media (max-width: 1200px) { .nav-main { display: none; } .menu-btn { display: inline-flex; } }

/* phone menu */
.sheet { position: fixed; inset: 0; z-index: 60; background: #fff; display: flex; flex-direction: column; padding: 0 var(--pad) 32px; visibility: hidden; opacity: 0; transform: translateY(-8px); transition: opacity .3s var(--ease), transform .3s var(--ease), visibility 0s .3s; overflow-y: auto; }
.sheet.open { visibility: visible; opacity: 1; transform: none; transition: opacity .3s var(--ease), transform .3s var(--ease); }
.sheet-top { flex: none; display: flex; justify-content: space-between; align-items: center; height: 76px; border-bottom: 3px double var(--ink); }   /* flex: none: on a short phone the menu scrolls instead of squeezing this bar */
.sheet-top img { height: 60px; width: auto; }
.sheet .menu-btn { display: inline-flex; }
.sheet nav:not(.langs) { display: flex; flex-direction: column; margin-top: 14px; }
.sheet nav:not(.langs) a { display: flex; justify-content: space-between; align-items: baseline; padding: 16px 0; border-bottom: 1px solid var(--rule); font: 400 34px/1.1 var(--serif); letter-spacing: -.02em; }
.sheet nav:not(.langs) a span { font: 600 11px/1 var(--sans); letter-spacing: .16em; color: var(--grey); }
.sheet nav:not(.langs) a[aria-current] { color: var(--blue); }
.sheet-foot { margin-top: auto; padding-top: 28px; display: grid; gap: 12px; }
.sheet-foot .btn { width: 100%; }
.sheet-foot p { margin: 6px 0 0; color: var(--grey); font-size: 14px; text-align: center; }
body.menu-open { overflow: hidden; }

/* ---------- buttons and links ---------- */
.ctas { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 26px; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; height: 54px; padding: 0 28px; border: 0; border-radius: 999px; background: var(--ink); color: #fff; font: 600 15px/1 var(--sans); cursor: pointer; transition: background .25s var(--ease), transform .25s var(--ease); }
.btn:hover { background: var(--blue); transform: translateY(-1px); }
.btn.line { background: transparent; color: var(--ink); box-shadow: inset 0 0 0 1px var(--rule-2); }
.btn.line:hover { background: var(--wash); box-shadow: inset 0 0 0 1px var(--ink); }
.arrow-link { display: inline-flex; align-items: center; gap: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--rule-2); font: 600 15px/1 var(--sans); transition: border-color .2s, gap .2s; }
.arrow-link:hover { border-color: currentColor; gap: 14px; }

/* ---------- home: hero ---------- */
/* 2 Nov 26: the screen the client likes is the first picture (Ito: the map up here is "kurang pro" for a media buyer;
   of two drafts Dave chose this one): the headline on the left, a wide screen on the right playing the three case
   studies' own clips, then the lead and the facts across, under a rule. The map is on Media Campaign (below). */
.hero { position: relative; overflow: hidden; padding: 0 0 clamp(40px, 5vw, 72px); }
.hero-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr); gap: 32px clamp(32px, 4.5vw, 72px); align-items: center; padding: clamp(36px, 5vw, 76px) 0 clamp(30px, 3.4vw, 50px); }
.hero .screen.wide .bezel { aspect-ratio: 16 / 9.4; }
.hero .screen figcaption { font-size: 14px; }
.hero-foot { display: grid; grid-template-columns: 1.25fr 1fr; gap: 24px clamp(36px, 5vw, 80px); align-items: end; padding-top: 26px; border-top: 1px solid var(--ink); }
.hero .hero-foot .lead { margin: 0; }
/* each fact as wide as it needs, so a number never breaks ("17 tahun" in Malay and Indonesian did) */
.hero-foot .facts { grid-template-columns: repeat(3, auto); margin-top: 0; border-top: 0; }
.hero-foot .facts div { padding-top: 0; }
.hero-foot .facts strong { white-space: nowrap; }
.hero h1 { font: 400 clamp(44px, 5.4vw, 80px)/1.02 var(--serif); letter-spacing: -.035em; margin: 18px 0 26px; }
.hero h1 em { display: block; color: var(--blue); }
/* The diamonds sit in the gap between two names. Each one is drawn by the name after it, but outside that name, so when
   a name wraps to a new line its diamond lands past the start edge and overflow clips it: no line starts with a
   diamond, and the new line starts flush (9 Nov 26: Dave's Samsung Flip, with its bigger text, showed "◆ INDONESIA" on a
   second line, pushed in by the diamond's margin). --sep is the gap, --dot the diamond. */
.msi { --sep: calc(2.6em + 6px); --dot: 6px; display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--sep); row-gap: .8em; overflow: hidden; margin: 0 0 30px; padding: 15px 0; border-top: 1px solid var(--ink); border-bottom: 1px solid var(--rule-2); font: 600 14px/1 var(--sans); letter-spacing: .2em; text-transform: uppercase; }
.msi > * { position: relative; }
.msi a { transition: color .2s; }
.msi a:hover { color: var(--blue); }
.msi > * + *::before { content: ""; position: absolute; top: 50%; inset-inline-start: calc(var(--sep) / -2 - var(--dot) / 2); width: var(--dot); height: var(--dot); margin-top: calc(var(--dot) / -2); background: var(--blue); transform: rotate(45deg); }
/* the headline block ends with the country line since 9 Nov 26 (no link under it): no gap left below it */
.hero .msi:last-child { margin-bottom: 0; }
.hero .lead { font-size: clamp(17px, 1.4vw, 20px); color: var(--grey); max-width: 600px; margin: 0 0 32px; }
.facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: 48px; border-top: 1px solid var(--ink); }
.facts div { padding-block: 16px 0; padding-inline: 0 18px; }
.facts div + div { padding-inline-start: 18px; border-inline-start: 1px solid var(--rule); }
.facts strong { display: block; font: 400 34px/1.05 var(--serif); letter-spacing: -.02em; }
.facts span { font-size: 13.5px; color: var(--grey); }

/* ---------- Media Campaign: the map ---------- */
/* 1 Nov 26: a hand-sketched map of the three markets (tools/make-map.mjs draws it), the home page's first screen until
   2 Nov 26. On a wide screen the content box is the stage, 1193 x 800 at the 1440px design: the heading sits bottom
   left over the Indian Ocean, and the map is placed so the peninsula, Singapore, East Malaysia's coast and Jakarta
   fall beside it. The numbers are that layout as percentages of the content width, so the drawing grows and shrinks
   with the page. */
.map-sec { position: relative; overflow: hidden; margin-bottom: clamp(56px, 6vw, 96px); border-block: 1px solid var(--rule); }
.stage { position: relative; aspect-ratio: 1193 / 800; }
.map-box { position: absolute; z-index: 0; left: -46.52%; top: 0; width: 193.13%; margin-top: -14.08%; pointer-events: none; clip-path: inset(0 0 27.98% 0); }
.map-box svg { display: block; width: 100%; height: auto; overflow: visible; direction: ltr; }
/* the heading in a box in the corner, like the title on an old map, so no coast or route runs through the words in
   any language; the same card as the map's buttons and panels */
.map-text { position: absolute; z-index: 2; left: 0; bottom: 4%; width: 34%; padding: 22px 24px 24px; background: #fff; border: 1px solid var(--ink); box-shadow: 6px 6px 0 var(--ink); }
.map-text h2 { margin: 10px 0 12px; font: 400 clamp(30px, 3vw, 44px)/1.06 var(--serif); letter-spacing: -.03em; }
.map-text h2 em { color: var(--blue); }
.map-text p { margin: 0; color: var(--grey); font-size: 14.5px; line-height: 1.5; }

/* the map itself: pen lines over hatching, like a page from a sketchbook. --k (set by site.js) is how big the
   drawing is on screen against its own units; pins and names divide by it so they stay readable on a phone. */
.map .grat path { fill: none; stroke: rgba(25, 40, 83, .08); stroke-width: 1; stroke-dasharray: 2 7; }
.map .grat .eq { stroke: rgba(12, 88, 147, .32); stroke-dasharray: 10 6; }
.map .grat text { fill: var(--blue); font: 500 calc(11.5px / var(--k, 1)) var(--sans); letter-spacing: .24em; text-transform: uppercase; opacity: .8; }
.map .side path { fill: rgba(25, 40, 83, .02); stroke: rgba(68, 84, 106, .4); stroke-width: .9; stroke-linejoin: round; }
.map .hatch { stroke: none; }
.map #hatch-my path { stroke: var(--blue); stroke-width: .8; opacity: .36; }
.map #hatch-id path { stroke: var(--grey); stroke-width: .75; opacity: .3; }
.map .land.sg .hatch { fill: var(--blue); opacity: .5; }
.map .land .ink { fill: none; stroke: var(--ink); stroke-width: 1.3; stroke-linejoin: round; stroke-linecap: round; }
.map .land .pencil { fill: none; stroke: var(--blue); stroke-width: .7; opacity: .5; stroke-linejoin: round; }
.map .routes path { fill: none; stroke: var(--blue); stroke-width: 1.2; opacity: .6; stroke-linecap: round; }
.map .routes .plan { stroke: var(--grey); opacity: .45; }
.map .trip { fill: var(--blue); }
.map .lm path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
/* the buildings: a touch larger when the whole map is small (phones), and when zoomed in they grow only so far: to
   1.8 times their size on a wide screen, to their own size on a phone (--k is the scale on screen) */
.map .lm-k { transform: scale(max(calc(.5 / var(--k, 1)), min(1, calc(clamp(1, 1.8 * var(--kb, 1), 1.8) / var(--k, 1))))); }
.map .lm { transition: opacity .35s; }
.map .lm.out { opacity: 0; }
.map .lm .line { stroke: var(--ink); stroke-width: calc(1.25px * var(--s, 1)); }
.map .lm .fine { stroke: var(--blue); stroke-width: calc(.6px * var(--s, 1)); opacity: .75; }
.map .cn { fill: var(--blue); font: 500 calc(19px / var(--k, 1)) var(--serif); letter-spacing: .42em; text-transform: uppercase; paint-order: stroke; stroke: #fff; stroke-width: 5px; stroke-linejoin: round; }
.map .city { fill: var(--ink); font: 600 10.5px var(--sans); letter-spacing: .16em; text-transform: uppercase; paint-order: stroke; stroke: #fff; stroke-width: 4px; stroke-linejoin: round; }
.map .pin { pointer-events: auto; cursor: pointer; }
/* --pop: a pin's size on screen against its drawing (smaller on a phone); --finger: how far from its centre a pin
   answers to a click, in screen px, unless another pin is nearer (site.js sets each pin's .hit from these) */
.map { --pop: 1; --finger: 14; }
.map .pop { transform: scale(calc(var(--pop) / var(--k, 1))); }
.map .pin .hit { fill: transparent; }
.map .pin .ring { fill: #fff; stroke: var(--ink); stroke-width: 1.3; transition: fill .2s, stroke .2s; }
.map .pin .dot { fill: var(--ink); transition: fill .2s; }
.map .pin.small .grow { scale: .78; }
.map .pin:hover .ring, .map .pin.on .ring { fill: var(--ink); stroke: var(--ink); }
.map .pin:hover .dot, .map .pin.on .dot { fill: #fff; }
.map .rose :is(circle, path) { fill: none; stroke: var(--ink); stroke-width: .9; opacity: .5; }
.map .rose path { fill: rgba(25, 40, 83, .05); }
.map .rose text { fill: var(--ink); font: 600 calc(13px / var(--k, 1)) var(--serif); opacity: .7; }
/* zooming into a country (1 Nov 26): a click on its land flies the map in and the heading steps aside;
   Back, Escape or a click on the sea fly it out. site.js sets --z (zoom), --k (on-screen size against map units, zoom
   included) and --kb (the same without zoom). While .flying they animate with the map; while .zoomfx lines keep the
   weight they had before the zoom, and the buildings grow only so far. */
@property --k { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --z { syntax: '<number>'; inherits: true; initial-value: 1; }
.map-box svg { transform-origin: 0 0; }
/* site.js sets how long a flight (or one leg of it) takes, and its easing */
.map-box.flying { transition: --k var(--fly, 1.1s) var(--fly-ease, cubic-bezier(.65, 0, .25, 1)), --z var(--fly, 1.1s) var(--fly-ease, cubic-bezier(.65, 0, .25, 1)); }
.map-box.flying svg { transition: transform var(--fly, 1.1s) var(--fly-ease, cubic-bezier(.65, 0, .25, 1)); }
.map .land .ink { pointer-events: fill; cursor: zoom-in; }
.zoomfx .map :is(.side path, .land .ink, .land .pencil, .lm path, .routes path, .rose circle, .rose path) { stroke-dasharray: none; vector-effect: non-scaling-stroke; }
.zoomfx .map .land .ink { stroke-width: calc(1.3px * var(--kb, 1)); }
.zoomfx .map .land .pencil { stroke-width: calc(.7px * var(--kb, 1)); }
.zoomfx .map .side path { stroke-width: calc(.9px * var(--kb, 1)); }
.zoomfx .map .routes path { stroke-width: calc(1.2px * var(--kb, 1)); }
/* a landmark's lines keep to its own drawing scale (--s is 1 / scale): the Merlion, drawn at half size, filled in solid */
.zoomfx .map .lm .line { stroke-width: calc(1.25px * var(--kb, 1) / var(--s, 1)); }
.zoomfx .map .lm .fine { stroke-width: calc(.6px * var(--kb, 1) / var(--s, 1)); }
/* the pencil wobble is too slow to redraw close up, mid-flight */
.zoomfx .map .lms { filter: none; }
/* close in, the hatching keeps hairlines, and Singapore is hatched like the rest instead of filled */
.zoomfx .map #hatch-my path { stroke-width: calc(.8px / var(--z, 1)); }
.zoomfx .map #hatch-id path { stroke-width: calc(.75px / var(--z, 1)); }
.deep .map .land.sg .hatch { fill: url(#hatch-my); opacity: 1; }
.zoomed .map { pointer-events: auto; cursor: zoom-out; }
.zoomed .map :is(.trip, .rose) { display: none; }
.stage > .map-text { transition: filter .45s var(--ease), visibility 0s; }
.stage.zoomed > .map-text { filter: opacity(0); visibility: hidden; transition: filter .45s var(--ease), visibility 0s .45s; }
/* the buttons over the map's top left corner: Back, and the visitor's proposal list */
.map-bar { position: absolute; z-index: 4; left: 24.09%; top: calc(12.5% + 18px); display: flex; flex-wrap: wrap; gap: 12px; pointer-events: none; }
.map-back { display: inline-flex; align-items: center; gap: 8px; height: 42px; padding: 0 16px; border: 1px solid var(--ink); border-radius: 999px; background: #fff; box-shadow: 4px 4px 0 var(--ink); font: 600 14px/1 var(--sans); color: var(--ink); cursor: pointer; pointer-events: auto; }
.map-back:hover { background: var(--wash); }
.map-back[hidden] { display: none; }
.map-back .ico { width: 17px; height: 17px; }
[dir="rtl"] .map-back .ico { transform: scaleX(-1); }
/* the country's business, beside the zoomed map: Singapore by media format, Malaysia state by state, Indonesia */
.map-panel { position: absolute; z-index: 3; top: 0; right: 0; width: min(390px, 33%); max-height: 94%; overflow: auto; margin-top: 2.2%; padding: 22px 22px 24px; background: #fff; border: 1px solid var(--ink); box-shadow: 6px 6px 0 var(--ink); animation: panel-in .55s .3s var(--ease) both; overscroll-behavior: contain; }
.map-panel[hidden] { display: none; }
@keyframes panel-in { from { opacity: 0; transform: translateY(14px); } }
.map-panel h3 { margin: 8px 0 6px; font: 500 30px/1.1 var(--serif); letter-spacing: -.02em; }
.map-panel > p { margin: 0 0 14px; color: var(--grey); font-size: 14px; line-height: 1.5; }
.biz { margin: 0 0 12px; padding: 0; list-style: none; border-top: 1px solid var(--rule-2); }
.biz li { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 1px 10px; padding: 9px 0; border-bottom: 1px solid var(--rule); }
.biz li .ico { grid-row: span 2; width: 20px; height: 20px; margin-top: 1px; color: var(--blue); }
.biz b { font-weight: 600; font-size: 14.5px; line-height: 1.3; }
.biz span { color: var(--grey); font-size: 13px; }
.biz-case { display: flex; gap: 8px; margin: 0; font-size: 13px; color: var(--grey); }
.biz-case .ico { width: 16px; height: 16px; color: var(--blue); flex: none; margin-top: 1px; }
.biz-states > div { padding: 9px 0; border-top: 1px solid var(--rule); }
.biz-states > div:first-child { border-top-color: var(--rule-2); }
.biz-states h4 { margin: 0 0 4px; font: 600 11.5px/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--blue); }
.biz-states h4 .ico { width: 13px; height: 13px; margin-inline-end: 6px; vertical-align: -2px; }
.biz-states ul { margin: 0; padding: 0; list-style: none; }
.biz-states li { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 2px 0; font-size: 13px; }
.biz-states li span { color: var(--grey); }
.biz-states li b { font-weight: 600; text-align: end; }
.map-panel .ctas { margin-top: 16px; gap: 10px 18px; }
.map-panel .btn { height: 44px; padding: 0 18px; font-size: 14px; }
.map-tip { position: absolute; z-index: 5; min-width: 140px; max-width: 250px; padding: 9px 12px 10px; background: #fff; border: 1px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); font: 400 13.5px/1.35 var(--sans); color: var(--ink); transform: translate(-50%, calc(-100% - 14px)); pointer-events: none; }
.map-tip b { display: block; margin-bottom: 3px; font: 600 11px/1.3 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--blue); }
.map-tip[hidden] { display: none; }

/* ---------- every site a click away (1 Nov 26): the map plays like a game map ---------- */
/* a hint on the full map, out over the South China Sea; gone after the first flight */
.map-hint { position: absolute; z-index: 4; left: 44.8%; top: 16.67%; display: inline-flex; align-items: center; gap: 9px; margin: 0; padding: 9px 16px 9px 12px; background: #fff; border: 1px solid var(--ink); border-radius: 999px; box-shadow: 4px 4px 0 var(--ink); font: 600 13px/1.25 var(--sans); color: var(--ink); white-space: nowrap; pointer-events: none; }
.js .map-hint { animation: hint-in .6s 3.4s var(--ease) both; }
.map-hint .ico, .mp-pick .ico { width: 18px; height: 18px; flex: none; color: var(--blue); animation: tap 1.8s 4.2s ease-in-out infinite; }
.played .map-hint { display: none; }
@keyframes hint-in { from { opacity: 0; transform: translateY(8px) scale(.96); } }
@keyframes tap { 0%, 55%, 100% { transform: none; } 25% { transform: translate(1px, 3px) scale(.86); } }
/* pins: they swell under the pointer; the site in view ripples, the ones already seen stay blue */
.map .grow { transition: scale .25s var(--ease); }
.map .pin:is(:hover, :focus-visible) .grow { scale: 1.3; }
.map .pin.small:is(:hover, :focus-visible) .grow { scale: 1; }
.map .pin:focus { outline: none; }
.map .pin:focus-visible .ring { stroke: var(--blue); stroke-width: 3; }
.map .ping { fill: none; stroke: var(--blue); stroke-width: 2; opacity: 0; pointer-events: none; }
.map .pin.here .ping { animation: ping 1.6s ease-out infinite; }
.map .pin.here .ring { fill: var(--blue); stroke: var(--blue); }
.map .pin.here .dot { fill: #fff; }
.map .pin.seen:not(.here) .ring { stroke: var(--blue); }
.map .pin.seen:not(.here) .dot { fill: var(--blue); }
.map .pin.lit .ring { stroke: var(--blue); stroke-width: 2.6; }
@keyframes ping { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(3.2); } }
/* close in (.deep), the pins and names that would crowd the full map come out */
.map .pin.zoom-only, .map .city.near { display: none; }
.deep .map .pin.zoom-only, .map .pin:is(.lit, .here) { display: inline; }
.deep .map .pin.zoom-only .grow, .map .pin.zoom-only:is(.lit, .here) .grow { animation: pin-in .6s var(--ease) .45s both; }
.deep .map .city.near { display: inline; opacity: 1; animation: appear .5s .5s both; }
/* a name the frame cuts, the panel covers or the Back button sits on fades once the map has landed (site.js) */
.map .city { transition: fill-opacity .35s, stroke-opacity .35s; }
.map .city.out { fill-opacity: 0; stroke-opacity: 0; }
@keyframes appear { from { opacity: 0; } }
/* the way from one site to the next: a dotted hop with a marker running along it */
.map .hops path { fill: none; stroke: var(--blue); stroke-width: calc(2.6px / var(--k, 1)); stroke-linecap: round; stroke-dasharray: 0 calc(8px / var(--k, 1)); animation: hop-line 2.8s ease-out both; }
.map .hop-dot { animation: hop-dot 1.4s both; }
.map .hop-dot circle { fill: var(--blue); stroke: #fff; stroke-width: 2; transform: scale(calc(1 / var(--k, 1))); }
@keyframes hop-line { 0% { opacity: 0; } 10%, 60% { opacity: .9; } 100% { opacity: 0; } }
@keyframes hop-dot { 0%, 75% { opacity: 1; } 100% { opacity: 0; } }

/* a country's panel: the score line, then its sites to pick (Malaysia by state) */
.hud { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); margin: 0 0 16px; border-top: 1px solid var(--ink); border-bottom: 1px solid var(--rule); }
.hud p { margin: 0; padding: 10px 0 9px; }
.hud p + p { padding-inline-start: 14px; border-inline-start: 1px solid var(--rule); }
.hud strong { display: block; font: 300 30px/1 var(--serif); letter-spacing: -.02em; font-variant-numeric: lining-nums tabular-nums; }
.hud span { display: block; margin-top: 5px; font: 600 10.5px/1.25 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--grey); }
.mp-pick { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font: 600 13px/1.3 var(--sans); color: var(--blue); }
.mp-pick .ico { width: 17px; height: 17px; animation-delay: .6s; }
.mp-sites { display: grid; gap: 7px; margin: 0; padding: 0; list-style: none; }
.site-btn { display: grid; grid-template-columns: 48px minmax(0, 1fr) auto; align-items: center; gap: 12px; width: 100%; padding: 5px 10px 5px 5px; border: 1px solid var(--rule-2); background: #fff; color: var(--ink); text-align: start; cursor: pointer; transition: transform .15s var(--ease), box-shadow .15s var(--ease), border-color .15s; }
.site-btn > img, .sb-pic { width: 48px; height: 48px; object-fit: cover; background: var(--wash); }
.sb-pic { display: grid; place-items: center; color: var(--blue); }
.sb-pic .ico { width: 20px; height: 20px; }
.sb-t b { display: block; font-size: 14px; font-weight: 600; line-height: 1.25; }
.sb-t small { display: block; margin-top: 2px; color: var(--grey); font-size: 12px; line-height: 1.35; }
.sb-n { display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px 4px 7px; border-radius: 999px; background: var(--wash); color: var(--blue); font: 600 12px/1 var(--sans); }
.sb-n .ico { width: 12px; height: 12px; }
.sb-n.v .ico { fill: currentColor; }
.site-btn:hover { border-color: var(--ink); box-shadow: 3px 3px 0 var(--ink); transform: translate(-2px, -2px); }
.site-btn:active { box-shadow: none; transform: translate(1px, 1px); }
.mp-h { margin: 20px 0 2px; font: 600 11.5px/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--blue); }
.mp-states { display: grid; gap: 16px; }
.mp-state h4 { margin: 0 0 7px; }
.st-btn { display: flex; align-items: center; gap: 7px; width: 100%; padding: 2px 0; border: 0; background: none; font: 600 11.5px/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--blue); text-align: start; cursor: zoom-in; }
.st-btn .ico { width: 13px; height: 13px; }
.st-btn i { min-width: 22px; margin-inline-start: auto; padding: 3px 7px; border-radius: 999px; background: var(--wash); font: normal 600 11px/1 var(--sans); letter-spacing: 0; text-align: center; transition: background .2s, color .2s; }
.st-btn:hover span { text-decoration: underline; text-underline-offset: 3px; }
.mp-state.on .st-btn i { background: var(--blue); color: #fff; }
.mp-state.on .site-btn { border-color: var(--blue); }

/* a site's view: where it is, what it is, its photos and clips, and the way on */
.map-panel.site-view { width: min(420px, 36%); }
.sv-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: -6px 0 12px; }
.sv-up { display: inline-flex; align-items: center; gap: 6px; min-width: 0; height: 34px; padding: 0 13px 0 9px; border: 1px solid var(--ink); border-radius: 999px; background: #fff; color: var(--ink); font: 600 13px/1 var(--sans); cursor: pointer; transition: background .15s, color .15s; }
.sv-up:hover { background: var(--ink); color: #fff; }
.sv-up .ico { width: 16px; height: 16px; }
.sv-step { display: inline-flex; align-items: center; gap: 4px; }
.sv-step button { display: grid; place-items: center; width: 34px; height: 34px; padding: 0; border: 1px solid var(--ink); border-radius: 50%; background: #fff; color: var(--ink); box-shadow: 2px 2px 0 var(--ink); cursor: pointer; transition: transform .12s, box-shadow .12s, background .15s, color .15s; }
.sv-step button:hover { background: var(--ink); color: #fff; }
.sv-step button:active { box-shadow: none; transform: translate(2px, 2px); }
.sv-step .ico { width: 18px; height: 18px; }
.sv-n { min-width: 56px; font: 600 12px/1 var(--sans); letter-spacing: .1em; text-align: center; font-variant-numeric: tabular-nums; }
[dir="rtl"] :is(.sv-up, .sv-step, .lightbox) .ico { transform: scaleX(-1); }
.sv-body > * { animation: sv-in .45s var(--ease) both; }
.sv-body > :nth-child(2) { animation-delay: .04s; }
.sv-body > :nth-child(3) { animation-delay: .08s; }
.sv-body > :nth-child(4) { animation-delay: .12s; }
.sv-body > :nth-child(n + 5) { animation-delay: .16s; }
@keyframes sv-in { from { opacity: 0; transform: translateY(10px); } }
.sv-body .label .ico { width: 13px; height: 13px; margin-inline-end: 6px; vertical-align: -2px; }
.sv-body h3 { margin: 7px 0 3px; font: 500 26px/1.15 var(--serif); letter-spacing: -.02em; }
.sv-sub { margin: 0; color: var(--grey); font-size: 14px; line-height: 1.45; }
.sv-meta { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 14px; padding: 0; list-style: none; }
.sv-meta li { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px 5px 9px; border: 1px solid var(--rule-2); border-radius: 999px; font-size: 12.5px; font-weight: 600; line-height: 1.2; }
.sv-meta .ico { width: 14px; height: 14px; color: var(--blue); }
/* the big picture, framed like one of the screens, over a blur of itself */
.sv-main { position: relative; display: block; width: 100%; aspect-ratio: 4 / 3; padding: 0; overflow: hidden; border: 6px solid var(--ink); border-radius: 10px; background: var(--ink); cursor: zoom-in; isolation: isolate; box-shadow: 0 18px 30px -18px rgba(25, 40, 83, .5); }
.sv-main::before { content: ""; position: absolute; inset: -30px; z-index: -1; background: var(--bg, none) center / cover; filter: blur(18px) saturate(1.1); opacity: .55; }
.sv-pic { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; animation: pic-in .5s var(--ease) both; }
@keyframes pic-in { from { opacity: 0; transform: scale(1.05); } }
.sv-zoom { position: absolute; z-index: 2; top: 8px; inset-inline-end: 8px; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: rgba(255, 255, 255, .92); color: var(--ink); transition: transform .2s var(--ease); }
.sv-main:hover .sv-zoom { transform: scale(1.12); }
.sv-zoom .ico { width: 15px; height: 15px; }
.sv-cap { position: absolute; z-index: 2; inset-inline: 0; bottom: 0; padding: 22px 12px 8px; background: linear-gradient(rgba(14, 24, 53, 0), rgba(14, 24, 53, .82)); color: #fff; font-size: 12.5px; line-height: 1.35; text-align: start; }
.sv-cap:empty { display: none; }
.sv-thumbs { display: flex; gap: 6px; margin: 8px 0 0; padding: 2px 2px 6px; list-style: none; overflow-x: auto; scrollbar-width: thin; }
.sv-thumbs[hidden] { display: none; }
.th { position: relative; display: block; flex: none; width: 56px; height: 56px; padding: 0; border: 2px solid transparent; background: var(--wash); cursor: pointer; transition: transform .15s var(--ease), border-color .15s; }
.th img { display: block; width: 100%; height: 100%; object-fit: cover; }
.th .ico { position: absolute; inset: 0; width: 20px; height: 20px; margin: auto; color: #fff; fill: #fff; filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .55)); }
.th:hover { transform: translateY(-2px); }
.th[aria-pressed="true"] { border-color: var(--ink); }
.sv-none { display: flex; align-items: flex-start; gap: 10px; margin: 2px 0 0; padding: 16px; border: 1px dashed var(--rule-2); color: var(--grey); font-size: 14px; line-height: 1.5; }
.sv-none .ico { width: 20px; height: 20px; flex: none; color: var(--blue); }
.sv-here { margin-top: 14px; }
.sv-here[hidden] { display: none; }
.sv-here .label { display: block; margin-bottom: 7px; }
.sv-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip-btn { padding: 6px 12px; border: 1px solid var(--rule-2); border-radius: 999px; background: #fff; color: var(--ink); font: 600 12.5px/1.2 var(--sans); cursor: pointer; transition: border-color .15s, background .15s, color .15s; }
.chip-btn:hover { border-color: var(--ink); }
.chip-btn[aria-current] { border-color: var(--ink); background: var(--ink); color: #fff; }
.map-panel :is(.site-btn, .st-btn, .sv-up, .sv-step button, .th, .sv-main, .chip-btn):focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
/* a photo or clip over the page, at full size */
html:has(.lightbox[open]) { overflow: hidden; }
.lightbox { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: transparent; color: #fff; overflow: hidden; }
.lightbox[open] { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; animation: appear .3s var(--ease); }
.lightbox::backdrop { background: rgba(14, 24, 53, .94); }
.lb-pic { display: grid; place-items: center; }
.lb-pic .sv-pic { position: static; width: auto; height: auto; max-width: calc(100vw - 160px); max-height: calc(100vh - 150px); max-height: calc(100dvh - 150px); }
.lb-cap { margin: 0; padding: 0 24px; font-size: 14px; line-height: 1.4; text-align: center; }
.lb-n { margin-inline-end: 12px; font-weight: 600; letter-spacing: .12em; }
.lb-n:empty { display: none; }
.lightbox button { position: absolute; display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border: 1px solid rgba(255, 255, 255, .45); border-radius: 50%; background: rgba(255, 255, 255, .08); color: #fff; cursor: pointer; transition: background .15s, color .15s; }
.lightbox button:hover { background: #fff; color: var(--ink); }
.lightbox button .ico { width: 22px; height: 22px; }
.lb-x { top: 16px; inset-inline-end: 16px; }
.lb-prev, .lb-next { top: calc(50% - 24px); }
.lb-prev { inset-inline-start: 16px; }
.lb-next { inset-inline-end: 16px; }
.lightbox.one :is(.lb-prev, .lb-next) { display: none; }
/* a site's details, once GAFAS sends them (tools/map-sites.mjs, specs) */
.sv-specs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; margin: 0 0 14px; background: var(--rule); border: 1px solid var(--rule); }
.sv-specs div { padding: 8px 10px; background: #fff; }
.sv-specs dt { font: 600 10.5px/1.25 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--grey); }
.sv-specs dd { margin: 3px 0 0; font-size: 13.5px; font-weight: 600; line-height: 1.3; }
/* the visitor's proposal list (1 Nov 26): the add button on a site's view, the button that holds the list, the list */
.site-view .ctas { gap: 10px; }
.site-view .ctas .btn { flex: 1 1 auto; }
.sv-pick span { display: inline-flex; align-items: center; gap: 8px; }
.sv-pick .pk-yes, .sv-pick[aria-pressed="true"] .pk-no { display: none; }
.sv-pick[aria-pressed="true"] .pk-yes { display: inline-flex; }
.sv-pick[aria-pressed="true"] { background: var(--blue); }
.map .pin.picked .ring { fill: var(--blue); stroke: var(--ink); }
.map .pin.picked .dot { fill: #fff; }
.picks-btn { position: relative; z-index: 30; pointer-events: auto; display: inline-flex; align-items: center; gap: 10px; height: 42px; padding: 0 8px 0 16px; border: 1px solid var(--ink); border-radius: 999px; background: #fff; color: var(--ink); box-shadow: 4px 4px 0 var(--ink); font: 600 14px/1 var(--sans); cursor: pointer; animation: tray-in .5s var(--ease) both; transition: transform .15s var(--ease), box-shadow .15s var(--ease); }
.picks-btn[hidden] { display: none; }
.picks-btn .ico { width: 19px; height: 19px; color: var(--blue); }
.picks-n { display: grid; place-items: center; min-width: 26px; height: 26px; padding: 0 6px; border-radius: 999px; background: var(--blue); color: #fff; font: 700 13px/1 var(--sans); }
.picks-btn:hover { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--ink); }
.picks-btn:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.picks-btn.bump .picks-n { animation: bump .5s var(--ease); }
@keyframes tray-in { from { opacity: 0; transform: translateY(16px) scale(.9); } }
@keyframes bump { 40% { transform: scale(1.45); } }
.fling { position: fixed; z-index: 80; object-fit: cover; border: 3px solid #fff; border-radius: 8px; box-shadow: 0 10px 24px rgba(25, 40, 83, .35); pointer-events: none; }
html:has(.picks[open]) { overflow: hidden; }
.picks { width: min(460px, calc(100vw - 32px)); max-height: min(640px, calc(100vh - 48px)); padding: 26px 24px 24px; border: 1px solid var(--ink); background: #fff; color: var(--ink); box-shadow: 8px 8px 0 var(--ink); overflow: auto; }
.picks[open] { animation: sv-in .35s var(--ease); }
.picks::backdrop { background: rgba(14, 24, 53, .55); }
.picks h3 { margin: 8px 0 6px; font: 500 26px/1.15 var(--serif); letter-spacing: -.02em; }
.picks > p { margin: 0 0 16px; color: var(--grey); font-size: 14px; line-height: 1.5; }
.picks-x { position: absolute; top: 14px; inset-inline-end: 14px; display: grid; place-items: center; width: 36px; height: 36px; padding: 0; border: 1px solid var(--rule-2); border-radius: 50%; background: #fff; color: var(--ink); cursor: pointer; }
.picks-x .ico { width: 18px; height: 18px; }
.picks-list { display: grid; gap: 8px; margin: 0 0 18px; padding: 0; list-style: none; }
.picks-list li { display: flex; align-items: center; gap: 6px; }
.pk-go { flex: 1; min-width: 0; display: grid; grid-template-columns: 44px minmax(0, 1fr); align-items: center; gap: 12px; padding: 5px 10px 5px 5px; border: 1px solid var(--rule-2); background: #fff; color: var(--ink); text-align: start; cursor: pointer; transition: border-color .15s; }
.pk-go:hover { border-color: var(--ink); }
.pk-pic { display: block; width: 44px; height: 44px; overflow: hidden; background: var(--wash); }
.pk-pic img { display: block; width: 100%; height: 100%; object-fit: cover; }
.pk-go b { display: block; font-size: 14px; line-height: 1.25; }
.pk-go small { display: block; margin-top: 2px; color: var(--grey); font-size: 12px; line-height: 1.3; }
.pk-x { flex: none; display: grid; place-items: center; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--grey); cursor: pointer; }
.pk-x:hover { background: var(--wash); color: var(--ink); }
.pk-x .ico { width: 16px; height: 16px; }
.picks .ctas { gap: 12px 20px; }
.picks-clear { padding: 0; border: 0; background: none; color: var(--grey); font: 600 14px/1 var(--sans); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
:is(.picks-btn, .picks-x, .pk-go, .pk-x, .picks-clear):focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* drawing it: coast first, then the hatching, the landmarks, the pins and the routes out from Johor Bahru */
@keyframes pen { to { stroke-dashoffset: 0; } }
@keyframes fade-in { to { opacity: 1; } }
@keyframes pin-in { from { transform: scale(0); } 70% { transform: scale(1.2); } to { transform: scale(1); } }
.js .map :is(.side path, .land .ink, .land .pencil, .lm path, .routes path, .rose circle, .rose path) { stroke-dasharray: 1 1; stroke-dashoffset: 1; }
/* down the page on Media Campaign, the map waits to draw itself until it comes into view (site.js adds .in) */
.js .map-box:not(.in) :is(.map *, .map-hint, .map-hint .ico) { animation-play-state: paused; }
.js .map .side path { animation: pen 2.6s var(--ease) .25s forwards; }
.js .map .land .ink { animation: pen 2.4s cubic-bezier(.45, .05, .25, 1) calc(.15s + var(--i, 0) * .04s) forwards; }
.js .map .land.id .ink { animation-delay: calc(.5s + var(--i, 0) * .04s); }
.js .map .land .pencil { animation: pen 2.6s ease-out calc(.7s + var(--i, 0) * .04s) forwards; }
.js .map :is(.hatch, .grat, .names, .city, .rose text, .trip) { opacity: 0; }
.js .map .grat { animation: fade-in 1.2s .1s forwards; }
.js .map .hatch { animation: fade-in 1.4s 1.1s forwards; }
.js .map .rose :is(circle, path) { animation: pen 1.6s var(--ease) .5s forwards; }
.js .map .rose text { animation: fade-in .8s 1.6s forwards; }
.js .map .lm path { animation: pen 1.8s var(--ease) calc(1.3s + var(--i, 0) * .3s) forwards; }
.js .map .lm .fine { animation-delay: calc(1.9s + var(--i, 0) * .3s); }
.js .map .names { animation: fade-in 1.2s 1.7s forwards; }
.js .map .grow { transform: scale(0); animation: pin-in .7s var(--ease) calc(2s + var(--i, 0) * .06s) forwards; }
.js .map .city { animation: fade-in .8s calc(2.4s + var(--i, 0) * .06s) forwards; }
.js .map .routes path { animation: pen 1.3s var(--ease) calc(2.3s + var(--i, 0) * .08s) forwards; }
.js .map .trip { animation: fade-in .4s var(--d, 3.2s) forwards; }

/* a client's profile beside its campaign (Proposal page, the buses) */
.client-card { display: grid; grid-template-columns: 220px 1fr auto; gap: 10px 48px; align-items: baseline; margin: -8px 0 34px; padding: 20px 0; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.client-card .label .ico { width: 14px; height: 14px; margin-inline-end: 6px; vertical-align: -2px; }
.client-card b { display: block; margin-bottom: 6px; font: 500 22px/1.2 var(--serif); }
.client-card p { margin: 0; max-width: 640px; color: var(--grey); font-size: 15px; }
@media (max-width: 1000px) { .client-card { grid-template-columns: minmax(0, 1fr); } }

/* Lucide icons (1 Nov 26): line icons in the text colour, sized for where they sit */
.ico { display: inline-block; flex: none; width: 1.1em; height: 1.1em; vertical-align: -.18em; }
:is(.rows, .meta) dt .ico { width: 15px; height: 15px; margin-inline-end: 7px; vertical-align: -3px; color: var(--blue); }
:is(.menu, .fmt, .places) h3 .ico { width: .8em; height: .8em; margin-inline-end: .34em; vertical-align: -.05em; color: var(--blue); stroke-width: 1.6; }
.card-top .ico { width: 44px; height: 44px; color: var(--blue); stroke-width: 1.4; }
.steps div { position: relative; }
.steps div > .ico { position: absolute; top: 34px; inset-inline-end: 28px; width: 34px; height: 34px; color: var(--blue); stroke-width: 1.5; }
:is(.facts, .ledger) div > .ico { display: block; width: 22px; height: 22px; margin-bottom: 10px; color: var(--blue); }
:is(.site-cap, .credits) span .ico { width: 13px; height: 13px; margin-inline-end: 5px; vertical-align: -2px; color: var(--blue); }
.btn .ico { width: 18px; height: 18px; }
.field > span .ico { width: 14px; height: 14px; margin-inline-end: 6px; vertical-align: -2px; color: var(--blue); }
.chip span .ico { width: 15px; height: 15px; margin-inline-end: 7px; }
:is(.ft-col, .sheet-foot) :is(a, p) .ico, .toc a .ico { width: 15px; height: 15px; margin-inline-end: 8px; vertical-align: -3px; color: var(--blue); }
.phone-big .ico { width: .62em; height: .62em; margin-inline-end: .3em; vertical-align: -.02em; color: var(--blue); }
.job h4 .ico { width: 17px; height: 17px; margin-inline-end: 8px; vertical-align: -3px; }
.job li .ico { width: 15px; height: 15px; margin-inline-end: 9px; vertical-align: -2px; color: var(--blue); }
.band .ico { color: inherit; }

/* client logos (5 Nov 26, Dave "要，重做"): a file a brand from tools/make-logos.py, each about the same area, in rows
   that wrap; grey until the pointer is on one, as on the old board. Golds and yellows grey out pale, so the ones the
   script marks "pale" are darkened a little while grey. Phones get the whole wall at 72%. */
/* The client logos drift sideways in three rows (9 Nov 26, Dave: "logo 做animation 不要全部挤在一起"; was one block of
   every logo). tools/make-logos.py writes each row twice in a row inside .rail-move, which slides by half its width, so
   the loop has no seam; --dur follows the row's width so all rows move at the same speed. A row stops under the pointer;
   with reduced motion the rows stand still and wrap. */
.logo-wall { display: grid; gap: clamp(22px, 3vw, 34px); margin: 0 auto clamp(48px, 6vw, 80px); overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.rail { overflow: hidden; }
.rail-move { display: flex; width: max-content; animation: crawl var(--dur, 90s) linear infinite; }
.rail:nth-child(2) .rail-move { animation-direction: reverse; }
.rail:hover .rail-move { animation-play-state: paused; }
.rail-track { display: flex; align-items: center; gap: 64px; margin: 0; padding: 0; padding-inline-end: 64px; list-style: none; }
.rail-track li { flex: none; display: flex; align-items: center; justify-content: center; min-height: 66px; }
/* each logo in its own colours (9 Nov 26, Dave: "logo 不要灰色挡住了"; they were grey and faded until hovered) */
.logo-wall img { display: block; height: auto; }
[dir="rtl"] .rail-move { animation-name: crawl-rtl; }
@media (prefers-reduced-motion: reduce) {
  .logo-wall { -webkit-mask-image: none; mask-image: none; }
  .rail-move { width: auto; animation: none; }
  .rail-track { flex-wrap: wrap; justify-content: center; gap: 28px 48px; padding: 0; }
  .rail-track[aria-hidden] { display: none; }
}
@media (max-width: 640px) { .logo-wall { zoom: .72; gap: 26px; } }

/* ---------- the screen: a digital totem that plays its clips in turn, like a slot on a real loop ---------- */
.screen { position: relative; justify-self: center; width: min(100%, 380px); margin: 0; }
.screen .bezel { position: relative; aspect-ratio: 9 / 15.6; border-radius: 16px; background: var(--ink); padding: 10px; box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 50px 80px -40px rgba(25, 40, 83, .55), 0 18px 30px -18px rgba(25, 40, 83, .4); }
.screen .glass { position: relative; height: 100%; border-radius: 8px; overflow: hidden; background: #0e1835; }
.screen .glass video, .screen .glass img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.screen [data-slot] { opacity: 0; transition: opacity 1s var(--ease); }
.screen [data-slot].on { opacity: 1; }
/* a finger slides the clips sideways (site.js, 10 Nov 26); up and down still scroll the page */
.screen[data-loop] .glass { touch-action: pan-y; -webkit-user-select: none; user-select: none; }
.screen .glass::after { content: ""; position: absolute; inset: 0; z-index: 2; background: linear-gradient(115deg, rgba(255, 255, 255, .16) 0%, rgba(255, 255, 255, 0) 32%); pointer-events: none; }
.screen .slot { position: absolute; z-index: 3; right: 10px; top: 10px; padding: 6px 8px 5px; border-radius: 3px; background: rgba(25, 40, 83, .6); color: #fff; font: 600 10.5px/1 var(--sans); letter-spacing: .14em; }
.screen .bar { position: absolute; z-index: 3; left: 12px; right: 12px; bottom: 12px; height: 2px; background: rgba(255, 255, 255, .3); }
.screen .bar i { display: block; height: 100%; background: #fff; transform: scaleX(0); transform-origin: left; }
.screen .foot { width: 46%; height: 26px; margin: 0 auto; background: var(--ink); border-radius: 0 0 6px 6px; box-shadow: inset 0 8px 10px -6px rgba(0, 0, 0, .35); }
.screen .shadow { width: 80%; height: 16px; margin: 6px auto 0; background: radial-gradient(closest-side, rgba(25, 40, 83, .28), transparent); }
.screen figcaption { margin-top: 14px; font: italic 400 15px/1.45 var(--sans); color: var(--grey); text-align: center; }
.screen .tag { position: absolute; z-index: 4; top: 26px; left: -22px; display: inline-flex; align-items: center; gap: 8px; padding: 9px 12px 9px 10px; background: #fff; border: 1px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); font: 600 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; transform: rotate(-4deg); }
.screen .tag i { width: 7px; height: 7px; border-radius: 50%; background: var(--blue); animation: blink 1.6s ease-in-out infinite; }
@keyframes blink { 50% { opacity: .2; } }
/* landscape version: a roadside screen */
.screen.wide { width: 100%; justify-self: stretch; }
.screen.wide .bezel { aspect-ratio: 16 / 8.2; border-radius: 12px; padding: 9px; }
.screen.wide .glass { border-radius: 6px; }
.screen.wide .tag { left: -12px; top: 22px; }
.screen.wide .foot { width: 18%; height: 34px; }

/* ---------- sections ---------- */
.sec { padding: clamp(80px, 9vw, 130px) 0; }
.sec.tight { padding-top: 0; }
.sec.near { padding-top: clamp(16px, 2vw, 28px); }
main > .sec:last-child { padding-bottom: 0; }
.sec-head { position: relative; display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 24px 48px; padding-top: 22px; margin-bottom: 40px; }
.sec-head h2 { font: 400 clamp(40px, 5vw, 72px)/1 var(--serif); letter-spacing: -.03em; margin: 0; max-width: 14em; }
.sec-head h2 em { color: var(--blue); }
/* (9 Nov 26 review: "Brands that have run with / us.", the home lead's "Singapore" alone on a phone) */
:is(h1, h2, h3, h4) { text-wrap: balance; }
:is(p, li, dd, figcaption) { text-wrap: pretty; }
.band .sec-head h2 em { color: rgba(255, 255, 255, .62); }   /* the logo blue is lost on the navy band */
.sec-head p { grid-column: 2; margin: 0; color: var(--grey); max-width: 640px; }

/* home: the seven formats */
.menu { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule-2); }
.menu li { position: relative; display: grid; grid-template-columns: 220px 1.1fr 1.4fr 170px; gap: 48px; align-items: baseline; padding: 26px 0 24px; border-bottom: 1px solid var(--rule); transition: background .3s var(--ease); }
.menu li:hover { background: linear-gradient(90deg, var(--wash), rgba(12, 88, 147, 0)); }
.menu .n { font: 300 44px/1 var(--serif); color: var(--blue); }
.menu h3 { font: 400 clamp(22px, 2.1vw, 30px)/1.1 var(--serif); letter-spacing: -.02em; margin: 0; }
.menu h3 a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.menu p { margin: 0; color: var(--grey); font-size: 16px; }
.menu .where { justify-self: end; text-align: end; }
/* a country heading inside the list (1 Nov 26: the media of all three countries, not Singapore alone) */
.menu .menu-c { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 30px 0 12px; border-bottom: 1px solid var(--ink); }
.menu .menu-c:first-child { padding-top: 18px; }
.menu .menu-c:hover { background: none; }
.menu .menu-c .label.blue .ico { width: 14px; height: 14px; margin-inline-end: 7px; vertical-align: -2px; }
/* the photo follows the pointer along the row (site.js sets --mx / --my) */
.menu .thumb { position: absolute; left: var(--mx, 64%); top: var(--my, 50%); z-index: 2; width: 150px; aspect-ratio: 3 / 4; object-fit: cover; border: 5px solid #fff; box-shadow: 0 20px 40px -20px rgba(25, 40, 83, .6); opacity: 0; transform: translate(28px, -50%) rotate(3deg) scale(.9); transition: opacity .35s var(--ease), transform .35s var(--ease), left .3s var(--ease), top .3s var(--ease); pointer-events: none; }
.menu li:hover .thumb { opacity: 1; transform: translate(28px, -50%) rotate(3deg) scale(1); }
.also { margin: 28px 0 0; font: italic 400 clamp(19px, 1.6vw, 22px)/1.5 var(--sans); color: var(--grey); }
.also a { color: var(--ink); border-bottom: 1px solid var(--rule-2); transition: border-color .2s, color .2s; }
.also a:hover { color: var(--blue); border-color: var(--blue); }

/* navy band (the only coloured background; the logo never sits on it) */
.band { background: var(--ink); color: #fff; }
.band .label, .band .label.blue { color: rgba(255, 255, 255, .7); }
.band .sec-head::before { background: #fff; }
.band .sec-head p, .band .body p { color: rgba(255, 255, 255, .78); }
.band .arrow-link { border-color: rgba(255, 255, 255, .45); }
.band .btn { background: #fff; color: var(--ink); }
.band .btn:hover { background: rgba(255, 255, 255, .86); }
.spread-grid { display: grid; grid-template-columns: 5fr 7fr; gap: clamp(36px, 5vw, 80px); align-items: start; }
.spread h2 { font: 400 clamp(34px, 3.7vw, 54px)/1.05 var(--serif); letter-spacing: -.025em; margin: 18px 0 26px; }
.pull { margin: 34px 0; padding: 22px 0; border-top: 1px solid currentColor; border-bottom: 1px solid currentColor; font: italic 400 clamp(24px, 2.2vw, 30px)/1.3 var(--sans); }
.band .pull { color: #fff; }
.placements { margin: 0 0 34px; padding: 0; list-style: none; font-size: 15.5px; }
.placements li { display: flex; justify-content: space-between; gap: 18px; padding: 11px 0; border-bottom: 1px dotted rgba(255, 255, 255, .32); }
.placements li span:last-child { color: rgba(255, 255, 255, .72); text-align: end; }
.mosaic { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-rows: 230px 230px 210px; gap: 14px; }
.mosaic figure, .gallery figure, .fmt-pic { position: relative; margin: 0; overflow: hidden; background: var(--wash); }
/* 1 Nov 26, Dave: "网站记得做防盗 保护好我们辛辛苦苦得来的资源". The photos and clips are GAFAS's own: a small GAFAS
   mark sits in a top corner of each, so a screenshot still says whose they are; they cannot be dragged out or saved with
   a long press on a phone, and site.js turns off the save menu. It slows a casual copy, not a determined one. */
img, video { -webkit-user-drag: none; user-select: none; -webkit-touch-callout: none; }
:is(.mosaic figure, .gallery figure, .fmt-pic, .photo-row figure, .duo, .sv-main, .lb-pic, .case figure)::after {
  content: ""; position: absolute; z-index: 2; top: 10px; inset-inline-end: 10px; width: 44px; aspect-ratio: 2310 / 1170;
  background: url(watermark.svg) center / contain no-repeat; opacity: .78; filter: drop-shadow(0 1px 2px rgba(10, 20, 45, .55));
  pointer-events: none;
}
.sv-main::after { inset-inline-end: auto; inset-inline-start: 10px; }       /* its zoom button has the other corner */
.lb-pic { position: relative; }
.lb-pic::after { top: 14px; inset-inline-end: 14px; width: 64px; }
.band .mosaic figure { background: rgba(255, 255, 255, .06); }
.mosaic img, .gallery img, .gallery video { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease); }
.mosaic figure:hover img, .gallery figure:hover img { transform: scale(1.04); }
.mosaic figcaption, .gallery figcaption, .fmt-pic figcaption { position: absolute; inset-inline-start: 0; bottom: 0; max-width: 85%; padding: 6px 10px 5px; background: #fff; color: var(--ink); font: italic 400 13.5px/1.3 var(--sans); }
.m1 { grid-column: 1 / 3; grid-row: 1 / 3; }
.m2 { grid-column: 3 / 7; grid-row: 1 / 2; }
.m3 { grid-column: 3 / 5; grid-row: 2 / 4; }
.m4 { grid-column: 5 / 7; grid-row: 2 / 4; }
.m5 { grid-column: 1 / 3; grid-row: 3 / 4; }

/* the eight platforms (2 Nov 26): icon, number and name on a ruled 4 x 2 board */
.platforms { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule-2); }
.platforms li { display: flex; flex-direction: column; gap: 22px; padding-block: 26px 28px; padding-inline: 0 24px; border-bottom: 1px solid var(--rule); transition: background .3s; }
.platforms li:not(:nth-child(4n + 1)) { padding-inline-start: 24px; border-inline-start: 1px solid var(--rule); }
.platforms li:hover { background: linear-gradient(180deg, var(--wash), rgba(12, 88, 147, 0)); }
.pf-top { display: flex; justify-content: space-between; align-items: flex-start; }
.pf-top .ico { width: 40px; height: 40px; color: var(--blue); stroke-width: 1.4; }
.pf-top i { font: 300 15px/1 var(--serif); font-style: normal; letter-spacing: .06em; color: var(--grey); }
.platforms b { font: 400 clamp(20px, 1.8vw, 25px)/1.2 var(--serif); letter-spacing: -.01em; }

/* the client's case studies (2 Nov 26): three campaigns, a clip each, on the navy band; four in one row from 5 Nov 26
   (Borneo Jazz, Ito: "Ltak je kat case studies") */
.cases { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(20px, 2.6vw, 36px); }
.case figure { position: relative; margin: 0 0 20px; aspect-ratio: 4 / 3; overflow: hidden; background: rgba(255, 255, 255, .06); }
.case video { display: block; width: 100%; height: 100%; object-fit: cover; }
.case .label .ico { width: 14px; height: 14px; margin-inline-end: 7px; vertical-align: -2px; }
/* a size smaller since there are four in a row (5 Nov 26): at 34 px "Tourism Sarawak" took two lines in a 271 px card */
.case h3 { margin: 10px 0; font: 400 clamp(24px, 2.1vw, 30px)/1.1 var(--serif); letter-spacing: -.02em; }
.case p { margin: 0; color: rgba(255, 255, 255, .78); }
/* a case on the home page opens its part of Media Campaigns (9 Nov 26 review): its name is the link, and the whole card
   answers to it */
.case { position: relative; }
.case-link { color: inherit; text-decoration: underline; text-decoration-color: transparent; text-decoration-thickness: 1px; text-underline-offset: 6px; transition: text-decoration-color .2s; }
.case-link::after { content: ""; position: absolute; inset: 0; z-index: 2; }
.case:hover .case-link { text-decoration-color: currentColor; }
.case-link:focus-visible { outline: none; }
.case:has(.case-link:focus-visible) { outline: 2px solid currentColor; outline-offset: 8px; }
/* two to a row on Media Campaigns (7 Nov 26: the latest two, Tourism Sarawak and Borneo Jazz), one on a phone */
@media (min-width: 861px) { .cases.two { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* About: Visit us as an address card with an icon (7 Nov 26, Ito's PPT V2: the street name was too big as a heading) */
.visit { display: grid; grid-template-columns: auto 1fr 1fr; gap: 26px clamp(28px, 4vw, 64px); align-items: start; padding: clamp(26px, 3.4vw, 46px); background: var(--wash); border-top: 2px solid var(--ink); }
.visit-badge { display: grid; place-items: center; width: 76px; height: 76px; border-radius: 50%; background: var(--ink); color: #fff; }
.visit-badge .ico { width: 34px; height: 34px; stroke-width: 1.5; }
.visit h2 { margin: 12px 0 10px; font: 400 clamp(28px, 2.6vw, 36px)/1.1 var(--serif); letter-spacing: -.02em; }
.visit-addr { margin: 0; color: var(--grey); font-size: 17px; line-height: 1.6; }
.visit-list { display: grid; gap: 10px; margin: 0 0 14px; padding: 0; list-style: none; font-size: 16px; }
.visit-list li { display: flex; align-items: center; gap: 10px; }
.visit-list .ico { flex: none; width: 18px; height: 18px; color: var(--blue); }
.visit-list a { color: var(--ink); }
.visit-when > p { margin: 0 0 22px; max-width: 34em; color: var(--grey); font-size: 15px; }
@media (max-width: 1000px) { .visit { grid-template-columns: auto minmax(0, 1fr); } .visit-when { grid-column: 2; } }
@media (max-width: 600px) { .visit { grid-template-columns: minmax(0, 1fr); } .visit-when { grid-column: auto; } .visit-badge { width: 60px; height: 60px; } .visit-badge .ico { width: 28px; height: 28px; } }

/* the menu's Facebook, LinkedIn and Instagram on one line (7 Nov 26) */
.sheet-foot .social { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 20px; }

/* clients */
.credits { columns: 3; column-gap: 48px; column-rule: 1px solid var(--rule); margin: 0; padding: 0; list-style: none; }
.credits li { break-inside: avoid; display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--rule); }
.credits b { font: 400 25px/1.2 var(--serif); letter-spacing: -.01em; }
.credits span { font-size: 13.5px; color: var(--grey); text-align: end; }
.credits.long { columns: 2; }
.credits.long li { display: block; }
.credits.long span { display: block; margin-top: 4px; text-align: start; font-size: 14.5px; }

/* numbered steps */
.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--rule-2); }
.steps.four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.steps div { padding-block: 30px 10px; padding-inline: 0 32px; }
.steps div + div { padding-inline-start: 32px; border-inline-start: 1px solid var(--rule); }
.steps i { display: block; margin-bottom: 18px; font: 300 64px/1 var(--serif); color: var(--blue); }
.steps h3 { font: 400 28px/1.15 var(--serif); letter-spacing: -.01em; margin: 0 0 10px; }
.steps p { margin: 0; color: var(--grey); }

/* contact box, set like a classified ad */
.classified { display: grid; grid-template-columns: 1.2fr 1fr; gap: clamp(28px, 5vw, 72px); padding: clamp(28px, 4vw, 56px); border: 3px double var(--ink); background: #fff; }
.classified h2 { font: 400 clamp(40px, 4.6vw, 66px)/1 var(--serif); letter-spacing: -.03em; margin: 16px 0 20px; }
.classified h2 em { color: var(--blue); }
.classified p { color: var(--grey); margin: 0 0 30px; max-width: 520px; }
.phone-big { display: block; margin: 6px 0 26px; font: 300 clamp(38px, 4.2vw, 58px)/1 var(--serif); letter-spacing: -.02em; }   /* wraps only at its space, and only when one line cannot hold it (big text on a small phone) */
.rows { margin: 0; }
.rows div { display: grid; grid-template-columns: 126px minmax(0, 1fr); gap: 16px; padding: 13px 0; border-top: 1px solid var(--rule); font-size: 16px; }
.rows dt { font: 600 11px/1.9 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--grey); }
.rows dd { margin: 0; }
/* a "·" list (What We Do's eight platforms, 10 Nov 26) wraps between its names, so a name is not cut in two
   ("Static / Billboards", "静态广 / 告牌"); one longer than the whole line still wraps inside itself */
.rows .seq > span { display: inline-block; }
/* ...and between the phone and desktop layouts (861-1100 px) the page head's right-hand column is only about 380 px:
   next to the 126 px labels the eight names went one to a line, "Digital Out-of- / Home (DOOH)" cut in two at 1024 px.
   There the labels of that list go over their values, as on a phone, and the names get the whole column. */
@media (min-width: 861px) and (max-width: 1100px) {
  .phead-foot .rows:has(.seq) div { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}
.rows a { border-bottom: 1px solid var(--rule-2); }
.rows a:hover { border-color: var(--ink); }
.rows .maps { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 8px; font-size: 14px; }
.classified.solo { grid-template-columns: minmax(0, 1fr); }
.classified dd { overflow-wrap: break-word; }   /* the Instagram name is one long word: on a small phone it may break rather than run out of the box; an e-mail breaks after its "@" (build-site.mjs adds <wbr>) */
.classified.solo .phone-big { font-size: clamp(34px, 3.3vw, 48px); }

/* ---------- inner pages ---------- */
.phead { padding: clamp(44px, 6vw, 84px) 0 clamp(40px, 5vw, 64px); }
.phead h1 { font: 400 clamp(46px, 7vw, 108px)/.98 var(--serif); letter-spacing: -.035em; margin: 20px 0 0; max-width: 12.5em; }
.phead h1 em { color: var(--blue); }
/* a Chinese word in a headline stays on one line (build-site.mjs wraps them, 9 Nov 26) */
.nw { white-space: nowrap; }
/* a headline three times the usual length (What We Do, Ito 9 Nov 26): smaller, so it reads as a sentence, not a wall */
.phead h1.long { font-size: clamp(28px, 3.7vw, 54px); line-height: 1.1; letter-spacing: -.025em; max-width: 21em; }
.phead-foot { display: grid; grid-template-columns: 1.3fr 1fr; gap: 28px 64px; align-items: start; margin-top: clamp(28px, 3.4vw, 48px); position: relative; padding-top: 22px; }
.deck { margin: 0; max-width: 640px; font: 400 clamp(19px, 1.6vw, 23px)/1.5 var(--serif); color: var(--grey); }
.phead-foot .deck + .ctas { margin-top: 28px; }   /* the button under a page's opening words, not touching them */
.toc { display: grid; border-top: 1px solid var(--rule-2); }
.toc a { display: flex; justify-content: flex-start; align-items: baseline; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--rule); font: 500 15.5px/1.3 var(--sans); transition: color .2s, padding .3s var(--ease); }
.toc a span { margin-inline-start: auto; color: var(--grey); font-size: 13px; }
.toc a:hover { color: var(--blue); padding-inline-start: 6px; }

/* media: one format per spread */
.fmt { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(32px, 5vw, 80px); align-items: center; padding: clamp(36px, 4vw, 56px) 0; border-top: 1px solid var(--rule-2); }
.fmt:nth-of-type(even) .fmt-pic { order: 2; }
.fmt-pic { aspect-ratio: 4 / 3; }
.fmt-pic img, .fmt-pic video { width: 100%; height: 100%; object-fit: cover; }
.fmt-n { display: block; font: 300 56px/1 var(--serif); color: var(--blue); }
.fmt h3 { font: 400 clamp(34px, 3.4vw, 52px)/1.02 var(--serif); letter-spacing: -.025em; margin: 12px 0 16px; }
.fmt p { max-width: 30em; margin: 0 0 24px; color: var(--grey); }
.meta { max-width: 460px; margin: 0; border-bottom: 1px solid var(--rule); }
.meta div { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 16px; padding: 11px 0; border-top: 1px solid var(--rule); font-size: 15.5px; }
.meta dt { font: 600 11px/1.9 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--grey); }
.meta dd { margin: 0; }
.trio { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--rule-2); }
.card { padding-block: 34px 38px; padding-inline: 0 32px; }
.card + .card { padding-inline-start: 32px; border-inline-start: 1px solid var(--rule); }
.card-top { display: flex; justify-content: space-between; align-items: flex-start; }
.card .fmt-n { font-size: 44px; }
.icon { width: 44px; height: 44px; color: var(--blue); fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.card h3 { font: 400 32px/1.08 var(--serif); letter-spacing: -.02em; margin: 22px 0 10px; }
.card p { margin: 0 0 18px; color: var(--grey); }
.places { list-style: none; margin: 0; padding: 0; border-top: 1px solid rgba(255, 255, 255, .45); }
.places li { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 10px 48px; align-items: baseline; padding: 22px 0; border-bottom: 1px solid rgba(255, 255, 255, .16); }
.places h3 { margin: 0; font: 400 clamp(26px, 2.6vw, 36px)/1.05 var(--serif); letter-spacing: -.02em; }
.places p { margin: 0; color: rgba(255, 255, 255, .82); font-size: 17px; }
.band .note { margin: 26px 0 0; color: rgba(255, 255, 255, .7); font: italic 400 17px/1.5 var(--sans); }
.note + .arrow-link, .sec-head p + .arrow-link { margin-top: 16px; }
.sec-head :is(p, h2) + .arrow-link { grid-column: 2; justify-self: start; }
.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px clamp(28px, 5vw, 80px); align-items: end; position: relative; padding-top: 22px; }
.split h2 { font: 400 clamp(40px, 5vw, 72px)/1 var(--serif); letter-spacing: -.03em; margin: 16px 0 0; }
.split h2 em { color: var(--blue); }
.split p { margin: 0 0 26px; color: var(--grey); font-size: 18px; max-width: 34em; }
.cta-end h2 { max-width: 12em; margin: 0; font: 400 clamp(38px, 4.6vw, 66px)/1.02 var(--serif); letter-spacing: -.03em; }
.cta-end h2 em { color: var(--blue); }
.cta-end .box { width: 100%; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-end; gap: 28px; padding: clamp(28px, 4vw, 52px); border: 3px double var(--ink); }
.cta-end .box > * { min-width: 0; }   /* the heading may be narrower than its longest word ("Bincangkan" at 130 % text), which then breaks */

/* work */
.ledger { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-bottom: 1px solid var(--rule-2); }
.ledger.four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ledger div { padding-block: 28px 30px; padding-inline: 0 24px; }
.ledger div + div { padding-inline-start: 24px; border-inline-start: 1px solid var(--rule); }
.ledger strong { display: block; font: 300 clamp(54px, 5.6vw, 84px)/1 var(--serif); letter-spacing: -.04em; font-variant-numeric: lining-nums; }
.ledger span { display: block; max-width: 250px; margin-top: 10px; color: var(--grey); font-size: 14.5px; }
.gallery { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 14px; }
.gallery figure { height: clamp(240px, 30vw, 440px); }
.g-4 { grid-column: span 4; } .g-5 { grid-column: span 5; } .g-6 { grid-column: span 6; } .g-7 { grid-column: span 7; } .g-8 { grid-column: span 8; }
/* a clip across the whole gallery keeps its own 16:9 instead of the row height, on a phone too (9 Nov 26: JETCO at MBS) */
.gallery figure.g-12 { grid-column: 1 / -1; height: auto; aspect-ratio: 16 / 9; }
.sites { width: 100%; border-collapse: collapse; font-size: 16px; }
.sites th { padding-block: 0 12px; padding-inline: 0 16px; border-bottom: 2px solid var(--ink); text-align: start; font: 600 11px/1.2 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--grey); }
.sites td { padding-block: 16px 15px; padding-inline: 0 16px; border-bottom: 1px solid var(--rule); vertical-align: baseline; }
.sites td:first-child { width: 76px; font: 300 28px/1 var(--serif); color: var(--blue); }
.sites td:nth-child(2) { font: 400 23px/1.25 var(--serif); letter-spacing: -.01em; }
.sites td:nth-child(n + 3) { color: var(--grey); }
.sites tbody tr { transition: background .25s var(--ease); }
.sites tbody tr:hover { background: var(--wash); }

/* the nine billboard sites: each card crossfades between the two pictures its board showed */
.reel { margin-bottom: clamp(44px, 5vw, 72px); }
.sites-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 36px 22px; }
.duo { position: relative; margin: 0; aspect-ratio: 4 / 3; overflow: hidden; background: var(--wash); }
.duo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease); }
.duo img + img { animation: duo 10s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -1.3s); }
.sites-grid li:hover .duo img { transform: scale(1.03); }
@keyframes duo { 0%, 40% { opacity: 0; } 50%, 90% { opacity: 1; } 100% { opacity: 0; } }
/* 1fr, not minmax(0, 1fr): a long place name ("Lebuhraya Persekutuan") widens its column of the list instead of sticking
   out of its card; when the two columns then no longer fit, site.js stacks the list */
.site-cap { display: grid; grid-template-columns: 46px 1fr; gap: 2px 10px; margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--rule-2); }
.site-cap .no { grid-row: span 2; font: 300 30px/1 var(--serif); color: var(--blue); }
.site-cap b { font: 400 22px/1.2 var(--serif); letter-spacing: -.01em; }
.site-cap span:last-child { color: var(--grey); font-size: 14.5px; }
/* Where a case is, first thing and plain to see (9 Nov 26, Dave: "Media Campaigns 地点要突出 客户翻到第一眼就知道在哪"):
   one style for the case cards and case sections (on top) and for every site and campaign in the lists (first line
   under the photo). build-site.mjs stops if a case has none. */
.where { display: flex; align-items: flex-start; gap: 7px; margin: 0 0 14px; color: var(--ink); font: 600 15px/1.35 var(--sans); letter-spacing: .01em; }
.where .ico { flex: none; width: 17px; height: 17px; margin-top: 1px; color: var(--blue); }
.where strong { font-weight: 600; }
.site-cap .where { grid-column: 2; margin: 0 0 3px; font-size: 14px; }
.site-cap .where .ico { width: 15px; height: 15px; margin: 2px 0 0; }
.sec-head .where { margin-bottom: 10px; }
/* A case section (data-case): its place stands in the left column, where other sections have their small label, a
   size up, and the headline beside it has the wide column (9 Nov 26 review: the place sat on the right in 14 px, and
   the 60 px headline was pushed into the 220 px column, three lines, "billboard" running 16 px into the paragraph) */
[data-case] .sec-head .where { grid-column: 1; grid-row: 1 / span 2; margin: 6px 0 0; font-size: 19px; line-height: 1.35; }
[data-case] .sec-head .where .ico { width: 21px; height: 21px; margin-top: 1px; }
[data-case] .sec-head h2 { grid-column: 2; }
/* the Construction Arm's projects (2 Nov 26): the old site's titles are longer, so a size down, with the place and the
   client under each; the package number may break anywhere */
.works .site-cap .no { grid-row: span 3; }
.works .site-cap b { font-size: 19px; line-height: 1.25; }
.works .site-cap span:not(.no) { grid-column: 2; color: var(--grey); font-size: 14.5px; }
.works .site-cap bdi { overflow-wrap: anywhere; }
/* what it is registered with: the old site's logos, small (135-189 px), so they keep about their own size */
.regs { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 16px 36px; }
.regs img { display: block; width: auto; height: 104px; }
#registered .sec-head { margin-bottom: 0; }
.sec-head .label .ico { width: 15px; height: 15px; margin-inline-end: 7px; vertical-align: -3px; }
/* the Plantation Arm: one page, its logo and a line (the client: "Something exciting coming") */
.soon { padding-block: clamp(64px, 9vw, 140px) clamp(72px, 10vw, 150px); }
.soon-logo { display: block; width: 280px; height: auto; margin-top: 34px; }
.soon h1 { margin-top: 28px; }
.soon .deck { margin-top: 24px; }
.soon .ctas { margin-top: 32px; }
/* a row of photos (Malaysia on the Media page) */
.photo-row { display: grid; grid-template-columns: 1.3fr 1fr 1fr; grid-auto-rows: clamp(220px, 22vw, 320px); gap: 14px; margin: 0 0 44px; }
.photo-row figure { position: relative; margin: 0; overflow: hidden; background: rgba(255, 255, 255, .06); }
.photo-row :is(img, video) { width: 100%; height: 100%; object-fit: cover; }
.photo-row figcaption { position: absolute; inset-inline-start: 0; bottom: 0; max-width: 85%; padding: 6px 10px 5px; background: #fff; color: var(--ink); font: italic 400 13.5px/1.3 var(--sans); }

/* about */
.story { columns: 2; column-gap: 56px; column-rule: 1px solid var(--rule); font-size: 18px; color: var(--grey); }
.story p { margin: 0 0 1em; }
.story b { color: var(--ink); font-weight: 600; }
/* About (2 Nov 26): the client's own copy, what GAFAS does and its eight platforms beside Why Us? */
.about-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.about-grid > div { padding-inline-end: clamp(24px, 3.5vw, 56px); }
.about-grid > div + div { padding-inline: clamp(24px, 3.5vw, 56px) 0; border-inline-start: 1px solid var(--rule); }
.about-grid h3 { margin: 0 0 12px; font: 600 11.5px/1.2 var(--sans); letter-spacing: .17em; text-transform: uppercase; color: var(--blue); }
.about-grid .intro { margin: 0 0 34px; font-size: 18px; color: var(--grey); }
/* two columns that line up row by row (9 Nov 26 review: as text columns, a name on two lines pushed its column
   out of step with the other) */
.solutions { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 28px; }
.solutions li { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px dotted var(--rule-2); }
.solutions .ico { flex: none; width: 18px; height: 18px; color: var(--blue); }
.why { margin: 0; }
.why div { padding-block: 0 22px; }
.why div + div { padding-top: 22px; border-top: 1px solid var(--rule); }
.why dt { margin: 0 0 8px; font: 400 clamp(22px, 2vw, 28px)/1.2 var(--serif); letter-spacing: -.01em; }
.why dt .ico { width: 22px; height: 22px; margin-inline-end: 10px; vertical-align: -3px; color: var(--blue); }
.why dd { margin: 0; color: var(--grey); }
.job { display: grid; grid-template-columns: 1fr 1.2fr; gap: clamp(28px, 5vw, 72px); padding: clamp(28px, 4vw, 52px); border: 3px double var(--ink); }
.job h3 { font: 400 clamp(36px, 4vw, 56px)/1 var(--serif); letter-spacing: -.03em; margin: 14px 0 16px; }
.job .hook { margin: 0 0 26px; font: italic 400 21px/1.45 var(--sans); color: var(--grey); }
.job h4 { margin: 0 0 10px; font: 600 11.5px/1.2 var(--sans); letter-spacing: .17em; text-transform: uppercase; color: var(--blue); }
.job ul { margin: 0 0 26px; padding: 0; list-style: none; }
.job li { position: relative; padding-block: 7px; border-bottom: 1px dotted var(--rule-2); }
.job .apply { margin: 0; font-size: 16px; }
.job .apply a { border-bottom: 1px solid var(--rule-2); font-weight: 600; }

/* contact form */
.contact-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(32px, 6vw, 96px); align-items: start; }
.form { display: grid; gap: 26px; }
.form .two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px; }
.field { display: block; }
.field > span, .form legend { display: block; margin-bottom: 8px; font: 600 11px/1.2 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--grey); }
.field input, .field textarea { width: 100%; padding: 8px 0 10px; border: 0; border-bottom: 1px solid var(--rule-2); border-radius: 0; background: transparent; color: var(--ink); font: 400 21px/1.4 var(--serif); transition: border-color .2s; }
.field textarea { min-height: 120px; resize: vertical; }
.field input:focus, .field textarea:focus { outline: none; border-bottom-color: var(--blue); box-shadow: 0 1px 0 var(--blue); }
.field input::placeholder, .field textarea::placeholder { color: rgba(68, 84, 106, .55); }
.form fieldset { margin: 0; padding: 0; border: 0; }
.form legend { padding: 0; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip { position: relative; }
.chip input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.chip span { display: inline-flex; align-items: center; height: 40px; padding: 0 16px; border: 1px solid var(--rule-2); border-radius: 999px; font: 500 14.5px/1 var(--sans); cursor: pointer; transition: background .2s, color .2s, border-color .2s; }
.chip span:hover { border-color: var(--ink); }
.chip input:checked + span { background: var(--ink); border-color: var(--ink); color: #fff; }
.chip input:focus-visible + span { outline: 2px solid var(--blue); outline-offset: 2px; }
.form-end { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 26px; padding-top: 6px; }
.form-note { margin: 0; font-size: 14px; color: var(--grey); }

/* ---------- footer ---------- */
.ft { margin-top: clamp(80px, 9vw, 130px); padding: 56px 0 34px; border-top: 3px double var(--ink); }
/* five columns since the subsidiaries came in (2 Nov 26): the logo, pages, subsidiaries, ways to talk to us, the office,
   each as wide as its longest line and spread across, so the phone number and the hours keep to one line (Malay, the
   widest, just fits at 1440). Below 1300 the logo and its line take a row of their own. */
.ft-grid { display: grid; grid-template-columns: repeat(5, auto); justify-content: space-between; gap: 36px 20px; }
@media (max-width: 1300px) {
  .ft-grid { grid-template-columns: repeat(4, auto); }
  .ft-brand { grid-column: 1 / -1; }
}
.ft-brand img { height: 104px; width: auto; }
.ft-brand p { margin: 18px 0 0; font: italic 400 18px/1.45 var(--sans); color: var(--grey); }
.ft-col { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; font-size: 15.5px; }
.ft-col .label { margin-bottom: 8px; }
.ft-col a { transition: color .2s; }
.ft-col a:hover { color: var(--blue); }
.ft-col p { margin: 0; color: var(--grey); }
/* MATRADE membership under the office hours (Ito, 9 Nov 26): its own colours, like the "Registered with" logos on the
   Construction page; the line goes under the logo when the column is narrow */
.ft-matrade { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.ft-matrade img { display: block; width: 138px; height: 22px; }
.legal { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 16px; margin-top: 48px; padding-top: 18px; border-top: 1px solid var(--rule); color: var(--grey); font-size: 12.5px; }
.credit { margin: 10px 0 0; color: var(--grey); font-size: 11.5px; }
.credit a { transition: color .2s; }
.credit a:hover { color: var(--blue); }

/* ---------- motion ---------- */
.js .rv { opacity: 0; transform: translateY(20px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.js .rv.in { opacity: 1; transform: none; }
.js .rise { opacity: 0; transform: translateY(18px); animation: rise 1s var(--ease) forwards; }
.js .rise:nth-child(2) { animation-delay: .08s; }
.js .rise:nth-child(3) { animation-delay: .16s; }
.js .rise:nth-child(4) { animation-delay: .24s; }
.js .rise:nth-child(5) { animation-delay: .32s; }
.js .rise:nth-child(6) { animation-delay: .4s; }
.js .screen.rise { animation-delay: .2s; animation-duration: 1.3s; }
@keyframes rise { to { opacity: 1; transform: none; } }

/* headlines: each word (each character in Chinese) rises out of its own mask; site.js wraps them */
.w { display: inline-block; overflow: hidden; vertical-align: top; padding: .04em .1em .2em; margin: -.04em -.1em -.2em; }
/* On a phone, a word wider than the line (big text: "infrastructure", "infrastruktur.", "Bincangkan") breaks inside
   itself, hyphenated where the browser knows the language, instead of running off the screen. Only when it cannot fit:
   at normal sizes nothing moves. Values in .rows (e-mails, numbers) the same. */
/* site.js adds .stack to a two-column list whose longest words cannot sit side by side (9 Nov 26: Samsung Internet
   with the phone's text at 115-130 %); it becomes one column instead of running off the screen */
.platforms.stack, .sites-grid.stack { grid-template-columns: minmax(0, 1fr); }
.platforms.stack li, .platforms.stack li:nth-child(even) { padding-inline-start: 0; border-inline-start: 0; }
.facts.stack { grid-template-columns: minmax(0, 1fr); row-gap: 12px; }
.facts.stack div + div { padding-inline-start: 0; border-inline-start: 0; }
@media (max-width: 760px) {
  .w { max-width: 100%; overflow-wrap: anywhere; -webkit-hyphens: auto; hyphens: auto; }
  h1, h2, h3 { overflow-wrap: break-word; }          /* "merentasi sempadan." in the home page's contact box */
  .cta-end h2 { overflow-wrap: anywhere; }
  .rows dd { overflow-wrap: break-word; }   /* not anywhere: "comm@gafas.com.m" + "y" on a 375 px iPhone (9 Nov 26) */
  /* the footer's two narrow columns on a 280 px phone with big text: "SUBSIDIARIES", "Construction Arm" break inside */
  .ft-col :is(.label, a) { overflow-wrap: anywhere; -webkit-hyphens: auto; hyphens: auto; }
  /* a button whose words do not fit on one line (Malay "Telefon bimbit +6019-756 6362" at 280 px, big text) takes two */
  .btn { flex-wrap: wrap; height: auto; min-height: 54px; row-gap: 4px; padding-block: 8px; text-align: center; }
}
.w > span { display: inline-block; }
.js .words .w > span { transform: translateY(115%); animation: word-up 1s var(--ease) forwards; animation-delay: calc(var(--i, 0) * 60ms + 120ms); }
@keyframes word-up { to { transform: none; } }

/* the rules over section heads draw in from the left */
.sec-head::before, .split::before, .ledger::before, .phead-foot::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: var(--ink); transform-origin: left center; }
.js .sec-head.rv::before, .js .split.rv::before, .js .ledger.rv::before { transform: scaleX(0); transition: transform 1.4s var(--ease) .15s; }
.js .sec-head.rv.in::before, .js .split.rv.in::before, .js .ledger.rv.in::before { transform: none; }
.js .phead-foot::before { animation: draw 1.4s .3s var(--ease) both; }
@keyframes draw { from { transform: scaleX(0); } }

/* lists come in one item after another (site.js numbers the items) */
.js [data-stagger] > * { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease), transform .7s var(--ease); transition-delay: calc(var(--i, 0) * 70ms + 120ms); }
.js .in[data-stagger] > *, .js .in [data-stagger] > * { opacity: 1; transform: none; }

/* photos open like a blind */
.js .rv.mosaic > figure, .js .rv.gallery > figure { clip-path: inset(100% 0 0 0); transition: clip-path 1.2s var(--ease); transition-delay: calc(var(--i, 0) * 90ms + 100ms); }
.js .rv.in.mosaic > figure, .js .rv.in.gallery > figure { clip-path: inset(0 0 0 0); }
.js .rv.fmt .fmt-pic { clip-path: inset(0 100% 0 0); transition: clip-path 1.3s var(--ease) .15s; }
.js .rv.fmt:nth-of-type(even) .fmt-pic { clip-path: inset(0 0 0 100%); }
.js .rv.in.fmt .fmt-pic { clip-path: inset(0 0 0 0); }
.fmt-pic img { transition: transform 1.2s var(--ease); }
.fmt:hover .fmt-pic img { transform: scale(1.03); }

/* the screen switches on, then its tag drops in */
@keyframes power-on {
  0% { clip-path: inset(49.4% 0 49.4% 0 round 8px); filter: brightness(2.6); }
  55% { clip-path: inset(0 0 0 0 round 8px); filter: brightness(1.5); }
  100% { clip-path: inset(0 0 0 0 round 8px); filter: brightness(1); }
}
@keyframes tag-in { from { opacity: 0; transform: translate(-8px, -16px) rotate(-16deg); } to { opacity: 1; transform: rotate(-4deg); } }
.js .hero .screen .glass { animation: power-on 1.2s .6s cubic-bezier(.7, 0, .2, 1) both; }
.js .hero .screen .tag { animation: tag-in .9s 1.5s var(--ease) both; }
.js .screen.rv .glass { clip-path: inset(49.4% 0 49.4% 0 round 6px); }
.js .screen.rv .tag { opacity: 0; }
.js .screen.rv.in .glass { animation: power-on 1.2s .3s cubic-bezier(.7, 0, .2, 1) both; }
.js .screen.rv.in .tag { animation: tag-in .9s 1.2s var(--ease) both; }

/* ticker: a news crawl of what we sell */
.ticker { overflow: hidden; background: var(--ink); color: #fff; }
.ticker-track { display: flex; width: max-content; animation: crawl 60s linear infinite; }
.ticker span { display: inline-flex; align-items: center; padding: 20px 0; font: 400 clamp(22px, 2.2vw, 30px)/1 var(--serif); white-space: nowrap; }
.ticker span:nth-child(even) { font-weight: 300; }
.ticker span::after { content: ""; width: 7px; height: 7px; margin: 0 30px; background: #fff; opacity: .55; transform: rotate(45deg); }
.ticker:hover .ticker-track { animation-play-state: paused; }
@keyframes crawl { to { transform: translateX(-50%); } }

/* page to page: the masthead stays put while the page fades through */
@view-transition { navigation: auto; }
.hdr { view-transition-name: masthead; }
::view-transition-old(root) { animation: vt-out .3s var(--ease) both; }
::view-transition-new(root) { animation: vt-in .55s var(--ease) both; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(12px); } }

/* numbers keep their width while they count up */
.facts strong, .ledger strong { font-variant-numeric: lining-nums tabular-nums; }
/* the years are a span inside the number (site.js keeps them current): it is part of the number, not a caption */
.facts strong span, .ledger strong span { display: inline; margin: 0; font: inherit; color: inherit; }

/* ---------- smaller screens ---------- */
/* the three countries under the home page's headline need about 400 px at full size, more than its column has from
   1200 px down: a smaller line keeps them on one */
@media (max-width: 1200px) {
  .hero .msi { font-size: 12.5px; letter-spacing: .14em; }
  .hero .msi { --sep: calc(2.2em + 6px); }
}
@media (max-width: 1100px) {
  /* narrower than the stage: the map becomes a picture of its own across the page, framed on the three markets
     (lon 95.5–120, lat 7.5 to −7.8), with the heading, or an open country's panel, under it */
  .stage { aspect-ratio: auto; }
  .map-box { position: relative; left: auto; width: auto; margin: 0 calc(-1 * var(--pad)) 6px; aspect-ratio: 1176 / 734.4; overflow: hidden; clip-path: none; }
  .map-box svg { position: absolute; left: -42.86%; top: 0; width: 195.92%; margin-top: -18.37%; }
  .map-sec { border-bottom: 0; }
  .map-text { position: static; width: auto; max-width: 640px; margin-top: 22px; padding: 0; background: none; border: 0; box-shadow: none; }
  .map-text h2 { font-size: clamp(32px, 4.6vw, 46px); }
  .map-text p { font-size: 15.5px; line-height: 1.55; }
  /* no layer of its own here (nothing overlaps the map), so the list button below can float over the whole page */
  .map-box, .map-bar { z-index: auto; }
  .map-bar { left: 12px; top: 12px; }
  /* on a narrower screen the list button waits in the window's corner, in reach of a thumb */
  .picks-btn { position: fixed; inset-inline-end: 16px; bottom: 16px; height: 50px; }
  .map-panel { position: relative; width: auto; max-height: none; margin: 2px 0 26px; box-shadow: 4px 4px 0 var(--ink); }
  .stage.zoomed > .map-text { display: none; }
  .map-panel.site-view { width: auto; }
  .map-hint { left: 12px; top: auto; bottom: 12px; white-space: normal; max-width: calc(100% - 24px); }   /* one line unless the phone's text is set big */
  /* the home page's headline gets a wider column (the country line is smaller from 1200 px down), and the lead and
     the facts stack */
  .hero-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); }
  .hero .arrow-link { font-size: 14px; }
  .hero-foot { grid-template-columns: minmax(0, 1fr); gap: 26px; }
}
@media (max-width: 1000px) {
  .menu li { grid-template-columns: 70px minmax(0, 1fr); gap: 6px 18px; }
  .menu li p { grid-column: 2; }
  .menu .where { grid-column: 2; justify-self: start; text-align: start; margin-top: 6px; }
  .menu .thumb { display: none; }
  .sec-head { grid-template-columns: minmax(0, 1fr); }
  .sec-head p { grid-column: 1; }
  [data-case] .sec-head .where { grid-row: auto; margin: 0; font-size: 17px; }
  [data-case] .sec-head h2 { grid-column: 1; }
  .steps.four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .steps.four div:nth-child(3) { padding-inline-start: 0; border-inline-start: 0; }
  .steps.four div:nth-child(n + 3) { border-top: 1px solid var(--rule); margin-top: 10px; }
  .places li { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 860px) {
  html { scroll-padding-top: 72px; }
  .hdr { top: -16px; height: 80px; }
  .hdr .wrap { display: flex; justify-content: space-between; }
  .hdr.compact .wrap { transform: translateY(8px); }
  .nav-main, .nav-r .pill, .nav-r .lang-pick { display: none; }
  .menu-btn { display: inline-flex; }
  .logo img { height: 62px; }
  .hdr.compact .logo img { transform: scale(.75); }
  .spread-grid, .phead-foot, .contact-grid, .split, .job { grid-template-columns: minmax(0, 1fr); }
  /* the eight platforms two by two, the case studies and About's two columns one under the other (2 Nov 26) */
  .platforms { grid-template-columns: 1fr 1fr; }
  .platforms li, .platforms li:not(:nth-child(4n + 1)) { gap: 14px; padding-block: 18px 20px; padding-inline: 0 14px; border-inline-start: 0; }
  .platforms li:nth-child(even) { padding-inline-start: 14px; border-inline-start: 1px solid var(--rule); }
  .pf-top .ico { width: 32px; height: 32px; }
  .cases { grid-template-columns: minmax(0, 1fr); gap: 34px; }
  .case h3 { font-size: 26px; }
  .about-grid { grid-template-columns: minmax(0, 1fr); }
  .about-grid > div, .about-grid > div + div { padding-inline: 0; border-inline-start: 0; }
  .about-grid > div + div { margin-top: 34px; padding-top: 30px; border-top: 1px solid var(--rule); }
  .solutions { grid-template-columns: minmax(0, 1fr); }
  /* on a phone the headline comes first, the screen under it, then the lead and the facts */
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: 30px; padding-top: 28px; }
  .hero .screen.wide .bezel { padding: 7px; border-radius: 10px; }
  .map .pin:not(.plan):not([data-k="jewel"]) .city { display: none; }
  /* the smaller peninsula sites crowd each other at this size; their pins come back on a bigger screen */
  .map .pin:is([data-k="alorsetar"], [data-k="ipoh"], [data-k="kuantan"], [data-k="seremban"], [data-k="melaka"], [data-k="pontian"], [data-k="desaru"]) { display: none; }
  .map { --pop: .72; --finger: 20; }
  .map .cn { font-size: calc(12.5px / var(--k, 1)); letter-spacing: .3em; stroke-width: calc(3px / var(--k, 1)); }
  .map :is(.rose, .grat text) { display: none; }
  .deep .map .pin:is([data-k="alorsetar"], [data-k="ipoh"], [data-k="kuantan"], [data-k="seremban"], [data-k="melaka"], [data-k="pontian"], [data-k="desaru"]) { display: inline; }
  .map .pin:is(.lit, .here) .grow, .deep .map .pin:is([data-k="alorsetar"], [data-k="ipoh"], [data-k="kuantan"], [data-k="seremban"], [data-k="melaka"], [data-k="pontian"], [data-k="desaru"]) .grow { animation: pin-in .6s var(--ease) .45s both; }
  .map .pin:is(.lit, .here) { display: inline; }
  .deep .map .pin:not(.plan):not([data-k="jewel"]) .city { display: inline; opacity: 1; animation: appear .5s .5s both; }
  .map-hint { padding: 7px 12px 7px 9px; font-size: 12px; }
  .lb-pic .sv-pic { max-width: calc(100vw - 24px); max-height: calc(100vh - 190px); max-height: calc(100dvh - 190px); }
  .lb-prev, .lb-next { top: auto; bottom: 16px; }
  .screen { width: min(78%, 320px); margin-top: 8px; }
  .screen .tag { left: -14px; }
  .screen.wide { width: 100%; }
  .screen.wide .tag { left: -6px; }
  .facts strong { font-size: 26px; }
  .mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: 260px 200px 200px; gap: 10px; }
  .m1 { grid-column: 1 / 2; grid-row: 1 / 2; } .m2 { grid-column: 1 / 3; grid-row: 2 / 3; } .m3 { grid-column: 2 / 3; grid-row: 1 / 2; } .m4 { grid-column: 1 / 2; grid-row: 3 / 4; } .m5 { grid-column: 2 / 3; grid-row: 3 / 4; }
  .ledger, .ledger.four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ledger div:nth-child(3) { padding-inline-start: 0; border-inline-start: 0; }
  .ledger div:nth-child(n + 3) { border-top: 1px solid var(--rule); }
  .ledger div:nth-child(3):last-child { grid-column: 1 / -1; }
  .credits, .credits.long { columns: 1; }
  .steps, .steps.four { grid-template-columns: minmax(0, 1fr); }
  .steps div + div, .steps.four div + div { padding-inline-start: 0; border-inline-start: 0; border-top: 1px solid var(--rule); margin-top: 0; }
  .classified { grid-template-columns: minmax(0, 1fr); }
  .fmt { grid-template-columns: minmax(0, 1fr); }
  .fmt:nth-of-type(even) .fmt-pic { order: 0; }
  .trio { grid-template-columns: minmax(0, 1fr); }
  .card + .card { padding-inline-start: 0; border-inline-start: 0; border-top: 1px solid var(--rule); }
  /* 1fr, not minmax(0, 1fr): at normal size the column with the longer word ("Persekutuan", "foodpanda") takes a little
     more room. When even that does not fit (the phone's text set bigger), site.js stacks the list (.stack, below). */
  .sites-grid { grid-template-columns: 1fr 1fr; gap: 26px 12px; }
  .site-cap { grid-template-columns: 34px 1fr; }
  /* its place across the whole caption, over the number and name (9 Nov 26 review: in the 120 px beside the number
     it went one word a line, "By Berjaya / Times / Square, / Kuala / Lumpur") */
  .site-cap .where { grid-column: 1 / -1; grid-row: 1; margin-bottom: 6px; }
  .site-cap .where ~ b { grid-column: 2; grid-row: 2; }
  .site-cap .no { font-size: 24px; }
  .site-cap b { font-size: 18px; }
  .site-cap span:last-child { font-size: 13px; }
  /* the construction projects one under the other: their titles are long, and the old photos small */
  .sites-grid.works { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .works .site-cap b { font-size: 18px; }
  .works .site-cap span:not(.no) { font-size: 13.5px; }
  .regs { gap: 12px 22px; }
  .regs img { height: 72px; }
  .soon-logo { width: 220px; }
  .photo-row { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: 220px 170px; gap: 10px; }
  .photo-row figure:first-child { grid-column: 1 / -1; }
  .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .gallery figure { grid-column: span 1; height: 220px; }
  .gallery figure.wide-m { grid-column: 1 / -1; height: 240px; }
  .story { columns: 1; }
  .ft-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .sites thead { display: none; }
  .sites tr { display: grid; grid-template-columns: 52px minmax(0, 1fr); padding: 14px 0; border-bottom: 1px solid var(--rule); }
  .sites td { padding: 0; border: 0; }
  .sites td:first-child { grid-row: span 2; width: auto; font-size: 24px; }
  .sites td:nth-child(2) { font-size: 21px; }
  .sites td:nth-child(n + 3) { font-size: 14.5px; }
  .form .two { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 520px) {
  .msi { font-size: 12px; letter-spacing: .13em; }
  .msi, .hero .msi { --sep: calc(1.8em + 5px); --dot: 5px; }
  .facts div { padding-inline-end: 10px; }
  .facts div + div { padding-inline-start: 10px; }
  .facts strong { font-size: 22px; }
  .facts span { display: block; margin-top: 4px; font-size: 12px; line-height: 1.35; }
  .ledger strong { font-size: 46px; }
  /* 8.6vw: on a 320-360 px phone the number at 34px was wider than the box and ran over its double border (every
     language, normal text size); a little smaller keeps it on one line inside. Bigger phone text still wraps it. */
  .phone-big, .classified.solo .phone-big { font-size: min(34px, 8.6vw); }
  /* the label over its value (9 Nov 26 review: in an 86 px column "LOCATION", "WHATSAPP" and "PACKAGE" dropped under
     their icons, "IN / EVERY / PROPOSAL" took three lines, "WORK / MODE" two) */
  .rows div { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}
/* Arabic (30 Oct 26; it replaced a Jawi version the same day): read right to left. Flex, grid and the start/end
   paddings above turn the layout around by themselves; this is the rest. */
html:lang(ar) {
  --serif: 'Montserrat Variable', 'Noto Sans Arabic Variable', sans-serif;
  --sans: 'Montserrat Variable', 'Noto Sans Arabic Variable', sans-serif;
  font-synthesis: none; /* Arabic letters have no italic to fake */
}
/* letter spacing pulls joined letters apart, and the Latin headlines' tight lines would clip the letters' dots */
html:lang(ar) * { letter-spacing: 0 !important; }
html:lang(ar) body { line-height: 1.9; }
html:lang(ar) :is(h1, h2, h3, h4, .deck, .pull, .lead, .ticker span, .facts strong, .ledger strong, .credits b, .site-cap b, .sites td, .sheet nav a, .phone-big) { line-height: 1.5; }
html:lang(ar) main :is(.hero, .phead) h1 { line-height: 1.3; }
/* longer headlines (Malay, Indonesian) and the taller Arabic one would push the first line up into the Johor pins */
html:lang(id) .hero h1 { font-size: clamp(40px, 4.6vw, 68px); }
/* "Rentas Sempadan." is 8.8 times its font size across: on one line in the headline's column at every width */
html:lang(ms) .hero h1 { font-size: clamp(34px, 3.5vw, 50px); }
html:lang(ar) .hero h1 { font-size: clamp(42px, 5.2vw, 80px); margin-block: 12px 20px; }
[dir="rtl"] .map .grat text { display: none; }
/* a drop cap would cut the first letter off the word it is joined to */
[dir="rtl"] .logo img { transform-origin: right center; }
[dir="rtl"] :is(.sec-head, .split, .ledger, .phead-foot)::before { transform-origin: right center; }
[dir="rtl"] .arrow-link span[aria-hidden] { transform: scaleX(-1); }
.js[dir="rtl"] .rv.fmt:not(.in) .fmt-pic { clip-path: inset(0 0 0 100%); }
.js[dir="rtl"] .rv.fmt:not(.in):nth-of-type(even) .fmt-pic { clip-path: inset(0 100% 0 0); }
@media (prefers-reduced-motion: no-preference) {
  [dir="rtl"] .ticker-track { animation-name: crawl-rtl; }
}
@keyframes crawl-rtl { to { transform: translateX(50%); } }
/* the Arabic line in every page's language list */
.langs a[lang="ar"] :is(span, b) { letter-spacing: 0; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  html { scroll-behavior: auto; }
  .js .rv, .js .rise, .js .words .w > span, .js [data-stagger] > *, .js .rv.mosaic > figure, .js .rv.gallery > figure, .js .rv.fmt .fmt-pic, .js .screen .glass, .js .screen .tag { opacity: 1 !important; transform: none !important; clip-path: none !important; filter: none !important; animation: none !important; transition: none !important; }
  .js .screen .tag { transform: rotate(-4deg) !important; }
  .sec-head::before, .split::before, .ledger::before, .phead-foot::before { transform: none !important; animation: none !important; transition: none !important; }
  .ticker-track, .screen .tag i, .duo img + img { animation: none; }
  .js .map :is(.side path, .land .ink, .land .pencil, .lm path, .routes path, .rose circle, .rose path) { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; animation: none !important; }
  .js .map :is(.hatch, .grat, .names, .city, .rose text) { opacity: 1 !important; animation: none !important; }
  .js .map .grow { transform: none !important; animation: none !important; }
  .map .trip, .map .hops, .map .ping { display: none; }
  .js .map-hint, .map-hint .ico, .mp-pick .ico, .sv-body > *, .sv-pic, .lightbox[open], .picks[open], .picks-btn, .picks-btn.bump .picks-n { animation: none; }
}

/* a short wide window (a 1366 x 768 or 1280 x 720 laptop) sees the whole map at once (1 Nov 26): the stage narrows
   to the height left under the header and stays on the page's left edge, and the heading scales with it (cqi: a
   hundredth of the stage's width), as everything else on it already does. The sizes are the 1440 design's (stage
   1192 px). */
@media (min-width: 1101px) {
  .stage { max-width: max(860px, calc((100vh - 124px) / .6555)); container-type: inline-size; }
  .map-text { padding: min(22px, 1.85cqi) min(24px, 2cqi) min(24px, 2cqi); }
  .map-text h2 { margin-block: min(10px, .84cqi) min(12px, 1cqi); font-size: clamp(26px, 3.7cqi, 44px); }
  .map-text p { font-size: clamp(13px, 1.22cqi, 14.5px); }
}

/* ---------- the phone, second pass (1 Nov 26, Dave: "手机版本需要优化设计", "和使用舒适度"): shorter pages, the main
   button on the first screen, finger-sized places to tap, larger small print, a closer map, WhatsApp in reach ---------- */
.wa-fab { display: none; }
@media (max-width: 1000px) {
  .sec-head :is(p, h2) + .arrow-link { grid-column: 1; }
}
@media (max-width: 860px) {
  /* the map stands tall, edge to edge, with the heading over the sea under Java (it was the phone's first screen until
     2 Nov 26, Dave: "手机版的能不能一点开就是整页满地图"). The frame: lon 98.4 to 116.9 (Penang to Kota Kinabalu), lat
     9.5 to -20, so Jakarta's pin stays above the heading in every language (below 16°S the drawing has stopped, under
     the white the heading sits on). Zoomed in, the map is shorter, so the site's view under it starts on the screen
     (site.js frames the flight on the shorter map). */
  .map-box { aspect-ratio: 888 / 1416; margin-bottom: 0; }
  .map-box svg { left: -72.43%; width: 259.46%; margin-top: -13.51%; }
  .map-box::after { content: ""; position: absolute; inset: auto 0 0; height: 42%; background: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, .9) 50%, #fff); pointer-events: none; }
  .stage.zoomed .map-box { aspect-ratio: 888 / 720; }
  .stage.zoomed .map-box::after { display: none; }
  .map-text { position: absolute; z-index: 2; left: 0; right: 0; bottom: 18px; margin: 0; }
  .map-text h2 { margin: 8px 0 12px; font-size: clamp(28px, 8.4vw, 34px); }
  .map-text p { font-size: 15px; }
  .hero h1 { font-size: clamp(30px, 9.2vw, 38px); }
  .map-hint { top: 12px; bottom: auto; left: 12px; right: 12px; width: fit-content; margin-inline: auto; }
  /* less air between sections */
  .sec { padding-block: 56px; }
  .sec-head { gap: 16px; margin-bottom: 26px; }
  .ft { margin-top: 56px; padding-top: 40px; }
  /* the steps: number, title and words side by side instead of stacked */
  .steps div, .steps.four div { display: grid; grid-template-columns: 46px minmax(0, 1fr); column-gap: 12px; padding-block: 18px 16px; }
  .steps i { grid-row: span 2; margin: 0; font-size: 40px; }
  .steps h3 { grid-column: 2; margin: 3px 0 6px; padding-inline-end: 34px; font-size: 22px; }
  .steps p { grid-column: 2; }
  .steps div > .ico { top: 20px; inset-inline-end: 0; width: 24px; height: 24px; }
  /* the media list, tighter */
  .menu li { padding: 18px 0 16px; }
  .menu .n { font-size: 30px; }
  .menu .menu-c { padding: 24px 0 10px; }
  /* the footer: pages and subsidiaries side by side, then the office and the ways to talk to us across, links tall
     enough for a finger */
  .ft-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 20px; }
  .ft-brand { grid-column: 1 / -1; }
  .ft-brand img { height: 72px; }
  .ft-brand p { margin-top: 12px; font-size: 16px; }
  .ft-office { grid-column: 1 / -1; }
  .ft-talk { grid-column: 1 / -1; order: 1; }
  .ft-col { gap: 0; }
  .ft-col .label { margin-bottom: 6px; }
  .ft-col a { padding-block: 9px; }
  .ft-col p { padding-block: 4px; }
  /* text links: the same look, a taller place to tap */
  .arrow-link { position: relative; }
  .arrow-link::after { content: ""; position: absolute; inset: -12px -6px -8px; }
  .phone-big { padding-block: 6px; }
  /* the small capitals a size up */
  .label, .field > span, .form legend, .rows dt, :is(.rows, .meta) dt { font-size: 12px; }
  /* WhatsApp in reach of the thumb (site.js shows it once the first screen has scrolled by); the visitor's proposal
     list moves to the other corner */
  .wa-fab { position: fixed; z-index: 35; inset-inline-end: 16px; bottom: 16px; display: grid; place-items: center; width: 56px; height: 56px; border-radius: 50%; background: var(--ink); color: #fff; box-shadow: 0 12px 26px -10px rgba(25, 40, 83, .6); opacity: 0; transform: translateY(18px) scale(.8); pointer-events: none; transition: opacity .3s var(--ease), transform .3s var(--ease); }
  .wa-fab.show { opacity: 1; transform: none; pointer-events: auto; }
  .wa-fab svg { width: 27px; height: 27px; }
  body.menu-open .wa-fab { display: none; }
  .picks-btn { inset-inline-end: auto; inset-inline-start: 16px; }
}
@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .wa-fab { transition: none; }
}
