/* ==========================================================================
   Unti — Resume & Portfolio (Liquid Glass)
   Colour tokens mirror the Figma "Unti theme" collection (unti/*), Light + Dark.
   Surfaces follow the Figma page "Unti — Liquid Glass".
   ========================================================================== */

/* Urbanist (Google Fonts, SIL OFL 1.1 — URBANIST-OFL.txt), variable 100–900, self-hosted. Replaces Gilroy
   (commercial, no web licence) on 6 Nov: closest free match — same x-height/cap height, name within 0.4% width.
   The Gilroy faces below stay declared but unused (a browser only downloads faces in use). */
/* Space Grotesk (OFL, fonts/SPACE-GROTESK-OFL.txt): only for the AGS design-system specimen (9 Nov) */
/* Playfair Display SemiBold Italic (OFL, fonts/PLAYFAIR-OFL.txt): only for the AGS live page's italic phrases (9 Nov) */
@font-face { font-family: "Playfair Display"; src: url("../fonts/playfair-display-italic-600-latin.woff2") format("woff2"); font-style: italic; font-weight: 600; font-display: swap; }
@font-face { font-family: "Space Grotesk"; src: url("../fonts/space-grotesk-latin-var.woff2") format("woff2"); font-weight: 300 700; font-display: swap; }
@font-face {
  font-family: "Urbanist";
  src: url("../fonts/urbanist-latin-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Urbanist";
  src: url("../fonts/urbanist-latin-ext-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Gilroy";
  src: url("../fonts/gilroy-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Gilroy";
  src: url("../fonts/gilroy-medium.woff2") format("woff2");
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Gilroy";
  src: url("../fonts/gilroy-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Gilroy";
  src: url("../fonts/gilroy-extrabold.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Gilroy";
  src: url("../fonts/gilroy-black.woff2") format("woff2");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* unti/bg/* */
  --bg-page: #ffffff;
  --bg-card: #ffffff;
  --bg-subtle: #fbfbfb;
  /* unti/border/default */
  --border: #eaeaea;
  /* unti/text/* */
  /* Ink (Figma 138:2, 5 Nov): one warm grey #3c3c3c at three strengths */
  --text-primary: #3c3c3c;
  --text-secondary: rgb(60 60 60 / 0.75);
  --text-muted: rgb(60 60 60 / 0.6);
  /* unti/status/available */
  --status-available: #07e64a;

  /* Surfaces (Light): the page is plain white and section panels carry no surface of their own;
     only content — cards, tags, the top bar, buttons — sits on a soft grey fill. */
  --glass-panel: transparent;
  --glass-inner: #fafafa;           /* cards, rows */
  --surface-soft: #f7f7f7;          /* nav bar, buttons, project image tiles */
  --surface-raised: #ffffff;        /* the ↗ badge on project tiles */
  --border-subtle: #f0f0f0;
  --border-default: #dedede;
  --glass-control: rgb(255 255 255 / 0.62);
  --glass-rim: rgb(255 255 255 / 0.85);
  --glass-rim-soft: rgb(255 255 255 / 0.6);
  --card-shadow: 0 0 #0000;
  --tag-bg: transparent;
  --btn-bg: var(--surface-soft);
  --chip-rim: rgb(0 0 0 / 0.1);
  /* derived states (not in Figma yet) */
  --glass-inner-hover: #f3f3f3;
  --glass-control-hover: #ffffff;
  --btn-bg-hover: #efefef;
  /* Hairline: one device pixel on high-density screens (0.5px at 2×), 1px otherwise */
  --hairline: 1px;

  --glass-specular: rgb(255 255 255 / 0.9);
  --glass-glow: rgb(255 255 255 / 0.07);
  /* Apple-style elevation: a faint contact shadow + a wide, low-opacity ambient lift (no hard drop) */
  --glass-shadow: 0 1px 2px rgb(0 0 0 / 0.03), 0 10px 32px -8px rgb(0 0 0 / 0.07);
  /* Logo tiles keep their brand grounds; this 1px rim gives every tile edge ≥3:1 against the
     card (WCAG 1.4.11). Measured minimums: black 42% on the light card, white 34% on the dark card. */
  --icon-rim: rgb(0 0 0 / 0.42);

  /* layout */
  --page-width: 760px;
  --nav-gap: 24px;
  --page-pad-y: 80px;
  --page-pad-x: 0px;
  --stack-gap: 64px;
  --case-width: var(--page-width);   /* was 880px; 9 Nov (Hanan): case pages share the home page's 760px column so every page (and its footer) lines up */
  --case-text: 680px;
  --radius-panel: 32px;
  --radius-card: 20px;
  --radius-project: 22px;
  --radius-sm: 10px;

  /* motion */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  /* The original site's appear spring (stiffness 500, damping 40, mass 1), sampled; settles in 374ms. */
  --spring-appear: linear(0, 0.0298, 0.1037, 0.1962, 0.2971, 0.4021, 0.4971, 0.587, 0.663, 0.7286, 0.7865, 0.8325, 0.8704, 0.9022, 0.9265, 0.9464, 0.9612, 0.9725, 0.9814, 0.9877, 0.9923, 0.9958, 0.998, 0.9996, 1.0006, 1.0012, 1.0015, 1.0016, 1.0016, 1.0015, 1.0013, 1.0012, 1);
  --spring-appear-duration: 374ms;
  /* 12 Nov (Hanan: "the smooth ease-in rubber band curve" from blog.justinbuilds.mov/ios): real spring physics,
     m·x'' = -k(x - target) - b·x', sampled into linear(). Interruptible: a transition picks up from where it is.
     tilt = SwiftUI .bouncy (damping ratio 0.70, response 0.40s): the ↗ arrows overshoot a touch past → and settle;
     snap = .snappy (0.85, 0.35s): hover lifts and presses, almost no overshoot. */
  --spring-tilt: linear(0, 0.0139, 0.0486, 0.0989, 0.1605, 0.2296, 0.3059, 0.3809, 0.4553, 0.5274, 0.5961, 0.6628, 0.7218, 0.7753, 0.8232, 0.8655, 0.9036, 0.935, 0.9615, 0.9835, 1.0013, 1.0155, 1.0267, 1.0346, 1.0401, 1.0434, 1.0451, 1.0453, 1.0443, 1.0425, 1.04, 1.0371, 1.0338, 1.0304, 1.027, 1.0237, 1.0204, 1.0174, 1.0144, 1.0118, 1.0095, 1.0074, 1.0055, 1.0039, 1.0025, 1.0014, 1.0005, 0.9997, 1);
  --spring-tilt-duration: 504ms;
  --spring-snap: linear(0, 0.0164, 0.0558, 0.1111, 0.1794, 0.2506, 0.3239, 0.3996, 0.4697, 0.5361, 0.6003, 0.6567, 0.7077, 0.7552, 0.7955, 0.8308, 0.8626, 0.8889, 0.9113, 0.9303, 0.9467, 0.9598, 0.9706, 0.9796, 0.9865, 0.992, 0.9964, 0.9996, 1.0019, 1.0037, 1.0048, 1.0055, 1.0058, 1.0059, 1.0058, 1.0056, 1.0052, 1.0049, 1.0044, 1.004, 1.0035, 1.0031, 1.0027, 1.0024, 1.002, 1.0017, 1.0014, 1.0012, 1);
  --spring-snap-duration: 486ms;

  /* Type: one family, Urbanist since 6 Nov (Gilroy before; self-hosted, assets/fonts) — ExtraBold for the name, Regular/Medium/Bold elsewhere */
  --font-primary: "Urbanist", ui-sans-serif, system-ui, sans-serif;     /* was "Gilroy" (switch back: also --track -0.02em, --w-body 500) */
  --font-secondary: "Urbanist", ui-sans-serif, system-ui, sans-serif;
  --track: -0.005em;      /* Urbanist sets ~4% narrower than Gilroy at -0.02em */
  --w-body: 545;          /* Urbanist 545 ≈ Gilroy Medium's colour */
  /* Brand card / game night (Figma 153:320). Dark mode tones it down (Hanan, 6 Nov) */
  --night-base: #0a011f;
  --night-glow: rgb(255 255 255 / 0.3);
  --night-rim: rgb(81 69 109 / 0.2);
  --night-top: rgb(54 51 64 / 0.3);
  --night-deep: #1a054f;
  --toolchip-bg: #ffffff;   /* tool chips / row hover on the grey card */
  /* Safari toolbar in the browser mockups */
  --safari-bar: #f6f6f6;
  --safari-field: #e8e8ea;
  --safari-line: rgb(0 0 0 / 0.08);
  --safari-icon: #737378;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-page: #141414; /* neutral dark (Hanan, 6 Nov). Violet alternative: #0b0224 */
    --safari-bar: #2c2c2e;
    --toolchip-bg: rgb(255 255 255 / 0.08);
    --safari-field: #3a3a3c;
    --safari-line: rgb(0 0 0 / 0.5);
    --safari-icon: #a1a1a6;
    --night-base: #0a011f; /* dark: same colour, softer effects (Hanan, 6 Nov) */
    --night-glow: rgb(255 255 255 / 0.1);
    --night-rim: rgb(81 69 109 / 0.08);
    --night-top: rgb(54 51 64 / 0.12);
    --night-deep: rgb(26 5 79 / 0.4);
    --bg-card: #1f1f1f;
    --bg-subtle: #222222;
    --border: #303030;
    --text-primary: rgb(255 255 255 / 0.94);
    --text-secondary: rgb(255 255 255 / 0.75);
    --text-muted: rgb(255 255 255 / 0.6);
    --glass-panel: transparent;
    --glass-inner: rgb(255 255 255 / 0.06);
    --surface-soft: rgb(255 255 255 / 0.07);
    --surface-raised: rgb(255 255 255 / 0.16);
    --border-subtle: rgb(255 255 255 / 0.08);
    --border-default: rgb(255 255 255 / 0.22);
    --glass-control: rgb(255 255 255 / 0.12);
    --glass-rim: transparent; /* no strokes in dark, matching light (Hanan, 6 Nov); was rgb(255 255 255 / 0.2) */
    --glass-rim-soft: transparent; /* was rgb(255 255 255 / 0.14) */
    --tag-bg: transparent;
    --btn-bg: var(--glass-control);
    --btn-bg-hover: var(--glass-control-hover);
    --chip-rim: rgb(255 255 255 / 0.16);
    --glass-inner-hover: rgb(255 255 255 / 0.09);
    --glass-control-hover: rgb(255 255 255 / 0.18);
    --glass-specular: rgb(255 255 255 / 0.1);
    --icon-rim: rgb(255 255 255 / 0.36);
    --card-shadow: 0 0 #0000;
    --glass-shadow: 0 1px 2px rgb(0 0 0 / 0.18), 0 12px 36px -10px rgb(0 0 0 / 0.32);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg-page: #141414; /* neutral dark (Hanan, 6 Nov). Violet alternative: #0b0224 */
  --safari-bar: #2c2c2e;
  --toolchip-bg: rgb(255 255 255 / 0.08);
  --safari-field: #3a3a3c;
  --safari-line: rgb(0 0 0 / 0.5);
  --safari-icon: #a1a1a6;
  --night-base: #0a011f; /* dark: same colour, softer effects (Hanan, 6 Nov) */
  --night-glow: rgb(255 255 255 / 0.1);
  --night-rim: rgb(81 69 109 / 0.08);
  --night-top: rgb(54 51 64 / 0.12);
  --night-deep: rgb(26 5 79 / 0.4);
  --bg-card: #1f1f1f;
  --bg-subtle: #222222;
  --border: #303030;
  --text-primary: rgb(255 255 255 / 0.94);
  --text-secondary: rgb(255 255 255 / 0.75);
  --text-muted: rgb(255 255 255 / 0.6);
  --glass-panel: transparent;
  --glass-inner: rgb(255 255 255 / 0.06);
  --surface-soft: rgb(255 255 255 / 0.07);
  --surface-raised: rgb(255 255 255 / 0.16);
  --border-subtle: rgb(255 255 255 / 0.08);
  --border-default: rgb(255 255 255 / 0.22);
  --glass-control: rgb(255 255 255 / 0.12);
  --glass-rim: transparent; /* no strokes in dark, matching light (Hanan, 6 Nov); was rgb(255 255 255 / 0.2) */
  --glass-rim-soft: transparent; /* was rgb(255 255 255 / 0.14) */
  --tag-bg: transparent;
  --btn-bg: var(--glass-control);
  --btn-bg-hover: var(--glass-control-hover);
  --chip-rim: rgb(255 255 255 / 0.16);
  --glass-inner-hover: rgb(255 255 255 / 0.09);
  --glass-control-hover: rgb(255 255 255 / 0.18);
  --glass-specular: rgb(255 255 255 / 0.1);
  --icon-rim: rgb(255 255 255 / 0.36);
  --card-shadow: 0 0 #0000;
  --glass-shadow: 0 1px 2px rgb(0 0 0 / 0.18), 0 12px 36px -10px rgb(0 0 0 / 0.32);
  color-scheme: dark;
}

@media (min-resolution: 2dppx) {
  :root { --hairline: 0.5px; }
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  /* Page colour + one faint neutral glow at the top (the Figma "Wallpaper") */
  background:
    radial-gradient(120% 900px at 50% 0%, var(--glass-glow), transparent 70%) no-repeat,
    var(--bg-page);
  color: var(--text-primary);
  font-family: var(--font-secondary);
  font-size: 16px;
  font-weight: var(--w-body);
  line-height: 1.35;
  letter-spacing: var(--track);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, p { margin: 0; font-weight: inherit; }
button { font: inherit; letter-spacing: inherit; }
/* Type (Figma 138:2): Gilroy, weights one step heavy in the Swiggy manner (body Medium, labels SemiBold,
   titles Bold, the name Black), −2% tracking resolved per element (an em on body would inherit as px). */
:where(h1, h2, h3, p, a, li, span, button, figcaption, strong) { letter-spacing: var(--track); }
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; height: auto; }

.icon { width: 20px; height: 20px; flex-shrink: 0; fill: currentColor; }
.icon--sm { width: 16px; height: 16px; }

/* Type scale — values from Figma 138:2 */
.t-display  { font-family: var(--font-primary); font-size: 44px; font-weight: 900; line-height: 1.05; letter-spacing: -0.0167em; color: var(--text-primary); }
.t-subtitle { font-size: 20px; font-weight: 600; line-height: 1.2; letter-spacing: -0.0475em; color: var(--text-muted); }
.t-title    { font-size: 18px; font-weight: 700; line-height: 1.22; color: var(--text-primary); }
.t-body     { font-size: 16px; font-weight: var(--w-body); line-height: 1.32; color: var(--text-muted); }
.t-small    { font-size: 14px; font-weight: 600; line-height: 1.28; color: var(--text-secondary); }
.t-label    { font-size: 14px; font-weight: 700; line-height: 1.2; color: var(--text-primary); }
.t-meta     { font-size: 13px; font-weight: var(--w-body); line-height: 1.2; color: var(--text-secondary); }
.t-meta :where(span) { letter-spacing: -0.031em; }

/* --------------------------------------------------------------------------
   Page shell + glass surfaces
   -------------------------------------------------------------------------- */

.page {
  width: 100%;
  max-width: calc(var(--page-width) + var(--page-pad-x) * 2);
  margin: 0 auto;
  padding: var(--page-pad-y) var(--page-pad-x);
  display: flex;
  flex-direction: column;
  gap: var(--stack-gap);
  /* Panels waiting to reveal sit 150px lower; clip vertically so they never extend the
     scroll height (horizontal stays visible for the glass shadows). */
  overflow-x: visible;
  overflow-y: clip;
}

/* Section panels are plain layout on the page; the nav bar is a grey content bar */
.nav {
  background: var(--surface-soft);
  border-radius: var(--radius-panel);
  box-shadow: inset 0 0 0 var(--hairline) var(--glass-rim-soft);
}

.panel {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* Cards inside panels: clear tint + rim, no second glass layer */
.card {
  background: var(--glass-inner);
  box-shadow: inset 0 0 0 var(--hairline) var(--glass-rim-soft), var(--card-shadow);
  border-radius: var(--radius-card);
  padding: 20px;
}

/* Section title ("Overview", "Projects" …) — a plain bold heading since Figma 138:47 */
.tag { align-self: flex-start; }
.tag .t-label {
  font-size: 20px;
  font-weight: 700;
  line-height: 16.8px;
  letter-spacing: 0;
  color: var(--text-primary);
}

/* Circular glass icon button (arrows) */
.icon-box {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: var(--glass-control);
  box-shadow: inset 0 0 0 var(--hairline) var(--glass-rim), inset 0 1px 0 0 var(--glass-specular);
  border-radius: 50%;
  color: var(--text-secondary);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

/* Glass capsule button */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 12px 16px 12px 14px;
  background: var(--btn-bg);
  box-shadow: inset 0 0 0 var(--hairline) var(--glass-rim);
  border-radius: 999px;
  color: var(--text-primary);
  font-size: 16px;
  font-weight: 600;
  line-height: 15px;
  white-space: nowrap;
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.btn .icon { width: 16px; height: 16px; color: var(--text-secondary); }
.btn .icon--stroke { fill: none; color: currentColor; }
.btn--icon-end { padding: 12px 14px 12px 16px; }

/* --------------------------------------------------------------------------
   Navigation bar
   -------------------------------------------------------------------------- */

.nav {
  margin-bottom: calc(var(--nav-gap) - var(--stack-gap));   /* the bar sits close to the hero */
  height: 60px;
  padding: 20px;
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--text-secondary);
}
.nav :where(p, span) { letter-spacing: -0.0357em; }
.nav__place { display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0; }
.nav__time  { flex: 1; text-align: right; font-variant-numeric: tabular-nums; }
.theme-toggle {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-left: 4px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
}
.theme-toggle .icon { width: 19px; height: 19px; }
/* Icon shows the current theme: moon in dark, sun in light (as on the original) */
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
}

/* --------------------------------------------------------------------------
   Home — hero
   -------------------------------------------------------------------------- */

.hero { flex-direction: row; gap: 32px; }
.hero__photo { width: 200px; height: 200px; border-radius: var(--radius-card); object-fit: cover; flex-shrink: 0; }
.hero__body { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 19px; min-width: 0; }
/* "Available for Work": a dashed sticker, tipped 4° (Figma 138:22) */
.status {
  align-self: flex-start;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 5px 0;
  padding: 8px 16px 8px 14px;
  border: 1px dashed var(--border-default);
  border-radius: 20px;
  rotate: -4deg;
  font-weight: 700;
  letter-spacing: -0.0357em;
}
.status__dot { width: 8px; height: 8px; border-radius: 4px; background: var(--status-available); }
.hero__names { display: flex; flex-direction: column; gap: 4px; }
.hero__actions { display: flex; gap: 10px; }

/* Overview */
.prose { display: flex; flex-direction: column; gap: 20px; }

/* --------------------------------------------------------------------------
   Grids & cards
   -------------------------------------------------------------------------- */

.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.grid-2:has(> .project-card) { gap: 20px; }
.stack  { display: flex; flex-direction: column; gap: 10px; }

/* Project card (Figma 138:85): the screen sits in a soft tile with a ↗ badge; title and scope below */
.project-card { display: flex; flex-direction: column; gap: 16px; }
.project-card__media {
  position: relative;
  display: block;
  aspect-ratio: 5 / 4;                     /* trimmed from ~1:1 (5 Nov) — the devices bleed, so less empty tile */
  border-radius: var(--radius-card);
  background: var(--surface-soft);
  overflow: hidden;
}
.project-card__img { width: 100%; height: 100%; object-fit: cover; }

/* Straight device mockups on the grey tile (Hanan's reference, 5 Nov): one device per project, rising from the
   bottom edge. Sized in container units so they scale with the tile. Web work sits in a browser window that runs
   off the right and bottom; apps in a phone, centred, bleeding off the bottom. */
.project-card__media, .case-cover { container-type: inline-size; }
.mock { position: absolute; display: block; transition: transform 400ms var(--ease-out); }
.mock img { display: block; width: 100%; height: auto; }
.mock--browser {
  left: 8cqw;
  top: 13cqw;
  width: 128cqw;
  border-radius: 2.6cqw 2.6cqw 0 0;
  overflow: hidden;
  background: var(--bg-page);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.06), 0 2cqw 6cqw -1.5cqw rgb(20 10 40 / 0.16);
}
/* Safari toolbar (6 Nov): everything is sized in em off the bar's font-size, so cards and case covers share it */
.mock__bar {
  display: flex;
  align-items: center;
  gap: 1.1em;
  height: 3.3em;
  padding: 0 1.3em;
  font-size: 1.45cqw;
  background: var(--safari-bar);
  border-bottom: 1px solid var(--safari-line);
  color: var(--safari-icon);
}
.mock__bar svg { display: block; width: 1.25em; height: 1.25em; flex-shrink: 0; }
.mock__lights { display: flex; gap: 0.55em; margin-right: 0.6em; }
.mock__lights i { width: 0.85em; height: 0.85em; border-radius: 50%; background: #ff5f57; box-shadow: inset 0 0 0 0.06em rgb(0 0 0 / 0.12); }
.mock__lights i:nth-child(2) { background: #febc2e; }
.mock__lights i:nth-child(3) { background: #28c840; }
.mock__tools { display: flex; align-items: center; gap: 1em; }
.mock__url {
  flex: 0 1 46%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  height: 2.1em;
  margin: 0 auto;
  border-radius: 0.6em;
  background: var(--safari-field);
}
.mock__url svg { width: 1em; height: 1em; opacity: 0.8; }
.mock__url b { width: 9em; height: 0.55em; border-radius: 1em; background: currentColor; opacity: 0.25; }
.mock--phone {
  --w: 50cqw;                              /* phone width and bezel; the Dynamic Island is derived from them */
  --pad: 1.6cqw;
  left: 50%;
  top: 8cqw;
  width: var(--w);
  translate: -50% 0;
  padding: var(--pad);
  border-radius: 8.4cqw;
  background: #111114;
  box-shadow: 0 0 0 0.5cqw #d8d8de, 0 0 0 0.75cqw #bdbdc6, 0 3cqw 7cqw -2cqw rgb(20 10 40 / 0.28);
}
.mock--phone img { border-radius: 6.9cqw; }
/* iOS status bar over a phone screen captured without one (the Visit Qatar landing; tools/statusbar.py) */
.mock--phone .mock__sb { position: absolute; z-index: 2; left: var(--pad); top: var(--pad); width: calc(var(--w) - 2 * var(--pad)); height: auto; border-radius: 0; }
/* iPhone 16 Dynamic Island: 126×37pt, 11pt from the top of a 393pt-wide screen (the Figma frames leave that
   space empty between the time and the status icons) */
.mock__island {
  position: absolute;
  z-index: 1;
  left: 50%;
  translate: -50% 0;
  top: calc(var(--pad) + (var(--w) - 2 * var(--pad)) * 0.028);
  width: calc((var(--w) - 2 * var(--pad)) * 0.32);
  height: calc((var(--w) - 2 * var(--pad)) * 0.094);
  border-radius: 999px;
  background: #000;
}
/* MacBook (project cards, 6 Nov): black lid with a thin aluminium edge and camera, placed like the browser window
   it replaces (the silver base sits below the tile, out of view) */
.mock--laptop { left: 8cqw; top: 13cqw; width: 128cqw; }   /* same placement as the browser window: runs off the right and bottom */
.mock__lid {
  position: relative;
  display: block;
  padding: 1.7cqw;
  border-radius: 3cqw 3cqw 0.5cqw 0.5cqw;
  background: #0d0d0f;
  box-shadow: 0 0 0 0.28cqw #c7c8cc, inset 0 0 0 0.12cqw #2c2c31;
}
.mock__lid::before {
  content: "";
  position: absolute;
  top: 0.55cqw;
  left: 50%;
  width: 0.55cqw;
  height: 0.55cqw;
  translate: -50% 0;
  border-radius: 50%;
  background: #2a2b31;
}
.mock__screen { display: block; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 0.4cqw; background: #000; }
.mock--laptop .mock__screen img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.mock__base {
  position: relative;
  display: block;
  height: 2.6cqw;
  border-radius: 0.3cqw 0.3cqw 2.4cqw 2.4cqw / 0.3cqw 0.3cqw 1.8cqw 1.8cqw;
  background: linear-gradient(to bottom, #f1f2f4 0%, #d6d7da 40%, #b4b6bb 85%, #8f9196 100%);
  box-shadow: 0 2.6cqw 5cqw -2cqw rgb(20 10 40 / 0.32);
}
.mock__base::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 15cqw;
  height: 0.9cqw;
  translate: -50% 0;
  border-radius: 0 0 1.2cqw 1.2cqw;
  background: linear-gradient(to bottom, #b9bbbf, #d3d4d7);
}
.project-card__go {
  position: absolute;
  right: 16px;
  bottom: 15px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 16px;
  background: var(--surface-raised);
  color: var(--text-primary);
  filter: drop-shadow(0 3.2px 4px rgb(0 0 0 / 0.04));
}
.project-card__text { display: flex; flex-direction: column; gap: 4px; padding: 0 16px; }

/* Experience / education */
.entry { display: flex; gap: 20px; }
.entry__logo { width: 48px; height: 48px; border-radius: 12px; flex-shrink: 0; border: 1.2px solid var(--border-subtle); }
.entry__body { display: flex; flex-direction: column; gap: 20px; min-width: 0; flex: 1; }
.entry__head { display: flex; flex-direction: column; gap: 6px; }
.entry__meta { display: flex; flex-wrap: wrap; gap: 10px 20px; }
.meta-item { display: inline-flex; align-items: center; gap: 5px; color: var(--text-secondary); }
.entry__list { margin: 0; padding-left: 24px; list-style: disc; }

/* Certification */
.cert { display: flex; align-items: center; gap: 16px; }
.cert__icon { width: 64px; height: 64px; flex-shrink: 0; margin: -6px 0; object-fit: contain; }   /* 3dicons gradient (6 Nov) */
.cert__go { margin-left: auto; }
.cert__body { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.cert__date { display: inline-flex; align-items: center; gap: 5px; color: var(--text-secondary); }

/* Tools */
.tool { display: flex; align-items: center; gap: 20px; min-height: 100px; }
.tool__icon { width: 44px; height: 44px; border-radius: 7.333px; flex-shrink: 0; box-shadow: 0 0 0 0.733px var(--icon-rim); }
.tool__text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

/* Tools layout variations (6 Nov). Only the one named in <html data-tools> shows (?tools=… to preview). */
.tools-v { display: none !important; }
[data-tools="grid"] .tools-v--grid { display: grid !important; }
[data-tools="dock"] .tools-v--dock { display: grid !important; }
[data-tools="groups"] .tools-v--groups { display: flex !important; }
[data-tools="list"] .tools-v--list { display: flex !important; }

/* A · Dock: one card, a row of app tiles (like the macOS dock) */
.dock { grid-template-columns: repeat(6, 1fr); gap: 8px; padding: 24px 12px 20px; }
.dock__item { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 4px; border-radius: 16px; text-align: center; color: inherit; text-decoration: none; }
.dock__icon { width: 56px; height: 56px; border-radius: 12.6px; object-fit: cover; box-shadow: 0 6px 14px -8px rgb(20 10 40 / 0.35); margin-bottom: 8px;   /* no rim (Hanan, 6 Nov); every icon is a full-bleed square, the radius makes the squircle */ transition: transform 380ms cubic-bezier(0.34, 1.56, 0.64, 1); }
.dock__name { font-size: 15px; font-weight: 700; color: var(--text-primary); }
.dock__kind { font-size: 13px; font-weight: var(--w-body); color: var(--text-muted); }
@media (hover: hover) and (pointer: fine) { .dock__item:hover .dock__icon { transform: translateY(-6px) scale(1.06); } }
/* Dark mode: Figma's near-black tile disappears into the card, so it swaps to a lifted grey copy (Hanan, 6 Nov) */
:root[data-theme="dark"] .dock__icon[src$="tool-figma.svg"] { content: url("../images/tool-figma-dark.svg"); }

/* B · Groups: what the tools are for, as two cards of chips */
.toolgroup { display: flex; flex-direction: column; gap: 16px; }
.toolgroup__chips { display: flex; flex-wrap: wrap; gap: 10px; }
.toolchip { display: inline-flex; align-items: center; gap: 10px; padding: 8px 16px 8px 8px; border-radius: 999px; background: var(--toolchip-bg); color: var(--text-primary); font-size: 15px; font-weight: 600; text-decoration: none; transition: background-color 200ms ease, transform 200ms var(--ease-out); }
.toolchip img { width: 28px; height: 28px; border-radius: 7px; box-shadow: 0 0 0 0.6px var(--icon-rim); }
@media (hover: hover) and (pointer: fine) { .toolchip:hover { transform: translateY(-2px); } }

/* C · List: one card, compact rows (like a settings list) */
.toollist { flex-direction: column; gap: 2px; padding: 8px; }
.toolrow { display: grid; grid-template-columns: 36px 1fr auto 16px; align-items: center; gap: 14px; padding: 10px 12px; border-radius: 14px; color: inherit; text-decoration: none; transition: background-color 200ms ease; }
.toolrow__icon { width: 36px; height: 36px; border-radius: 8px; box-shadow: 0 0 0 0.6px var(--icon-rim); }
.toolrow__name { font-size: 16px; font-weight: 700; color: var(--text-primary); }
.toolrow__kind { font-size: 14px; font-weight: var(--w-body); color: var(--text-muted); }
.toolrow__go { color: var(--text-muted); opacity: 0; transition: opacity 200ms ease, transform var(--spring-tilt-duration) var(--spring-tilt); }
@media (hover: hover) and (pointer: fine) {
  .toolrow:hover { background: var(--toolchip-bg); }
  .toolrow:hover .toolrow__go { opacity: 1; transform: rotate(45deg); }
}
@media (max-width: 640px) {
  .dock { grid-template-columns: repeat(3, 1fr); row-gap: 16px; }
}

/* Contact (footer) */
.contact { display: flex; align-items: center; gap: 20px; }
.contact { min-height: 80px; }
.contact__label { flex: 1; min-width: 0; font-weight: 600; color: var(--text-secondary); }
/* The résumé row is outlined, not filled (Figma 138:302) */
.contact--outline { background: transparent; box-shadow: none; border: 1px dashed var(--border-default); }
.contact--outline .icon-box { background: var(--glass-inner); }
.contact__value { flex: 1; min-width: 0; text-align: right; margin-right: 20px; overflow-wrap: anywhere; }
.contact-list { display: flex; flex-direction: column; gap: 10px; }
.footer__credit { text-align: center; letter-spacing: -0.0357em; }
.footer__credit a { color: var(--text-secondary); }

/* --------------------------------------------------------------------------
   Project page
   -------------------------------------------------------------------------- */

.project-head { display: flex; align-items: center; justify-content: space-between; gap: 20px; }
.btn--icon-end .icon { order: 2; }

/* Case study — editorial layout: full-bleed grey cover, chips + title + fact boxes,
   then sections that open with a label or a bold lead line and run their media full width. */
.case-hero {
  background: var(--glass-inner);
  padding: 24px 24px 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.case-hero__bar {
  width: 100%;
  max-width: var(--case-width);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.case-hero .btn { background: var(--bg-page); }
@media (hover: hover) and (pointer: fine) { .case-hero .btn:hover { background: var(--glass-control-hover); } }
.case-hero__back { padding: 12px 18px 12px 12px; }
.case-hero__back .icon { width: 18px; height: 18px; color: var(--text-secondary); }
.case-hero__theme.theme-toggle {
  width: 40px;
  height: 40px;
  margin: 0;
  background: var(--bg-page);
  box-shadow: inset 0 0 0 var(--hairline) var(--glass-rim);
  border-radius: 50%;
}
.case-hero__theme .icon { width: 18px; height: 18px; }
.case-cover {
  position: relative;
  width: min(var(--case-width), 100%);
  margin-top: 40px;
  overflow: hidden;
}
.case-cover--browser { aspect-ratio: 880 / 470; }
.case-cover--browser .mock--browser { left: 0; top: 0; width: 100%; border-radius: 1.6cqw 1.6cqw 0 0; }
.case-cover--browser .mock__bar { font-size: 0.97cqw; }
.case-cover--phone { aspect-ratio: 880 / 520; }
.case-cover--phone .mock--phone { --w: 36cqw; --pad: 1.1cqw; top: 3cqw; border-radius: 5.6cqw; box-shadow: 0 0 0 0.35cqw #d8d8de, 0 0 0 0.5cqw #bdbdc6, 0 2cqw 5cqw -1.5cqw rgb(20 10 40 / 0.28); }
.case-cover--phone .mock--phone img { border-radius: 4.6cqw; }
/* video cover (AGS, 7 Nov): the screen recording sits on the band's bottom edge like the mockups */
.case-cover--video video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; background: #0b0b0d; border-radius: var(--radius-card) var(--radius-card) 0 0; }
@supports (corner-shape: squircle) { :root[data-corners="smooth"] .case-cover--video video { corner-shape: squircle; } }
.case-hero__img {
  display: block;
  width: min(680px, 100%);
  height: auto;
  margin-top: 40px;
  border-radius: var(--radius-card) var(--radius-card) 0 0;
}

.page--case { max-width: calc(var(--case-width) + var(--page-pad-x) * 2); gap: 72px; padding-top: 56px; }

.case-intro { display: flex; flex-direction: column; gap: 20px; }
.chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  padding: 8px 14px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--chip-rim);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text-secondary);
}
.case-title { font-size: 38px; font-weight: 800; line-height: 1.1; color: var(--text-primary); max-width: var(--case-text); }
.case-facts { display: grid; grid-template-columns: repeat(4, auto); gap: 10px; margin-top: 8px; }   /* columns size to their content (was fixed ratios), so short facts stay on one line */
.case-fact { padding: 18px 20px; display: flex; flex-direction: column; gap: 8px; border-radius: 16px; }
.case-fact__k { font-size: 12px; font-weight: 700; line-height: 1.2; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-muted); }
.case-fact__v { font-size: 16px; font-weight: 600; line-height: 1.3; color: var(--text-primary); }

.case-section { display: flex; flex-direction: column; gap: 28px; }
.case-section--media-only { margin-top: -44px; }   /* a second screen continues the section above it */
.case-copy { display: flex; flex-direction: column; gap: 14px; max-width: var(--case-text); }
.case-label { font-size: 20px; font-weight: 800; line-height: 1.2; color: var(--text-primary); }
.case-lead { font-size: 24px; font-weight: 600; line-height: 1.25; color: var(--text-muted); text-wrap: pretty; }
.case-lead strong { font-weight: 800; color: var(--text-primary); }
.case-body { font-size: 17px; font-weight: var(--w-body); line-height: 1.5; color: var(--text-muted); text-wrap: pretty; }
.case-list { margin: 0; padding-left: 1.2em; display: flex; flex-direction: column; gap: 6px; }

.case-section img,
.case-section video { display: block; width: 100%; height: auto; border-radius: var(--radius-card); background: var(--glass-inner); }
.case-media--2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; align-items: start; }
.back { align-self: flex-start; }

/* 404 */
.not-found { align-items: center; text-align: center; padding: 80px 20px; gap: 20px; }
.not-found__code { font-size: 96px; line-height: 1; letter-spacing: -0.04em; color: var(--text-primary); }

/* --------------------------------------------------------------------------
   Progressive blur — pinned to the bottom quarter of the viewport, as on the Framer site:
   eight backdrop blurs doubling from 0.04px to 5px, each masked to its own band (Figma 147:4).
   Content sharpens as it scrolls up out of it. Fades away once the footer/game is reached.
   -------------------------------------------------------------------------- */
.pblur {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 25vh;
  z-index: 40;
  pointer-events: none;
  transition: opacity 300ms ease;
}
.pblur > i { position: absolute; inset: 0; }
.pblur > i:nth-child(1) { backdrop-filter: blur(0.0390625px); -webkit-backdrop-filter: blur(0.0390625px); mask-image: linear-gradient(to bottom, #0000 0%, #000 12.5%, #000 25%, #0000 37.5%); }
.pblur > i:nth-child(2) { backdrop-filter: blur(0.078125px); -webkit-backdrop-filter: blur(0.078125px); mask-image: linear-gradient(to bottom, #0000 12.5%, #000 25%, #000 37.5%, #0000 50%); }
.pblur > i:nth-child(3) { backdrop-filter: blur(0.15625px); -webkit-backdrop-filter: blur(0.15625px); mask-image: linear-gradient(to bottom, #0000 25%, #000 37.5%, #000 50%, #0000 62.5%); }
.pblur > i:nth-child(4) { backdrop-filter: blur(0.3125px); -webkit-backdrop-filter: blur(0.3125px); mask-image: linear-gradient(to bottom, #0000 37.5%, #000 50%, #000 62.5%, #0000 75%); }
.pblur > i:nth-child(5) { backdrop-filter: blur(0.625px); -webkit-backdrop-filter: blur(0.625px); mask-image: linear-gradient(to bottom, #0000 50%, #000 62.5%, #000 75%, #0000 87.5%); }
.pblur > i:nth-child(6) { backdrop-filter: blur(1.25px); -webkit-backdrop-filter: blur(1.25px); mask-image: linear-gradient(to bottom, #0000 62.5%, #000 75%, #000 87.5%, #0000 100%); }
.pblur > i:nth-child(7) { backdrop-filter: blur(2.5px); -webkit-backdrop-filter: blur(2.5px); mask-image: linear-gradient(to bottom, #0000 75%, #000 87.5%, #000 100%); }
.pblur > i:nth-child(8) { backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); mask-image: linear-gradient(to bottom, #0000 87.5%, #000 100%); }
.at-end .pblur { opacity: 0; visibility: hidden; transition: opacity 300ms ease, visibility 0s linear 300ms; }

/* --------------------------------------------------------------------------
   End stage — the footer (Figma 147:216) and Doha Run share one pinned screen. Scrolling on, the
   footer's cards dissolve into the sunset and the window opens out into the game (runner.js drives it).
   Mobile first: phones get the stacked footer; the cards sit side by side from 810px.
   -------------------------------------------------------------------------- */
/* The end stage is the footer's own band. At the bottom of the page, scrolling on (or swiping up) plays the
   morph into the game in place; scrolling back up plays it back (runner.js). */
.endstage { position: relative; margin-top: calc(-1 * var(--page-pad-y)); }
.endstage__dock {
  position: relative;
  /* the footer's own area (80px above the cards, as in Figma — room for the bot's perch); the game fills it */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-top: 80px;
  overflow: clip;
}
/* The white page ends here with rounded corners (the reference); the game shows behind them */
.endstage__lip {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: 3;
  height: 40px;
  border-radius: 0 0 40px 40px;
  background: var(--bg-page);
  pointer-events: none;
}
.runner {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  background: transparent;
  pointer-events: none;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  will-change: clip-path, opacity;
}
.runner.is-live { pointer-events: auto; }
.site-footer { z-index: 2; }
.runner__canvas {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
  image-rendering: pixelated;
  opacity: 0;
  will-change: transform, opacity;
}
/* The game's night: the brand card's own texture at the band's size. The expanding window reveals it, and it
   stays as the top of the sky above the sunset (the canvas sky is transparent up there). */
.runner__night {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: url("../images/footer-night.jpg") center 82% / cover, var(--night-base);
  background-blend-mode: luminosity, normal;
  pointer-events: none;
}
.runner__hud, .runner__hint, .runner__controls { z-index: 2; }
/* The veil: an exact copy of the brand card, sitting under it. It never resizes (no stretched stars); it hands
   the card over to the night and fades as the window opens. runner.js places it once per layout. */
.runner__veil {
  position: absolute;
  z-index: 0;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  border-radius: 24px;
  will-change: opacity;
  background: url("../images/footer-night.jpg") 0 23.6% / 100% 153.62%, var(--night-base);
  background-blend-mode: luminosity, normal;
  box-shadow:
    inset 0 -20px 50px -20px var(--night-glow),
    inset 0 -8px 15px -2px var(--night-rim),
    inset 0 120px 100px -8px var(--night-top),
    inset 0 -30px 50px -30px var(--night-deep);
  pointer-events: none;
}
.runner__hud { position: absolute; top: 56px; right: 20px; display: flex; gap: 6px; }
.runner__chip {
  padding: 6px 10px;
  border-radius: 8px;
  /* --day (runner.js, 0–1): by day the sky is pale, so the chip gains a violet wash to keep its white text readable */
  background: linear-gradient(rgb(40 22 92 / calc(var(--day, 0) * 0.42)) 0 0), rgb(255 255 255 / 0.16);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.runner__hint {
  position: absolute;
  left: 50%;
  top: 18%;
  translate: -50% 0;
  padding: 10px 16px;
  border-radius: 999px;
  background: linear-gradient(rgb(40 22 92 / calc(var(--day, 0) * 0.42)) 0 0), rgb(255 255 255 / 0.16);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: opacity 240ms var(--ease-out);
}
.runner__hint[hidden] { display: block; opacity: 0; }
/* Controls, shown before the first run — up in the sky on phones, so the skyline stays in view */
.runner__controls {
  position: absolute;
  left: 50%;
  top: 34%;
  translate: -50% -50%;
  width: min(360px, calc(100% - 32px));
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 22px 22px 18px;
  border-radius: 20px;
  background: rgb(20 8 46 / 0.62);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.14);
  color: #fff;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: opacity 260ms var(--ease-out), scale 260ms var(--ease-out);
}
.runner__controls[hidden] { display: flex; opacity: 0; scale: 0.97; pointer-events: none; }
@media (min-width: 810px) { .runner__controls { top: 46%; } }
.runner__title { font-size: 20px; font-weight: 800; }
.runner__keys { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.runner__keys li { display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 600; color: rgb(255 255 255 / 0.85); }
.runner__keys li > span:last-child { margin-left: 6px; }
.runner__kbd {
  min-width: 30px;
  padding: 5px 9px;
  border-radius: 7px;
  background: rgb(255 255 255 / 0.12);
  box-shadow: inset 0 -2px 0 rgb(0 0 0 / 0.35), inset 0 0 0 1px rgb(255 255 255 / 0.2);
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  color: #fff;
}
.runner__note { font-size: 13px; line-height: 1.4; color: rgb(255 255 255 / 0.7); }
.runner__start { padding-top: 12px; border-top: 1px solid rgb(255 255 255 / 0.14); font-size: 14px; font-weight: 700; color: #ffd27a; }
.runner__controls[data-touch-ui] [data-fine],
.runner__controls:not([data-touch-ui]) [data-touch] { display: none; }

.site-footer {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding: 0 16px;
  transform-origin: 50% 100%;
}
.site-footer__cols { position: relative; width: 100%; max-width: var(--page-width); display: flex; flex-direction: column; gap: 12px; }
.site-footer__brand {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "mark social" "role social";
  align-items: end;
  gap: 6px 16px;
  padding: 24px;
  border-radius: 24px;
  color: #fff;
  /* night texture over #0a011f in luminosity, placed as in Figma 153:320 */
  background: url("../images/footer-night.jpg") 0 23.6% / 100% 153.62%, var(--night-base);
  background-blend-mode: luminosity, normal;
  box-shadow:
    inset 0 -20px 50px -20px var(--night-glow),
    inset 0 -8px 15px -2px var(--night-rim),
    inset 0 120px 100px -8px var(--night-top),
    inset 0 -30px 50px -30px var(--night-deep);
}
.site-footer__mark { grid-area: mark; font-size: 34px; font-weight: 900; line-height: 1.05; letter-spacing: -0.0167em; white-space: nowrap; }
.site-footer__role { grid-area: role; font-size: 16px; font-weight: 600; color: rgb(255 255 255 / 0.8); }
.site-footer__social { grid-area: social; display: flex; gap: 12px; align-self: end; }
.site-footer__circle {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.4);
  color: #fff;
  transition: background-color 200ms ease;
}
.site-footer__circle .icon--stroke { width: 20px; height: 20px; fill: none; }
.site-footer__panel {
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding: 28px 20px 24px;
  border-radius: 24px;
  background: var(--glass-inner);
}
.site-footer__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 16px; }
.site-footer__h { font-size: 18px; font-weight: 700; line-height: 16.8px; color: var(--text-primary); }
.site-footer__grid ul { list-style: none; margin: 16px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.site-footer__grid a { display: inline-block; padding: 4px 0; font-size: 15px; font-weight: 600; line-height: 1.2; color: var(--text-secondary); transition: color 200ms ease; }
.site-footer__legal { font-size: 15px; font-weight: 600; color: var(--text-secondary); }
.site-footer__hello { display: flex; flex-direction: column; gap: 16px; }
.site-footer__pill { display: flex; align-items: center; gap: 12px; padding: 6px 6px 6px 16px; border: 1px solid var(--border-subtle); border-radius: 16px; background: var(--bg-page); }
.site-footer__pill a { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; color: var(--text-secondary); }
.site-footer__copy { flex: none; padding: 12px 20px; border: 0; border-radius: 12px; background: var(--text-primary); color: var(--bg-page); font-size: 15px; font-weight: 600; cursor: pointer; }
.site-footer__wordmark {
  margin: 0;
  width: 100%;
  max-width: var(--page-width);
  text-align: center;
  font-size: min(110px, calc((100vw - 32px) * 0.1447));   /* 110px across the 760px column (Figma 153:384) */
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;    /* as in Figma: the band's bottom edge crops the "y" descender */
  color: transparent;
  background: linear-gradient(to bottom, #ececec, #fbfbfb);
  -webkit-background-clip: text;
  background-clip: text;
  user-select: none;
}
:root[data-theme="dark"] .site-footer__wordmark { background-image: linear-gradient(to bottom, rgb(255 255 255 / 0.09), rgb(255 255 255 / 0.02)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-footer__wordmark { background-image: linear-gradient(to bottom, rgb(255 255 255 / 0.09), rgb(255 255 255 / 0.02)); }
}

/* The easter egg's hint: after a moment at the very bottom, a quiet line under the cards with a small pixel
   chevron (the game's own pixel style) — it suggests there is more without saying what. runner.js shows it. */
.site-footer__hint {
  position: absolute;
  left: 50%;
  top: calc(100% + 8px);
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 16px;
  white-space: nowrap;
  color: var(--text-muted);
  pointer-events: none;
  opacity: 0;
  translate: -50% 4px;
  transition: opacity 500ms var(--ease-out), translate 500ms var(--ease-out);
}
.site-footer__hint.is-shown { opacity: 1; translate: -50% 0; }
.site-footer__hint i {                     /* a 5×3 pixel chevron in 2px pixels */
  position: relative;
  width: 10px;
  height: 6px;
  flex: none;
}
.site-footer__hint i::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 2px;
  background: currentColor;
  box-shadow: 8px 0 currentColor, 2px 2px currentColor, 6px 2px currentColor, 4px 4px currentColor;
  animation: hint-nudge 1.6s steps(1, end) infinite;
}
@keyframes hint-nudge { 0% { transform: translateY(0); } 50% { transform: translateY(2px); } }
@media (min-width: 810px) { .site-footer__hint { top: calc(100% + 12px); } }
@media (prefers-reduced-motion: reduce) {
  .site-footer__hint { translate: -50% 0; transition: opacity 300ms ease; }
  .site-footer__hint i::before { animation: none; }
}

/* Tablet and up (Figma 153:318): both cards in the 760px column, 413px tall */
@media (min-width: 810px) {
  .site-footer { gap: 40px; padding: 0 24px; }
  .site-footer__cols { flex-direction: row; gap: 16px; }
  .site-footer__brand {
    flex: 0 0 273px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
    min-height: 413px;
    padding: 32px 24px 24px;
  }
  .site-footer__mark { font-size: 38px; line-height: 36px; }
  .site-footer__role { font-size: 18px; flex: 1; }
  .site-footer__social { align-self: flex-start; }
  .site-footer__panel { flex: 1 1 0; min-width: 0; min-height: 413px; gap: 24px; padding: 32px 24px 24px; }
  .site-footer__grid { grid-template-columns: 1fr; }
  .site-footer__h { font-size: 20px; }
  .site-footer__grid a { font-size: 16px; }
  .site-footer__legal { margin-top: auto; font-size: 16px; }
}

/* The bot: one element for its whole life — beside the cursor, in flight, then the runner.
   runner.js writes its transform every frame; it is rendered at 224px (its perch size on the footer)
   and only ever scaled down — 32px beside the cursor, 72px as the runner — so it stays sharp. */
.bot {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2147483646;
  width: 224px;
  height: 224px;
  pointer-events: none;
  transform-origin: 50% 50%;
  opacity: 0;
  transition: opacity 150ms ease;
  will-change: transform;
}
.bot.is-visible { opacity: 1; }
.bot > div, .bot canvas { display: block; width: 224px; height: 224px; }
.bot--tag { width: 64px; height: 64px; }
.bot.bot--tag > div { width: 64px; height: 64px; }

/* ==========================================================================
   Motion
   ========================================================================== */

/* Hover — colour feedback only, and only on devices that really hover */
a.card,
.btn,
.icon-box,
.footer__credit a { transition: background-color 200ms ease, color 200ms ease, transform 160ms var(--ease-out); }
.card .icon-box .icon { transition: transform var(--spring-tilt-duration) var(--spring-tilt); }
.icon-box .icon-arrow-up-right, .toolrow__go { transition: transform 360ms var(--ease-out), opacity 200ms ease; }

@media (hover: hover) and (pointer: fine) {
  a.card:hover { background: var(--glass-inner-hover); }
  .btn:hover { background: var(--btn-bg-hover); }
  a.icon-box:hover { background: var(--glass-control-hover); }
  a.card:hover .icon-box { background: var(--glass-control-hover); }
  a.card:hover .icon-box .icon { transform: translateX(2px); }
  a.card:hover .icon-box .icon-arrow-up-right { transform: rotate(45deg); }   /* every ↗ link icon turns to → on hover, like the project cards (Hanan, 6 Nov) */
  .footer__credit a:hover { color: var(--text-primary); }
  .project-card:hover .project-card__img { transform: scale(1.02); }
  .project-card:hover .mock { transform: translateY(-1.5cqw); }
  .project-card:hover .project-card__go .icon { transform: rotate(45deg); }   /* ↗ turns to → on hover (Hanan, 6 Nov) */
  .site-footer__grid a:hover { color: var(--text-primary); }
  .site-footer__circle:hover { background: rgb(255 255 255 / 0.08); }
}
.project-card__img,
.project-card__go { transition: transform var(--spring-snap-duration) var(--spring-snap); }
.project-card__go .icon { transition: transform var(--spring-tilt-duration) var(--spring-tilt); }
.site-footer__copy:active { transform: scale(0.97); }

/* Press — instant physical feedback */
.btn:active,
a.icon-box:active,
.theme-toggle:active { transform: scale(0.97); }
.theme-toggle { transition: transform 160ms var(--ease-out); }

/* Appear on load / reveal on scroll — the original's spring.
   Hidden states only apply once JS has armed them (html.js); a failsafe reveals
   everything if main.js never runs. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(150px);
}
.js [data-reveal="down"] { transform: translateY(-150px); }
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--spring-appear-duration) var(--spring-appear),
    transform var(--spring-appear-duration) var(--spring-appear);
  transition-delay: var(--reveal-delay, 0ms);
}

/* Lists inside a revealed panel settle in one after another */
.js [data-stagger] > * {
  opacity: 0;
  transform: translateY(8px);
}
.js [data-stagger].is-in > * {
  opacity: 1;
  transform: none;
  transition: opacity 300ms var(--ease-out), transform 300ms var(--ease-out);
  transition-delay: calc(var(--stagger-base, 0ms) + var(--i, 0) * 50ms);
}

/* Project gallery images wipe in as they scroll into view */
.js [data-reveal="wipe"] {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 100% 0 round var(--radius-card));
}
.js [data-reveal="wipe"].is-in {
  clip-path: inset(0 0 0 0 round var(--radius-card));
  transition: clip-path 600ms var(--ease-in-out);
}

/* Failsafe: if main.js never arms the reveals, show everything */
.js:not(.reveal-armed) [data-reveal],
.js:not(.reveal-armed) [data-stagger] > * { animation: reveal-failsafe 0s 1.5s forwards; }
@keyframes reveal-failsafe { to { opacity: 1; transform: none; clip-path: none; } }

/* Multiplayer cursor (main.js) — macOS arrow; the bot avatar rides beside it as its name tag (runner.js).
   Follows the pointer 1:1 (no easing lag); only state changes animate. */
.cursor-on,
.cursor-on * { cursor: none !important; }
.cursor {
  --cursor-accent: #0071e3;          /* Apple link blue */
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2147483647;
  pointer-events: none;
  opacity: 0;
  transition: opacity 150ms ease;
  will-change: transform;
}
.cursor.is-visible { opacity: 1; }
.cursor__arrow {
  position: absolute;
  left: -5.5px;                      /* put the arrow's tip on the hotspot */
  top: -3px;
  display: block;
  overflow: visible;
  transform-origin: 5.5px 3px;
  transition: transform 120ms var(--ease-out);
  filter: drop-shadow(0 1px 1.5px rgb(0 0 0 / 0.25));
}
.cursor__arrow path {
  fill: #000;
  stroke: #fff;
  stroke-width: 1.5;
  stroke-linejoin: round;
  transition: fill 150ms ease;
}
/* Over something clickable the arrow turns blue; pressing pushes it in */
.cursor.is-link .cursor__arrow path { fill: var(--cursor-accent); }
.cursor.is-down .cursor__arrow { transform: scale(0.9); }

/* Theme switch — a short crossfade via the View Transitions API (see main.js) */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 200ms; animation-timing-function: ease; }

/* Reduced motion: keep the fades, drop the movement */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal="down"],
  .js [data-stagger] > * { transform: none; }
  .js [data-reveal].is-in,
  .js [data-stagger].is-in > * { transition: opacity 200ms ease; transition-delay: 0ms; }
  .js [data-reveal="wipe"] { clip-path: none; opacity: 0; }
  .js [data-reveal="wipe"].is-in { opacity: 1; transition: opacity 200ms ease; }
  .btn:active,
  a.icon-box:active,
  .theme-toggle:active { transform: none; }
  a.card:hover .icon-box .icon { transform: none; }
  a.card:hover .icon-box .icon-arrow-up-right { transform: rotate(45deg); }   /* still turns, without the spin */
  .icon-box .icon-arrow-up-right, .toolrow__go { transition: none; }
  .cursor.is-down .cursor__arrow { transform: none; }
  .project-card:hover .project-card__img,
  .project-card:hover .mock,
  .project-card:hover .project-card__go { transform: none; }
  .project-card__go .icon { transition: none; }   /* still turns to →, just without the spin */
}

/* --------------------------------------------------------------------------
   Breakpoints (match the Framer site: desktop ≥1200, tablet 810–1199, mobile <810)
   -------------------------------------------------------------------------- */

@media (max-width: 1199.98px) {
  :root { --page-pad-y: 40px; }
}

@media (max-width: 809.98px) {
  :root { --page-pad-y: 16px; --page-pad-x: 16px; --stack-gap: 48px; }

  .t-display { font-size: 34px; }
  .t-subtitle { font-size: 18px; }
  .t-title { font-size: 17px; }
  .case-label { font-size: 18px; }


  .grid-2 { grid-template-columns: 1fr; }
  .case-media--2 { grid-template-columns: 1fr; }
  .case-hero { padding: 16px 16px 0; }
  .case-hero__img { margin-top: 28px; }
  .page--case { gap: 56px; padding-top: 32px; }
  .case-title { font-size: 28px; }
  /* 12 Nov: the Year cell takes only its width, so a longer role ("Senior UI/UX Designer") stays on one line. Was 1fr 1fr */
  .case-facts { grid-template-columns: auto minmax(0, 1fr); }
  .case-fact:first-child, .case-fact:last-child { grid-column: 1 / -1; }   /* phones: Client and the last fact (Type / Services) get a full row */
  .case-lead { font-size: 20px; }
  .case-section--media-only { margin-top: -40px; }

  .entry { flex-direction: column; }
  .entry__meta { flex-direction: column; gap: 10px; }

  .cert { gap: 12px; }   /* stays a row on small screens now that it has an icon and ↗ (was a column, 6 Nov) */
  /* 11 Nov (Hanan): three lines on phones (title, issuer, ID), the ID never cut short */
  .cert .cert__meta { flex-direction: column; align-items: flex-start; align-self: stretch; gap: 6px; text-align: left; }
  .cert .cert__id-v { overflow: visible; white-space: normal; overflow-wrap: anywhere; }
  .cert__icon { width: 52px; height: 52px; }
  /* 12 Nov (Hanan, mobile fixes #2): one row on phones, as on desktop. Was stacked:
     .contact { flex-direction: column; align-items: flex-start; gap: 10px; }
     .contact__value { text-align: left; margin-right: 0; }
     .contact .icon-box { margin-top: 10px; } */
  .contact { gap: 12px; min-height: 64px; padding-top: 12px; padding-bottom: 12px; }
  .contact__label { flex: 0 0 auto; }
  .contact__value { margin-right: 4px; font-size: 14px; }

  .project-head { flex-direction: column; align-items: flex-start; }

  .not-found__code { font-size: 64px; }
}
@media (max-width: 599.98px) {
  /* 11 Nov (Hanan): horizontal on phones as on desktop: a smaller photo beside the sticker, name and title, then both
     buttons in one row underneath. Was: stacked and centred, the photo full width (the photo filled the first screen):
     .hero { flex-direction: column; gap: 20px; text-align: center; } .hero__photo { width: 100%; height: auto; aspect-ratio: 1 / 1; }
     .hero__body { align-items: center; } .status { align-self: center; } .hero__actions { flex-direction: column; width: 100%; }
     .hero__actions .btn { width: 100%; } */
  /* 12 Nov (Hanan: "check the top spacing before available for work"): the sticker and name sat at the bottom of the
     photo, leaving a gap above; now centred on the photo as on desktop (an empty 1fr row above and below them).
     Was: grid-template-rows: 1fr auto auto; photo row 1 / span 2; status row 1, names row 2, actions row 3 */
  .hero { display: grid; grid-template-columns: clamp(104px, 30vw, 168px) minmax(0, 1fr); grid-template-rows: 1fr auto auto 1fr auto;
    column-gap: 16px; row-gap: 0; align-items: center; }
  .hero__photo { grid-column: 1; grid-row: 1 / span 4; width: 100%; height: auto; aspect-ratio: 1 / 1; }
  .hero__body { display: contents; }
  .hero__body > .status { grid-column: 2; grid-row: 2; align-self: end; justify-self: start; margin: 0 0 8px; padding: 5px 11px 5px 10px; gap: 7px; font-size: 13px; }
  .hero__names { grid-column: 2; grid-row: 3; align-self: start; }
  .hero__actions { grid-column: 1 / -1; grid-row: 5; width: 100%; margin-top: 20px; }
  .hero__actions .btn { flex: 1 1 0; min-width: 0; justify-content: center; padding-left: 10px; padding-right: 10px; white-space: nowrap; }
}
/* the smallest phones: a slightly bigger photo so the sticker and name still sit inside its height */
@media (max-width: 379.98px) { .hero { grid-template-columns: 38vw minmax(0, 1fr); } }

/* ™ as a small superscript (Urbanist draws a full-size TM; Gilroy's was small) */
.tm { font-size: 0.55em; vertical-align: 0.6em; line-height: 0; letter-spacing: 0; }

/* CUA badge angle variations (6 Nov): only the one named in <html data-cua> shows (?cua=… to preview) */
.cua-v { display: none; }
[data-cua="front"] .cua-v--front, [data-cua="three-quarter"] .cua-v--three-quarter, [data-cua="tilted-back"] .cua-v--tilted-back, [data-cua="dynamic"] .cua-v--dynamic, [data-cua="dynamic-right"] .cua-v--dynamic-right { display: block; }

/* ---------- Card corners: iOS-style smoothing (7 Nov, preview: ?corners=smooth) ----------
   CSS corner-shape (Chrome/Edge 139+) draws a squircle. Figma's 100% corner smoothing stretches the curve over
   about twice the radius, so the radii are scaled ~1.75x to match its look (20 -> 35, 32 -> 56, 24 -> 42).
   Browsers without corner-shape keep the plain rounded corners, so the radii only change where it's supported. */
@supports (corner-shape: squircle) {
  :root[data-corners="smooth"] { --radius-panel: 56px; --radius-card: 35px; --radius-project: 38px; }
  :root[data-corners="smooth"] :is(.nav, .card, .project-card__media, .hero__photo, .case-hero__img, .case-section video,
    .site-footer__brand, .site-footer__panel, .case-fact, .entry__logo, .dock__icon) { corner-shape: squircle; }
  :root[data-corners="smooth"] :is(.site-footer__brand, .site-footer__panel) { border-radius: 42px; }
  :root[data-corners="smooth"] .case-fact { border-radius: 28px; }
  :root[data-corners="smooth"] .entry__logo { border-radius: 21px; }
  :root[data-corners="smooth"] .dock__icon { border-radius: 22px; }
  /* the wipe reveal clips with a circular round-rect, which would shave the squircle: clip square instead */
  :root[data-corners="smooth"].js [data-reveal="wipe"] { clip-path: inset(0 0 100% 0); }
  :root[data-corners="smooth"].js [data-reveal="wipe"].is-in { clip-path: inset(0 0 0 0); }
}

/* ---------- Credential ID chip on certification cards (7 Nov) ---------- */
.cert__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-width: 0; }
.cert__id {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0;
  padding: 4px 10px 4px 8px;
  border: 1px dashed var(--border-default);   /* dashed, like the "Available for Work" sticker (Hanan, 7 Nov) */
  border-radius: 8px;
  font-size: 12px; line-height: 16px; font-weight: 600; color: var(--text-secondary);
  font-variant-numeric: tabular-nums; letter-spacing: 0.01em;
}
.cert__id-k { flex: none; padding-right: 6px; border-right: 1px dashed var(--border-default); color: var(--text-tertiary, var(--text-secondary)); opacity: 0.8; font-weight: 700; letter-spacing: 0.04em; }
.cert__id-v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@supports (corner-shape: squircle) { :root[data-corners="smooth"] .cert__id { corner-shape: squircle; border-radius: 14px; } }

/* ---------- Credential page (Google Digital Unlocked certificate, 7 Nov) ---------- */
.page--case.credential { padding-top: 32px; gap: 40px; }
.credential__bar .theme-toggle { width: 40px; height: 40px; margin: 0; }
.credential__sheet { margin: 0; padding: 12px; border-radius: var(--radius-card); background: var(--glass-inner); }
.credential__sheet img { display: block; width: 100%; height: auto; border-radius: calc(var(--radius-card) - 12px); }
.credential__note { display: flex; flex-direction: column; gap: 12px; padding: 24px; }
.credential__note .t-body { color: var(--text-secondary); max-width: 62ch; }
.credential__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }
.credential__actions .btn { background: var(--bg-page); }
@supports (corner-shape: squircle) {
  :root[data-corners="smooth"] :is(.credential__sheet, .credential__sheet img) { corner-shape: squircle; }
  :root[data-corners="smooth"] .credential__sheet img { border-radius: calc(var(--radius-card) - 6px); }
}

/* ---------- Section rules (Hanan's Figma 138:2, lines 157:2–157:48, 7 Nov; idea from the AGS landing page) ----------
   2px strokes, 8 on / 8 off, #fafafa, diamond caps. Two rails 44px outside the 760px column run from the top of the
   nav to 40px below the last section (main.js sets --rails-top/--rails-bottom); a horizontal rule spans rail to rail
   at the exact middle of the gap before each section from Overview on (none under the nav, none closing the page,
   none before a media-only case section, which continues the one above). The rules are their own elements
   (.page__rule, placed by main.js from layout offsets) so the sections' reveal motion never shifts them; the gaps
   themselves are Figma's: 64px between sections, 24px nav → intro, 80px top/bottom. Phones: no rails, rules span
   the column.
   Switch: data-rules="on|off" (SECTION_RULES in build-unti.py, ?rules=off to compare). */
:root {
  --rule: #fafafa; --rule-w: 2px; --rule-dash: 8px; --rule-cap-s: 6px; --rail-off: 44px;
  --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 6'%3E%3Cpath d='M3 0 6 3 3 6 0 3z' fill='%23fafafa'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] { --rule: rgb(255 255 255 / 0.05); --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 6'%3E%3Cpath d='M3 0 6 3 3 6 0 3z' fill='%23ffffff' fill-opacity='0.1'/%3E%3C/svg%3E"); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --rule: rgb(255 255 255 / 0.05); --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 6'%3E%3Cpath d='M3 0 6 3 3 6 0 3z' fill='%23ffffff' fill-opacity='0.1'/%3E%3C/svg%3E"); } }
:root[data-rules="on"] .page { position: relative; --rule-c: 0px; }
:root:not([data-rules="on"]) .page__rule { display: none; }
:root[data-rules="on"] .page__rule {   /* placed by main.js at the exact middle of each gap; static, so the reveal animations never move it */
  position: absolute; pointer-events: none; z-index: 0;
  top: calc(var(--y) - var(--rule-cap-s) / 2); height: var(--rule-cap-s);
  left: calc(var(--page-pad-x) - var(--rule-c) - var(--rule-cap-s) / 2 + var(--snap-x, 0px)); right: calc(var(--page-pad-x) - var(--rule-c) - var(--rule-cap-s) / 2 - var(--snap-x, 0px));
  background:
    var(--rule-cap) left center / var(--rule-cap-s) var(--rule-cap-s) no-repeat,
    var(--rule-cap) right center / var(--rule-cap-s) var(--rule-cap-s) no-repeat,
    repeating-linear-gradient(90deg, var(--rule) 0 var(--rule-dash), transparent var(--rule-dash) calc(var(--rule-dash) * 2))
      center / calc(100% - var(--rule-cap-s)) var(--rule-w) no-repeat;
}
@media (min-width: 900px) {
  :root[data-rules="on"] .page { --rule-c: var(--rail-off); }
  :root[data-rules="on"] .page::before, :root[data-rules="on"] .page::after {
    content: ""; position: absolute; pointer-events: none; z-index: 4;   /* above the end stage lip (z 3) */
    width: var(--rule-cap-s); top: calc(var(--rails-top, 0px) - var(--rule-cap-s) / 2); bottom: calc(var(--rails-bottom, 0px) - var(--rule-cap-s) / 2);
    background:
      var(--rule-cap) center top / var(--rule-cap-s) var(--rule-cap-s) no-repeat,
      var(--rule-cap) center bottom / var(--rule-cap-s) var(--rule-cap-s) no-repeat,
      repeating-linear-gradient(180deg, var(--rule) 0 var(--rule-dash), transparent var(--rule-dash) calc(var(--rule-dash) * 2))
        center / var(--rule-w) calc(100% - var(--rule-cap-s)) no-repeat;
  }
  :root[data-rules="on"] .page::before { left: calc(var(--page-pad-x) - var(--rule-c) - var(--rule-cap-s) / 2 + var(--snap-x, 0px)); }
  :root[data-rules="on"] .page::after { right: calc(var(--page-pad-x) - var(--rule-c) - var(--rule-cap-s) / 2 - var(--snap-x, 0px)); }
}

/* 12 Nov (Hanan, after Cloudflare's dashboard): the rules in Cloudflare's style. Finer, shorter dashes in a slightly
   stronger grey (the project tiles' grey family), and the nodes where lines meet are small hollow rounded squares
   instead of diamonds. Switch: data-rstyle = "cf" (default) | "diamond" (the 7 Nov style above), ?rstyle= to compare;
   ?rstyle=cf-a / cf-b are the two other weights that were tried. */
:root[data-rstyle^="cf"] { --rule: #efefef; --rule-w: 1.5px; --rule-dash: 5px; --rule-cap-s: 9px; --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'%3E%3Crect x='.5' y='.5' width='8' height='8' rx='1.5' fill='%23ffffff' stroke='%23e4e4e4'/%3E%3C/svg%3E"); }
:root[data-rstyle="cf-a"] { --rule: #f7f7f7; --rule-w: 2px; --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'%3E%3Crect x='.5' y='.5' width='8' height='8' rx='1.5' fill='%23ffffff' stroke='%23e8e8e8'/%3E%3C/svg%3E"); }
:root[data-rstyle="cf-b"] { --rule: #e9e9e9; --rule-w: 1px; --rule-dash: 4px; --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'%3E%3Crect x='.5' y='.5' width='8' height='8' rx='1.5' fill='%23ffffff' stroke='%23e0e0e0'/%3E%3C/svg%3E"); }
:root[data-theme="dark"][data-rstyle^="cf"] { --rule: rgb(255 255 255 / 0.09); --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'%3E%3Crect x='.5' y='.5' width='8' height='8' rx='1.5' fill='%23141414' stroke='%23ffffff' stroke-opacity='0.16'/%3E%3C/svg%3E"); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"])[data-rstyle^="cf"] { --rule: rgb(255 255 255 / 0.09); --rule-cap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'%3E%3Crect x='.5' y='.5' width='8' height='8' rx='1.5' fill='%23141414' stroke='%23ffffff' stroke-opacity='0.16'/%3E%3C/svg%3E"); } }
/* the hollow nodes sit over the rails, so a rail never shows through the square where the lines meet */
:root[data-rstyle^="cf"][data-rules="on"] .page__rule { z-index: 5; }

/* ---------- Case study v2: screens in grey frames (AGS, 9 Nov) ----------
   Flat Figma exports on the site's grey card surface instead of staged mockups. stage = rises from the frame's bottom
   edge; inset = even margin all round; scroll = a long page drifting slowly in a window while in view (pauses on
   hover, still for reduced motion); pair = two insets side by side. Captions under each frame. The design-system strip
   is one quiet frame of tokens, not a section of its own. */
:root { --frame-bg: #fafafa;   /* = the card surface (--glass-inner), Hanan 9 Nov: one fill for cards and frames; opaque so the match ring can sit on it */ --frame-shot: 0 0 0 1px rgb(0 0 0 / 0.05), 0 22px 44px -26px rgb(20 10 40 / 0.28); }
:root[data-theme="dark"] { --frame-bg: #222222; --frame-shot: 0 0 0 1px rgb(255 255 255 / 0.06), 0 22px 44px -26px rgb(0 0 0 / 0.6); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --frame-bg: #222222; --frame-shot: 0 0 0 1px rgb(255 255 255 / 0.06), 0 22px 44px -26px rgb(0 0 0 / 0.6); } }
.story-media { display: flex; flex-direction: column; gap: 32px; }
.frame { margin: 0; display: flex; flex-direction: column; gap: 12px; }
.frame__tile { position: relative; overflow: hidden; border-radius: var(--radius-card); background: var(--frame-bg); }
.frame__cap { padding-left: 4px; font-size: 13px; font-weight: 600; line-height: 1.3; color: var(--text-secondary); }
.case-section .frame img { border-radius: 0; background: none; }
.frame--stage .frame__tile, .frame--scroll .frame__tile, .frame--live .frame__tile { padding: 5.5% 5.5% 0; }   /* the live page sits on the grey frame like the other screens */
.case-section .frame--stage img { border-radius: 12px 12px 0 0; box-shadow: var(--frame-shot); }
.frame--inset .frame__tile { padding: 5.5%; }
.case-section .frame--inset img { border-radius: 10px; box-shadow: var(--frame-shot); }
.frame__window { aspect-ratio: 16 / 10; overflow: hidden; border-radius: 12px 12px 0 0; box-shadow: var(--frame-shot); background: #fff; }
.case-section .frame__window img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 0%; }
@keyframes frame-scroll { 0%, 6% { object-position: 50% 0%; } 94%, 100% { object-position: 50% 100%; } }
@media (prefers-reduced-motion: no-preference) {
  .frame--scroll.is-in .frame__window img { animation: frame-scroll 48s ease-in-out 1s infinite alternate; }
  .frame--scroll:hover .frame__window img { animation-play-state: paused; }
}
.frame-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-items: stretch; }
/* both frames in a pair share one height; each screen is centred in its tile */
.frame-pair .frame--inset .frame__tile { flex: 1; display: flex; align-items: center; justify-content: center; padding: 7%; }
@media (max-width: 700px) {
  .frame-pair { grid-template-columns: 1fr; gap: 24px; }
  .story-media { gap: 24px; }
  .case-section .frame--stage img, .frame__window { border-radius: 8px 8px 0 0; }
  .case-section .frame--inset img { border-radius: 6px; }
}
@supports (corner-shape: squircle) { :root[data-corners="smooth"] .frame__tile { corner-shape: squircle; } }

/* the design-system frame, mobile-first (9 Nov): everything stacks in one column on phones; from 640px Colour takes
   a full row and Type | Radius share the next, so nothing is squeezed at the 760px column. Dashed separators
   (the site's language) sit inset between the groups; the "In Use" row of components is last. */
.ds { display: flex; flex-direction: column; gap: 0; padding: 0; }
.ds ul { margin: 0; padding: 0; list-style: none; }
.ds__tokens { display: grid; grid-template-columns: 1fr; }
.ds__col { position: relative; display: flex; flex-direction: column; gap: 14px; min-width: 0; padding: 22px 24px; }
.ds__col + .ds__col::before, .ds__comps::before { content: ""; position: absolute; top: 0; left: 24px; right: 24px; border-top: 1px dashed var(--border-default); }
.ds__h { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-secondary); opacity: 0.85; }
.ds__group { display: flex; gap: 14px; }
.ds__swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 16px 12px; }
.ds__sw, .ds__type { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ds__chip { width: 100%; max-width: 64px; aspect-ratio: 1; margin-bottom: 8px; border-radius: 14px; background: var(--c); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.1); }
@supports (corner-shape: squircle) { :root[data-corners="smooth"] .ds__chip { corner-shape: squircle; border-radius: 22px; } }
.ds__k { font-size: 12px; font-weight: 700; line-height: 1.2; color: var(--text-primary); white-space: nowrap; }
.ds__v { font-size: 11px; font-weight: 600; line-height: 1.35; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.ds__sw .ds__v, .ds__type .ds__v { white-space: nowrap; }
.ds__types { gap: 28px; }
.ds__aa { font-size: 40px; line-height: 1; letter-spacing: -0.02em; color: var(--text-primary); margin-bottom: 6px; }
.ds__radii { flex-direction: column; gap: 10px; }
.ds__radii ul { display: flex; gap: 8px; }
.ds__r { width: 26px; height: 26px; border-top: 2px solid var(--text-secondary); border-left: 2px solid var(--text-secondary); border-top-left-radius: var(--r); opacity: 0.7; }
.ds__comps { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 14px; padding: 20px 24px 24px; }
.ds__comps .ds__h { flex: none; }
@media (min-width: 640px) {
  .ds__tokens { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }   /* equal halves: the Type | Radius divider sits centred in the frame */
  .ds__col:first-child { grid-column: 1 / -1; padding-top: 26px; }
  .ds__swatches { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  /* row 2: the separator above runs across both cells; a dashed line divides Type | Radius */
  .ds__col:nth-child(2)::before { right: 0; }
  .ds__col:nth-child(3)::before { left: 0; }
  .ds__col:nth-child(3)::after { content: ""; position: absolute; left: 0; top: 22px; bottom: 22px; border-left: 1px dashed var(--border-default); }
  .ds__comps { flex-direction: row; align-items: center; gap: 20px; }
}
/* AGS components, rebuilt from the tokens (they keep AGS's own colours in both site themes) */
.ags-ui { --ags-h: 36px; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; font-family: "Urbanist", var(--font-secondary); letter-spacing: 0; }
.ags-ui button { font-family: inherit; border: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.ags-ui button:focus-visible { outline: 2px solid #3d8a7a; outline-offset: 2px; }
/* buttons: lift on hover, press down on click */
.ags-btn { position: relative; display: inline-flex; align-items: center; gap: 0; height: var(--ags-h); padding: 0 16px; border-radius: 8px; font-size: 13px; font-weight: 600;
  transition: transform var(--spring-snap-duration) var(--spring-snap), box-shadow 200ms ease, background-color 200ms ease, gap 220ms cubic-bezier(0.2, 0, 0, 1); }
.ags-btn--green { background: #034638; color: #fafafa; box-shadow: 0 1px 2px rgb(3 70 56 / 0.2); }
.ags-btn--yellow { background: #f3e500; color: #0a0a0a; box-shadow: 0 1px 2px rgb(120 110 0 / 0.2); }
@media (hover: hover) {
  .ags-btn:hover { transform: translateY(-1px); }
  .ags-btn--green:hover { background: #023b2f; box-shadow: 0 8px 18px -8px rgb(3 70 56 / 0.55); }
  .ags-btn--yellow:hover { background: #f7ec40; box-shadow: 0 8px 18px -8px rgb(160 150 0 / 0.55); }
}
.ags-btn:active { transform: translateY(0) scale(0.97); transition-duration: 80ms; }
/* "Apply Filters": a short "Applied" confirmation after a click */
.ags-btn__l, .ags-btn__done { transition: opacity 180ms ease, transform 220ms cubic-bezier(0.2, 0, 0, 1); }
.ags-btn__done { position: absolute; inset: 0; display: grid; place-items: center; opacity: 0; transform: translateY(6px); }
.ags-btn.is-done .ags-btn__l { opacity: 0; transform: translateY(-6px); }
.ags-btn.is-done .ags-btn__done { opacity: 1; transform: none; }
.ags-btn.is-done .ags-btn__done::before { content: "✓ "; white-space: pre; }
/* segmented toggle: the thumb slides to the chosen view */
.ags-seg { position: relative; display: inline-flex; box-sizing: border-box; height: var(--ags-h); padding: 3px; border-radius: 999px; background: #f4f4f2; box-shadow: inset 0 0 0 1px #e8e8e6; font-size: 12px; font-weight: 500; }
.ags-seg__thumb { position: absolute; top: 3px; bottom: 3px; left: 3px; width: var(--tw, 90px); transform: translateX(var(--tx, 0)); border-radius: 999px; background: #034638;
  box-shadow: 0 2px 6px -2px rgb(3 70 56 / 0.5); transition: transform 320ms cubic-bezier(0.3, 1.3, 0.5, 1), width 320ms cubic-bezier(0.3, 1.3, 0.5, 1); }
.ags-seg > button { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 6px; height: 100%; padding: 0 12px; border-radius: 999px;
  background: transparent; color: #525252; transition: color 220ms ease; }
.ags-seg > button.is-on { color: #fafafa; }
@media (hover: hover) { .ags-seg > button:not(.is-on):hover { color: #034638; } }
.ags-pin { width: 7px; height: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 0 2px rgb(255 255 255 / 0.25); }
.ags-grid { width: 8px; height: 8px; background:
  linear-gradient(currentColor 0 0) 0 0 / 3px 3px no-repeat, linear-gradient(currentColor 0 0) 100% 0 / 3px 3px no-repeat,
  linear-gradient(currentColor 0 0) 0 100% / 3px 3px no-repeat, linear-gradient(currentColor 0 0) 100% 100% / 3px 3px no-repeat; }
/* tag: tints on hover, toggles on like a filter chip; at its Figma height (25 of the buttons' 40, drawn 22 of 36) */
.ags-tag { display: inline-flex; align-items: center; height: 22px; padding: 0 10px; border-radius: 6px; background: #e8f2ef; color: #034638; font-size: 10px; font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase; transition: background-color 180ms ease, color 180ms ease, transform 120ms ease; }
@media (hover: hover) { .ags-tag:hover { background: #b8d9d1; } }
.ags-tag:active { transform: scale(0.96); }
.ags-tag[aria-pressed="true"] { background: #034638; color: #fafafa; }
/* match score: the ring and number count up again on hover / click */
@property --mm { syntax: "<number>"; inherits: true; initial-value: 96; }
.ags-match { display: inline-flex; flex-direction: row; align-items: center; gap: 8px; height: var(--ags-h); padding: 0; background: none; transition: transform 160ms ease; }
.ags-match:active { transform: scale(0.95); }
.ags-match__ring { display: grid; place-items: center; width: var(--ags-h); height: var(--ags-h); border-radius: 50%; --mm: var(--m);
  background: radial-gradient(closest-side, var(--frame-bg) 82%, transparent 84%), conic-gradient(#034638 calc(var(--mm) * 1%), #d1d1cf 0); }
.ags-match.is-counting .ags-match__ring { animation: ags-ring 0.9s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes ags-ring { from { --mm: 0; } to { --mm: var(--m); } }
.ags-match__ring b { font-family: "Space Grotesk", var(--font-primary); font-size: 13px; font-weight: 700; color: #034638; font-variant-numeric: tabular-nums; }
:root[data-theme="dark"] .ags-match__ring b { color: #7dbfb2; }
.ags-match__k { font-size: 10px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-secondary); }   /* beside the ring now, so the row keeps one height */
@media (prefers-reduced-motion: reduce) {
  .ags-btn, .ags-seg__thumb, .ags-tag, .ags-match, .ags-btn__l, .ags-btn__done { transition: none; }
  .ags-match.is-counting .ags-match__ring { animation: none; }
}

/* scroll-driven video (AGS home walkthrough, 9 Nov): the frame pins while a runway below it scrolls past; main.js
   maps the runway progress to the video's time, so the Figma interactions play as the visitor scrolls (and rewind
   on the way back). Reduced motion: no pin, a plain video with controls. */
.frame--scrub { display: block; }
.frame--scrub::after { content: ""; display: block; height: var(--scrub-len, 110vh); }
.frame__pin { position: sticky; top: max(24px, calc(50vh - var(--pin-h, 320px) / 2)); display: flex; flex-direction: column; gap: 12px; }
.frame--scrub .frame__tile { padding: 5.5%; }
.case-section .frame--scrub video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; border-radius: 12px; background: #050807; box-shadow: var(--frame-shot); }
.frame__progress { position: absolute; left: 5.5%; right: 5.5%; bottom: calc(5.5% * 0.45); height: 2px; border-radius: 2px; background: rgb(0 0 0 / 0.08); overflow: hidden; }
.frame__progress i { display: block; height: 100%; width: 100%; transform-origin: left; transform: scaleX(var(--p, 0)); background: var(--text-secondary); opacity: 0.6; }
:root[data-theme="dark"] .frame__progress { background: rgb(255 255 255 / 0.1); }
@media (max-width: 700px) { .case-section .frame--scrub video { border-radius: 6px; } }
@media (prefers-reduced-motion: reduce) {
  .frame--scrub::after { display: none; }
  .frame__pin { position: static; }
  .frame__progress { display: none; }
}

/* ---------- live page (AGS home, 9 Nov): the auto-scrolling page plus the prototype's mouse-enter interactions ----------
   The flat export is the "before" state (curtain text hidden, pillar cards stacked). Layers on top are the Figma
   "Revealed" variants, sliced line by line, and the five pillar cards; main.js scrolls the page and switches a layer
   .on when it drifts into view, so the text rises line by line and the cards fan out — and reverse on the way back.
   Units: --u = one Figma px of the 1920-wide page. Reduced motion: no drift, every layer on, the window scrolls by hand. */
.live { position: relative; container-type: inline-size; }
.live__page { position: absolute; left: 0; top: 0; width: 100%; --u: calc(100cqw / var(--pw)); height: calc(var(--ph) * var(--u));
  transform: translate3d(0, calc(var(--off, 0) * -1px), 0); will-change: transform; }
.case-section .live .live__page > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; }
.live__line { position: absolute; overflow: hidden; }
.live__in { position: absolute; inset: 0; transform: translate3d(0, 105%, 0); transition: transform 0.55s cubic-bezier(0.3, 0, 0.2, 1) calc(var(--i) * 90ms); }
.live__line.on .live__in { transform: none; }
.live__in { white-space: nowrap; letter-spacing: 0; -webkit-font-smoothing: antialiased; }
.live__t--u6 { font-family: "Urbanist", sans-serif; font-weight: 600; }
.live__t--u4 { font-family: "Urbanist", sans-serif; font-weight: 400; }
.live__t--pi { font-family: "Playfair Display", serif; font-style: italic; font-weight: 600; }
.live__stat { position: absolute; font-family: "Space Grotesk", sans-serif; font-weight: 700; letter-spacing: 0; white-space: nowrap;
  background: linear-gradient(90deg, #f3d700, #034638); -webkit-background-clip: text; background-clip: text; color: transparent;
  opacity: 0; }
/* a hover is momentary: each number lights up in turn and settles back, as if the pointer swept across the row */
@keyframes live-stat { 0% { opacity: 0; } 18%, 62% { opacity: 1; } 100% { opacity: 0; } }
.live__stat.on { animation: live-stat 1.7s ease-in-out calc(0.3s + var(--i) * 0.55s) both; }
.case-section .live img.live__card { position: absolute; left: var(--x0); max-width: none; object-fit: fill; border-radius: 0;
  filter: drop-shadow(0 8px 12px rgb(0 0 0 / 0.16)); backface-visibility: hidden;   /* follows the card's rounded alpha */
  transform: translate3d(0, 0, 0); transition: transform 0.9s cubic-bezier(0.65, 0, 0.35, 1); }
.case-section .live img.live__card.on { transform: translate3d(calc(var(--x1) - var(--x0)), 0, 0);
  transition: transform 1.6s cubic-bezier(0.65, 0, 0.35, 1) calc(var(--i) * 70ms + 120ms); }
.live__clip { position: absolute; overflow: hidden; }
/* the pillar row: its bottom edge hides the hand of cards below the row, but once the cards have settled into the
   row the edge opens so their shadows aren't cut (sides and top stay open throughout for the same reason) */
.live__clip--rise { overflow: visible; clip-path: inset(-80px -80px 0 -80px); }
.live__clip--rise:has(.live__rise.on) { clip-path: inset(-80px -80px -48px -80px); transition: clip-path 0s linear 2.7s; }
/* option 2 pillar cards: a tilted hand peeking from the bottom of the row rises into an arc (Figma Position4 -> 5) */
.case-section .live img.live__rise { position: absolute; max-width: none; object-fit: fill; border-radius: 0; transform-origin: 0 0;
  filter: drop-shadow(0 8px 12px rgb(0 0 0 / 0.18)); backface-visibility: hidden;
  transform: translate(0, 0) rotate(var(--r)) scale(var(--k)); }
/* the prototype's chain in one go: Position4 -> Position5 (rise into the arc, 1.67s), a beat, then Position=1
   (straighten and grow into the full-size row). Tightened to ~2.8s in all; the live page holds ~3.2s here.
   Cards are laid out at full size and scaled down by --k for the hand and arc, so the final row stays sharp. */
@keyframes live-rise {
  0%   { transform: translate(0, 0) rotate(var(--r)) scale(var(--k)); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  36%  { transform: translate(0, var(--dy)) rotate(var(--r)) scale(var(--k)); }
  44%  { transform: translate(0, var(--dy)) rotate(var(--r)) scale(var(--k)); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  100% { transform: translate(var(--sx), var(--sy)) rotate(0deg) scale(1); }
}
.case-section .live img.live__rise.on { animation: live-rise 2.8s calc(var(--i) * 40ms) both; }   /* tightened from 5s (Hanan, 9 Nov): rise ~1s, beat ~0.2s, spread ~1.6s */
/* the join panel's dotted glow fades up (Figma Component 1104, 3.3s); screen-blended, its baked canvas colour removed */
.case-section .live img.live__glow { position: absolute; max-width: none; object-fit: fill; border-radius: 0; mix-blend-mode: screen;
  opacity: 0; transform: translate3d(0, 4%, 0); transition: opacity 0.6s ease, transform 0.6s ease; }
.case-section .live img.live__glow.on { opacity: 1; transform: none; transition: opacity 2.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.2s, transform 3s cubic-bezier(0.22, 1, 0.36, 1) 0.2s; }
@media (prefers-reduced-motion: reduce) {
  .live { overflow-y: auto; }
  .live__page { position: relative; transform: none; }
  .live__in, .case-section .live img.live__card, .case-section .live img.live__glow { transition: none; }
  .case-section .live img.live__rise.on { animation: none; transform: translate(var(--sx), var(--sy)); }
  .live__stat.on { animation: none; opacity: 1; }
}

/* ---------- story lead styles (9 Nov, options; STORY_LEAD / ?lead=) ----------
   inline: the original — bold lead running into grey text at 24px.
   a "stacked": the lead becomes a title line (22px/800) and the rest drops to readable body text (17px).
   b "numbered": a small chapter number (01 / 06) above a slightly larger title, body text below.
   c "lighter inline": stays one paragraph but at 19px with a lighter grey continuation. */
.case-num { display: none; }
:root[data-lead="a"] .case-lead strong, :root[data-lead="b"] .case-lead strong { display: block; }
:root[data-lead="a"] .case-lead__rest, :root[data-lead="b"] .case-lead__rest { display: block; margin-top: 10px; font-size: 17px; font-weight: var(--w-body); line-height: 1.55; color: var(--text-muted); }
:root[data-lead="a"] .case-lead, :root[data-lead="b"] .case-lead { font-size: 22px; line-height: 1.25; color: var(--text-primary); }
:root[data-lead="a"] .case-lead strong { font-weight: 800; }
:root[data-lead="b"] .case-num { display: block; margin-bottom: -4px; font-size: 12px; font-weight: 700; letter-spacing: 0.08em; color: var(--text-primary); font-variant-numeric: tabular-nums; }
:root[data-lead="b"] .case-num i { font-style: normal; color: var(--text-secondary); opacity: 0.7; }
:root[data-lead="b"] .case-lead { font-size: 26px; letter-spacing: -0.01em; }
:root[data-lead="b"] .case-lead strong { font-weight: 800; }
:root[data-lead="c"] .case-lead { font-size: 19px; line-height: 1.5; font-weight: 500; color: var(--text-secondary); max-width: 620px; }
:root[data-lead="c"] .case-lead strong { font-weight: 700; color: var(--text-primary); }

/* ---------- map pins (AGS directory map, 9 Nov): the Figma "Scholar Marker" hover state over the screen ----------
   Ring (#f3d700 at 25%) + bigger dot + a dark label (#081714, r 8) with the name (Space Grotesk 500) and city
   (Urbanist, yellow). Placed in Figma px of the 1920-wide screen (--u); the label keeps a readable minimum size.
   main.js lights one pin at a time while the map is on screen; hovering a pin shows its label and pauses the cycle. */
.frame__shot { position: relative; display: block; }
.pins { position: absolute; inset: 0; container-type: inline-size; --u: calc(100cqw / var(--pw)); pointer-events: none; }
.pin { position: absolute; left: calc(var(--x) * var(--u)); top: calc(var(--y) * var(--u)); width: calc(32 * var(--u)); height: calc(60 * var(--u)); pointer-events: auto; cursor: default; }
.pin__ring, .pin__dot { position: absolute; border-radius: 50%; opacity: 0; transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.2, 0, 0, 1); }
.pin__ring { left: 0; top: calc(14 * var(--u)); width: calc(32 * var(--u)); height: calc(32 * var(--u)); background: rgb(243 215 0 / 0.25); transform: scale(0.6); }
.pin__dot { left: calc(9 * var(--u)); top: calc(23 * var(--u)); width: calc(14 * var(--u)); height: calc(14 * var(--u)); background: #f3d700; box-shadow: 0 0 calc(12 * var(--u)) rgb(243 215 0 / 0.8); }
.pin__tip { position: absolute; left: calc(36 * var(--u)); top: 50%; transform: translate(-4px, -50%); display: flex; flex-direction: column; gap: 2px; white-space: nowrap;
  padding: max(calc(8 * var(--u)), 5px) max(calc(16 * var(--u)), 9px); border-radius: max(calc(8 * var(--u)), 6px); background: #081714;
  box-shadow: 0 6px 16px -6px rgb(0 0 0 / 0.5); opacity: 0; transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.2, 0, 0, 1); z-index: 2; }
.pin__tip b { font-family: "Space Grotesk", sans-serif; font-weight: 500; font-size: max(calc(14 * var(--u)), 10px); line-height: 1.25; color: #fff; letter-spacing: 0; }
.pin__tip i { font-family: "Urbanist", sans-serif; font-style: normal; font-weight: 500; font-size: max(calc(12 * var(--u)), 9px); line-height: 1.2; color: #f3d700; letter-spacing: 0; }
.pin.on .pin__ring, .pin.on .pin__dot { opacity: 1; transform: none; }
.pin.on .pin__tip { opacity: 1; transform: translate(0, -50%); }
.pin.on { z-index: 3; }
/* the matching row in the "Live network directory" list: a faint Green 50 tint (Figma has no selected
   row state, so it uses the system's own colours); the list box clips the last, partly hidden row */
.pin-list { position: absolute; left: calc(var(--x) * var(--u)); top: calc(var(--y) * var(--u)); width: calc(var(--w) * var(--u)); height: calc(var(--h) * var(--u)); overflow: hidden; border-radius: calc(12 * var(--u)); }
.pin-row { position: absolute; left: calc(var(--x) * var(--u)); top: calc(var(--y) * var(--u)); width: calc(var(--w) * var(--u)); height: calc(var(--h) * var(--u));
  border-radius: calc(12 * var(--u)); background: rgb(3 70 56 / 0.07); opacity: 0; transition: opacity 0.25s ease; }   /* tint only, no stroke (Hanan: the outline was too obvious) */
.pin-row.on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .pin__ring, .pin__dot, .pin__tip, .pin-row { transition: none; } }

/* ---------- Qatar Rail case study (10 Nov): cycling screens, chat replay, phone row, outlined-glyph components ----------
   cycle: screens stacked in one frame; main.js (cycler) brings the next one in on top with a crossfade while the
   previous stays underneath, so the frame never dims. Labels in the caption follow the current screen.
   chat: the app frame with its chat panel stepping through the prototype's conversation states the same way.
   Both pause on hover and off screen; reduced motion shows one still. */
.cyc { position: relative; display: block; }
.case-section .frame .cyc__s { display: block; width: 100%; height: auto; opacity: 0; border-radius: 0; box-shadow: none; }
.case-section .frame .cyc__s + .cyc__s { position: absolute; inset: 0; height: 100%; }
.case-section .frame .cyc__s.was { opacity: 1; z-index: 1; }
.case-section .frame .cyc__s.on { opacity: 1; z-index: 2; transition: opacity 0.55s ease; }
.frame--cycle .cyc, .chat { overflow: hidden; border-radius: 12px 12px 0 0; box-shadow: var(--frame-shot); background: #fff; }
.chat { position: relative; display: block; container-type: inline-size; }
.case-section .frame .chat > img { display: block; width: 100%; height: auto; border-radius: 0; box-shadow: none; }
.chat__panel { position: absolute; overflow: hidden; border-radius: calc(var(--r) * 100cqw / var(--pw)); }
.case-section .frame .chat__panel .cyc__s { height: 100%; }
.case-section .frame .chat__panel .cyc__s.on { transition-duration: 0.35s; }
.frame__cap--steps { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; }
.frame__cap--steps > span:first-child::after { content: " ·"; }
.cyc__l { opacity: 0.5; transition: opacity 0.3s ease, color 0.3s ease; }
.cyc__l.on { opacity: 1; color: var(--text-primary); }
/* one phone replaying the app's prototype flow (Figma "Mobile App" frames iPhone 16 - 1, 2, 6, 7, 3, 4), in an iPhone
   mockup: bezel + Dynamic Island around a 393x852 screen. The first two steps are the prototype's own motion, rebuilt
   from its layers (.app): splash -> home with the pattern lines parting (Slow), the balance rolling up to 98 QAR; then
   the wallet tap: the screen clears (Gentle), the wallet drops away, the cards rise and fan out into the Manage Cards
   carousel. Positions are Figma px as % of the screen (wallet layers: % of the 361x232 wallet component); 1px = 100cqw/393.
   main.js arms each layered step paused at its start and plays it when it comes on; un-armed (no JS, reduced motion)
   it shows its end state. Back = the prototype's MOVE_OUT right, Top-Up / Payment = its MOVE_IN (0.3s ease-in-out). */
.frame--phone .frame__tile { padding: 6% 0; display: grid; place-items: center; container-type: inline-size; }
.phone { --w: min(34cqw, 266px); position: relative; display: block; width: var(--w); padding: calc(var(--w) * 0.032); border-radius: calc(var(--w) * 0.168); background: #111114;
  box-shadow: 0 0 0 calc(var(--w) * 0.01) #d8d8de, 0 0 0 calc(var(--w) * 0.015) #bdbdc6, 0 22px 44px -26px rgb(20 10 40 / 0.28); }
.phone__screen { aspect-ratio: 393 / 852; overflow: hidden; border-radius: calc(var(--w) * 0.138); background: #fff; container-type: inline-size; }
.phone__island { position: absolute; z-index: 4; left: 50%; top: 1.291%; width: 32.061%; height: 4.343%; transform: translateX(-50%); border-radius: 999px; background: #000; }
.case-section .frame .phone .cyc__s { position: absolute; inset: 0; width: 100%; height: 100%; }
@keyframes cyc-slide { from { transform: translateX(100%); } to { transform: none; } }
@keyframes cyc-out { to { transform: translateX(100%); } }
.case-section .frame .cyc__s.on.cyc--slide { animation: cyc-slide 0.3s ease-in-out; transition: none; }
.case-section .frame .cyc__s.on.cyc--back, .case-section .frame .cyc__s.on.app--cards { transition: none; }   /* back: the screen above slides off it; cards: starts exactly where home ended */
.case-section .frame .phone__screen:has(> .cyc__s.on.cyc--back) > .cyc__s.was { z-index: 3; animation: cyc-out 0.3s ease-in-out forwards; }
@media (max-width: 700px) { .phone { --w: 58cqw; } }
.app { overflow: hidden; --ap-g: linear(0, 0.0287, 0.1006, 0.1982, 0.3079, 0.42, 0.5277, 0.6266, 0.7142, 0.7893, 0.8518, 0.9024, 0.9422, 0.9724, 0.9945, 1.0099, 1.0198, 1.0255, 1.028, 1.0282, 1.0268, 1.0244, 1.0215, 1.0183, 1.0152, 1.0122, 1.0095, 1.0072, 1.0052, 1.0036, 1.0023, 1.0013, 1.0005, 1, 0.9996, 0.9994, 0.9992, 0.9992, 0.9992, 0.9993, 1); --ap-s: linear(0, 0.0474, 0.1489, 0.2668, 0.3823, 0.4869, 0.5779, 0.6549, 0.7191, 0.7721, 0.8154, 0.8508, 0.8795, 0.9027, 0.9215, 0.9367, 0.949, 0.9589, 0.9668, 0.9733, 0.9785, 0.9826, 0.986, 0.9887, 0.9909, 0.9927, 0.9941, 0.9952, 0.9962, 0.9969, 0.9975, 0.998, 1); }
.case-section .frame .app img { position: absolute; display: block; height: auto; max-width: none; border-radius: 0; box-shadow: none; }
.case-section .frame .app .ap-bg, .case-section .frame .app .ap-sp { inset: 0; width: 100%; height: 100%; }
.app span { position: absolute; display: block; }
.app .ap-home { inset: 0; }
.app .ap-pt { left: 0%; top: 0%; width: 100%; }
.app .ap-pb { left: 0%; top: 78.404%; width: 100%; }
.app .ap-top { left: 4.071%; top: 9.155%; width: 91.858%; }
.app .ap-low { left: 4.071%; top: 57.16%; width: 91.858%; }
.app .ap-av { left: 71.756%; top: 87.676%; width: 30.025%; }
.app .ap-st { left: 0%; top: 0%; width: 100%; }
.app .ap-mc { left: 4.071%; top: 9.155%; width: 91.858%; }
.app .ap-lg { left: 36.26%; top: 40.376%; width: 27.481%; }
.app .ap-cd { left: 4.071%; top: 42.019%; width: 91.858%; }
.app .ap-cs { left: -2.036%; top: 41.315%; width: 104.071%; }   /* section cards (card at 16, 376 / 575) with their 24px shadow margin */
.app .ap-ca { left: -2.036%; top: 64.671%; width: 104.071%; }
.app .ap-hi { left: 31.807%; top: 98.474%; width: 36.641%; height: 0.587%; border-radius: 99px; background: #000; }
.app .ap-wal { left: 4.071%; top: 27.113%; width: 91.858%; height: 27.23%; }
.app .ap-wb { left: -6.648%; top: -19.694%; width: 113.573%; }
.app .ap-wf { left: 2.964%; top: 26.121%; width: 95.014%; }
.app .ap-bal { inset: 0; }
.app .ap-roll { left: 8.864%; top: 74.569%; width: 6.925%; height: 6.897%; overflow: hidden; }
.case-section .frame .app .ap-roll img { left: 0; top: 0; width: 52%; }
.case-section .frame .app .ap-roll .ap-d2 { left: 48%; }
.app .ap-qar { left: 17.23%; top: 75%; width: 9.831%; }
.app .ap-tb { left: 8.981%; top: 84.905%; width: 18.989%; }
.app .ap-c { left: 6.629%; width: 87.258%; aspect-ratio: 3 / 2; transform-origin: 0 0; }
.case-section .frame .app .ap-c img { inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* home: end state (the layers as on the Figma home frame, balance rolled to 98) */
.app .ap-sp, .app .ap-lg { opacity: 0; }
.app .ap-pt { transform: translateY(-135.87%); }
.app .ap-pb { transform: translateY(135.87%); }
.app .ap-d1 { transform: translateY(-85.135%); }
.app .ap-d2 { transform: translateY(-75.676%); }
.app .ap-c1 { top: 0%; filter: drop-shadow(0 0 0 rgb(0 0 0 / 0)) drop-shadow(0 0 0 rgb(0 0 0 / 0)); }
.app .ap-c1 img { clip-path: inset(0 0 0% 0 round 4.071cqw); }
.app .ap-c2 { top: 12.069%; filter: drop-shadow(0 -0.254cqw 0.254cqw rgb(0 0 0 / 0.2)) drop-shadow(0 -1.018cqw 1.018cqw rgb(0 0 0 / 0.15)); }
.app .ap-c2 img { clip-path: inset(0 0 16.19% 0 round 4.071cqw); }
.app .ap-c3 { top: 25.862%; filter: drop-shadow(0 -0.254cqw 0.254cqw rgb(0 0 0 / 0.2)) drop-shadow(0 -1.018cqw 1.018cqw rgb(0 0 0 / 0.15)); }
.app .ap-c3 img { clip-path: inset(0 0 29.52% 0 round 4.071cqw); }
/* manage cards: end state (header, alert and tiles gone, wallet dropped away, cards in the carousel) */
.app--cards .ap-top { transform: translateY(-209.3%); }
.app--cards .ap-wal { transform: translateY(-48.71%); }
.app--cards .ap-low { transform: translateY(131.51%); }
.app--cards .ap-av, .app--cards .ap-bal, .app--cards .ap-wb, .app--cards .ap-wf { opacity: 0; }
.app--cards .ap-wb { transform: translateY(166.19%); }
.app--cards .ap-wf { transform: translateY(347.31%); }
.app--cards .ap-c1 { transform: translate(216.15%, 1.9%) scale(1.0679); filter: drop-shadow(0 0.254cqw 5.089cqw rgb(0 0 0 / 0.04)) drop-shadow(0 0 0 rgb(0 0 0 / 0)); }
.app--cards .ap-c2 { transform: translate(104.27%, -11.43%) scale(1.0679); filter: drop-shadow(0 0.254cqw 5.089cqw rgb(0 0 0 / 0.04)) drop-shadow(0 0 0 rgb(0 0 0 / 0)); }
.app--cards .ap-c3 { transform: translate(-7.6%, -26.67%) scale(1.0679); filter: drop-shadow(0 0.254cqw 5.089cqw rgb(0 0 0 / 0.04)) drop-shadow(0 0 0 rgb(0 0 0 / 0)); }
.app--cards .ap-c img { clip-path: inset(0 round 4.071cqw); }
@keyframes ap-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes ap-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes ap-pt { from { transform: none; } }
@keyframes ap-pb { from { transform: none; } }
@keyframes ap-roll { from { transform: none; } }
@keyframes ap-move { from { transform: none; } }
@keyframes ap-drop { from { transform: none; opacity: 1; } }
@keyframes ap-rise { from { opacity: 0; transform: translateY(3.053cqw); } }
@keyframes ap-c1 {
  0% { transform: none; filter: drop-shadow(0 0 0 rgb(0 0 0 / 0)) drop-shadow(0 0 0 rgb(0 0 0 / 0)); animation-timing-function: var(--ap-g); }
  50% { transform: translate(-0.31%, -19.05%); filter: drop-shadow(0 0 0 rgb(0 0 0 / 0)) drop-shadow(0 0 0 rgb(0 0 0 / 0)); animation-timing-function: var(--ap-g); }
}
@keyframes ap-c2 {
  0% { transform: none; filter: drop-shadow(0 -0.254cqw 0.254cqw rgb(0 0 0 / 0.2)) drop-shadow(0 -1.018cqw 1.018cqw rgb(0 0 0 / 0.15)); animation-timing-function: var(--ap-g); }
  50% { transform: translate(-0.31%, -9.52%); filter: drop-shadow(0 -0.254cqw 0.254cqw rgb(0 0 0 / 0.2)) drop-shadow(0 -1.018cqw 1.018cqw rgb(0 0 0 / 0.15)); animation-timing-function: var(--ap-g); }
}
@keyframes ap-c2k {
  0% { clip-path: inset(0 0 16.19% 0 round 4.071cqw); animation-timing-function: var(--ap-g); }
  50% { clip-path: inset(0 0 8.1% 0 round 4.071cqw); animation-timing-function: var(--ap-g); }
}
@keyframes ap-c3 {
  0% { transform: none; filter: drop-shadow(0 -0.254cqw 0.254cqw rgb(0 0 0 / 0.2)) drop-shadow(0 -1.018cqw 1.018cqw rgb(0 0 0 / 0.15)); animation-timing-function: var(--ap-g); }
  50% { transform: translate(-0.31%, 0%); filter: drop-shadow(0 -0.254cqw 0.254cqw rgb(0 0 0 / 0.2)) drop-shadow(0 -1.018cqw 1.018cqw rgb(0 0 0 / 0.15)); animation-timing-function: var(--ap-g); }
}
@keyframes ap-c3k {
  0% { clip-path: inset(0 0 29.52% 0 round 4.071cqw); animation-timing-function: var(--ap-g); }
  50% { clip-path: inset(0 0 0% 0 round 4.071cqw); animation-timing-function: var(--ap-g); }
}
/* home timeline (3.727s): splash holds 0.8s -> Slow 1.667s to home -> the balance rolls (Slow 1.25s) */
.app--home.arm .ap-sp { animation: ap-fade-out 1.667s 0.8s var(--ap-s) both paused; }
.app--home.arm .ap-lg { animation: ap-fade-out 0.5s 0.8s var(--ap-g) both paused; }   /* the logo clears before the home dissolves in */
.app--home.arm .ap-pt { animation: ap-pt 1.667s 0.8s var(--ap-s) both paused; }
.app--home.arm .ap-pb { animation: ap-pb 1.667s 0.8s var(--ap-s) both paused; }
.app--home.arm .ap-home { animation: ap-fade-in 1.667s 0.8s var(--ap-s) both paused; }
.app--home.arm .ap-roll img { animation: ap-roll 1.25s 2.477s var(--ap-s) both paused; }
/* manage cards timeline (5.566s): Gentle 1.022s x3 (screen clears, wallet opens, cards fan out), then the header dissolves in */
.app--cards.arm .ap-top, .app--cards.arm .ap-wal, .app--cards.arm .ap-low { animation: ap-move 1.022s var(--ap-g) both paused; }
.app--cards.arm .ap-av, .app--cards.arm .ap-bal { animation: ap-fade-out 1.022s var(--ap-g) both paused; }
.app--cards.arm .ap-wb, .app--cards.arm .ap-wf { animation: ap-drop 1.022s 1.022s var(--ap-g) both paused; }
.app--cards.arm .ap-c1 { animation: ap-c1 2.044s 1.022s both paused; }
.app--cards.arm .ap-c2 { animation: ap-c2 2.044s 1.022s both paused; }
.app--cards.arm .ap-c2 img { animation: ap-c2k 2.044s 1.022s both paused; }
.app--cards.arm .ap-c3 { animation: ap-c3 2.044s 1.022s both paused; }
.app--cards.arm .ap-c3 img { animation: ap-c3k 2.044s 1.022s both paused; }
.app--cards.arm .ap-mc { animation: ap-fade-in 1.022s 3.522s var(--ap-g) both paused; }
/* card settings + recent activity (not in the Figma frame: fills the space under the carousel; sample rows) rise in after the header */
.app--cards.arm .ap-cd { animation: ap-rise 1.022s 3.582s var(--ap-g) both paused; }
.app--cards.arm .ap-cs { animation: ap-rise 1.022s 3.642s var(--ap-g) both paused; }
.app--cards.arm .ap-ca { animation: ap-rise 1.022s 3.722s var(--ap-g) both paused; }
.case-section .frame .app.arm.play * { animation-play-state: running; }
@media (prefers-reduced-motion: reduce) {
  .case-section .frame .cyc__s.on.cyc--slide, .case-section .frame .phone__screen:has(> .cyc__s.on.cyc--back) > .cyc__s.was, .case-section .frame .app.arm * { animation: none; }
}
/* AI assistant intro (Figma "Component 9", Hanan's workspace): the prototype's own sequence, rebuilt from its layers.
   S8 everything parked off the panel -> (after a beat) Gentle spring 1.28s -> S6 the orb centred, prompt bar up, Activity
   Hub down; "Good Morning, Ahmed" types in under the orb (one letter / 40ms, centred) -> 1.2s later Gentle 1.92s -> S7 the
   orb shrinks into the top-left beside the greeting, the subtitle fades in and the dashboard cards rise in.
   Positions are Figma px in the 1571x1048 panel; main.js arms it paused (S8) and plays it when the frame is half in view.
   Without the arm (no JS, reduced motion) it simply shows the landing screen (S7). */
.ai-intro { position: relative; overflow: hidden; }
.case-section .frame .ai-intro img { position: absolute; display: block; height: auto; max-width: none; border-radius: 0; box-shadow: none; }
.case-section .frame .ai-intro .ii-bg { inset: 0; width: 100%; height: 100%; }
.ai-intro .ii-orb { mix-blend-mode: multiply; }   /* the orb is drawn on white and multiplied in Figma */
.ai-intro .ii-greet { position: absolute; overflow: visible; }
.case-section .frame .ai-intro .ii-greet img { position: static; width: 100%; }
/* the cards rise from behind the composer: clipped at the middle of its opaque prompt box (Figma y 922 of 1048), so nothing
   shows past it (in the Figma frame itself they run on under the box, into the chips and the disclaimer) */
.ai-intro .ii-clip { position: absolute; left: 0; top: 0; width: 100%; height: 87.98%; overflow: hidden; }
.ai-intro .ii-cards { left: 18.46%; top: 22.99%; width: 63.21%; transform-origin: 50% 50%; }
@keyframes ii-cards {
  0%, 10.22% { transform: translateY(56.22%); opacity: 0; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  36.33%, 60.85% { transform: translateY(56.22%); opacity: 0; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  100% { transform: none; opacity: 1; }
}
.ai-intro .ii-prompt { left: 17.25%; top: 62.21%; width: 65.5%; transform-origin: 50% 50%; }
@keyframes ii-prompt {
  0%, 10.22% { transform: translateY(77.02%); opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  36.33%, 60.85% { transform: none; opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  100% { transform: none; opacity: 1; }
}
.ai-intro .ii-hub { left: 89.43%; top: 0.67%; width: 10.18%; transform-origin: 50% 50%; }
@keyframes ii-hub {
  0%, 10.22% { transform: translateY(-1267.86%); opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  36.33%, 60.85% { transform: none; opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  100% { transform: none; opacity: 1; }
}
.ai-intro .ii-orb { left: 20.21%; top: 6.11%; width: 6.51%; transform-origin: 0 0; }
@keyframes ii-orb {
  0%, 10.22% { transform: translate(360.22%, -343.4%) scale(1.955); opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  36.33%, 60.85% { transform: translate(360.22%, 232.08%) scale(1.955); opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  100% { transform: none; opacity: 1; }
}
.ai-intro .ii-greet { left: 27.88%; top: 7.82%; width: 20.43%; transform-origin: 50% 50%; }
@keyframes ii-greet {
  0%, 10.22% { transform: translate(58.41%, -504.69%) scale(1.125); opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  36.33%, 60.85% { transform: translate(58.41%, 1401.56%) scale(1.125); opacity: 1; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  100% { transform: none; opacity: 1; }
}
.ai-intro .ii-sub { left: 27.83%; top: 11.86%; width: 36.35%; transform-origin: 50% 50%; }
@keyframes ii-sub {
  0%, 10.22% { transform: translate(11.09%, -776.5%); opacity: 0; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  36.33%, 60.85% { transform: translate(11.09%, 2273.5%); opacity: 0; animation-timing-function: linear(0, 0.0236, 0.0837, 0.1672, 0.2633, 0.3643, 0.4641, 0.5586, 0.6452, 0.7224, 0.7894, 0.8462, 0.8933, 0.9314, 0.9615, 0.9845, 1.0015, 1.0134, 1.0213, 1.0259, 1.028, 1.0283, 1.0272, 1.0252, 1.0227, 1.0199, 1.017, 1.0142, 1.0116, 1.0093, 1.0072, 1.0054, 1.0039, 1.0026, 1.0016, 1.0008, 1.0003, 0.9998, 0.9995, 0.9993, 1); }
  100% { transform: none; opacity: 1; }
}
@keyframes ii-type {
  0% { clip-path: inset(-20% 100% -20% 0); transform: translateX(50%); }
  5.56% { clip-path: inset(-20% 88.96% -20% 0); transform: translateX(44.48%); }
  11.11% { clip-path: inset(-20% 83.22% -20% 0); transform: translateX(41.61%); }
  16.67% { clip-path: inset(-20% 77.64% -20% 0); transform: translateX(38.82%); }
  22.22% { clip-path: inset(-20% 77.64% -20% 0); transform: translateX(38.82%); }
  27.78% { clip-path: inset(-20% 67.32% -20% 0); transform: translateX(33.66%); }
  33.33% { clip-path: inset(-20% 61.33% -20% 0); transform: translateX(30.67%); }
  38.89% { clip-path: inset(-20% 57.28% -20% 0); transform: translateX(28.64%); }
  44.44% { clip-path: inset(-20% 51.84% -20% 0); transform: translateX(25.92%); }
  50% { clip-path: inset(-20% 49.15% -20% 0); transform: translateX(24.58%); }
  55.56% { clip-path: inset(-20% 43.25% -20% 0); transform: translateX(21.62%); }
  61.11% { clip-path: inset(-20% 37.06% -20% 0); transform: translateX(18.53%); }
  66.67% { clip-path: inset(-20% 34.76% -20% 0); transform: translateX(17.38%); }
  72.22% { clip-path: inset(-20% 34.76% -20% 0); transform: translateX(17.38%); }
  77.78% { clip-path: inset(-20% 25.44% -20% 0); transform: translateX(12.72%); }
  83.33% { clip-path: inset(-20% 19.97% -20% 0); transform: translateX(9.99%); }
  88.89% { clip-path: inset(-20% 11.51% -20% 0); transform: translateX(5.76%); }
  94.44% { clip-path: inset(-20% 5.6% -20% 0); transform: translateX(2.8%); }
  100% { clip-path: inset(-20% 0% -20% 0); transform: translateX(0%); }
}
/* armed: the whole timeline is applied but paused at its start (S8); .play runs it */
.ai-intro.arm .ii-cards { animation: ii-cards 4.89s both paused; }
.ai-intro.arm .ii-prompt { animation: ii-prompt 4.89s both paused; }
.ai-intro.arm .ii-hub { animation: ii-hub 4.89s both paused; }
.ai-intro.arm .ii-orb { animation: ii-orb 4.89s both paused; }
.ai-intro.arm .ii-greet { animation: ii-greet 4.89s both paused; }
.ai-intro.arm .ii-sub { animation: ii-sub 4.89s both paused; }
.ai-intro.arm .ii-greet img { animation: ii-type 0.72s 1.78s step-end both paused; }
.ai-intro.arm.play .ii-greet img, .ai-intro.arm.play .ii-cards, .ai-intro.arm.play .ii-prompt, .ai-intro.arm.play .ii-hub, .ai-intro.arm.play .ii-orb, .ai-intro.arm.play .ii-greet, .ai-intro.arm.play .ii-sub { animation-play-state: running; }
@media (prefers-reduced-motion: reduce) { .ai-intro.arm *, .ai-intro.arm .ii-greet img { animation: none; } }
/* a row of flat phone screens */
/* the tap / click marker on the replayed flows (11 Nov): a small translucent dot where the hand went, for a moment */
.tapdot { position: absolute; z-index: 6; width: 20px; height: 20px; margin: -10px 0 0 -10px; border-radius: 50%; pointer-events: none;
  background: rgb(70 70 70 / 0.16); border: 1.5px solid rgb(255 255 255 / 0.8); box-shadow: 0 1px 6px rgb(0 0 0 / 0.14);
  opacity: 0; scale: 0.7; transition: opacity 0.22s ease, scale 0.22s ease; }
.tapdot.on { opacity: 1; scale: 1; transition-duration: 0.14s; }
.phone__screen .tapdot { width: 16px; height: 16px; margin: -8px 0 0 -8px; }
@media (max-width: 700px) { .tapdot { width: 14px; height: 14px; margin: -7px 0 0 -7px; } }
/* ---------- Visit Qatar concierge (11 Nov): recordings of the prototype in the phone, and its components ---------- */
/* a recording in the phone: the screen's background is the clip's first frame, so the loop can cross-fade back to it */
.frame--clip .phone__screen { display: block; position: relative; background-size: cover; background-position: center; aspect-ratio: 602 / 1310; }
.case-section .frame .frame__tile .phone__screen .phone__sb { position: absolute; z-index: 3; left: 0; top: 0; width: 100%; height: auto; border-radius: 0; box-shadow: none; pointer-events: none; }
.case-section .frame .frame__tile .phone__screen video { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 0; box-shadow: none;
  transition: opacity 0.26s ease; }
.case-section .frame .frame__tile .phone__screen video.is-out { opacity: 0; }
/* Visit Qatar components: shells in the app's colours, labels as outlined glyphs (the brand typeface can't be hosted) */
.vq-c { display: inline-flex; align-items: center; gap: 6px; height: var(--ags-h); padding: 0 16px; border-radius: 999px; background: none;
  transition: transform var(--spring-snap-duration) var(--spring-snap), box-shadow 200ms ease, background-color 200ms ease; }
.vq-c__l { display: block; height: 20px; width: var(--w); flex: none; overflow: visible; }
.vq-c__i { display: block; width: 14px; height: 14px; flex: none; }
.vq-c--primary { background: #005a70; box-shadow: 0 1px 2px rgb(0 90 112 / 0.25); }
.vq-c--secondary { padding: 0 16px; border-radius: 999px;   /* 12 Nov: the pen icon removed, padding as the primary (was 0 14px 0 12px) */ background: #fff; box-shadow: inset 0 0 0 1px #eeebe5; }   /* fully rounded (Hanan, 11 Nov) */
/* the AI voice button (prompt-box__speak): teal with its sheen and soft teal drop, the soundwave icon */
.vq-c--voice { width: var(--ags-h); padding: 0; justify-content: center; border-radius: 50%;
  background: linear-gradient(90deg, rgb(49 149 175 / 0.8) 10%, rgb(49 149 175 / 0.1) 59%), #005a70; box-shadow: 0 5px 11.5px rgb(0 98 108 / 0.22); }
.vq-c--voice svg { display: block; width: 18px; height: 18px; }
.vq-c--chip { background: linear-gradient(90deg, rgb(49 149 175 / 0.8) 10%, rgb(49 149 175 / 0.1) 59%), #00626c; }
.vq-c--tag { --ags-h: 24px; gap: 5px; padding: 0 9px 0 7px; background: #fff; box-shadow: inset 0 0 0 1px #eeebe5; }
.vq-c--tag .vq-c__i--s { width: 10px; height: 10px; }
.vq-c--icon { width: var(--ags-h); padding: 0; justify-content: center; background: linear-gradient(112deg, rgb(255 255 255 / 0.9), rgb(255 255 255 / 0.7)); box-shadow: inset 0 0 0 1px #eeebe5; }
.vq-c--icon svg { display: block; width: 20px; height: 20px; }
@media (hover: hover) {
  .vq-c:hover { transform: translateY(-1px); }
  .vq-c--primary:hover { background: #004f63; box-shadow: 0 8px 18px -8px rgb(0 90 112 / 0.6); }
  .vq-c--voice:hover { box-shadow: 0 8px 18px -6px rgb(0 98 108 / 0.45); }
}
.vq-c:active { transform: translateY(0) scale(0.97); transition-duration: 80ms; }
@media (prefers-reduced-motion: reduce) { .vq-c, .case-section .frame .frame__tile .phone__screen video { transition: none; } }
/* Supreme Committee components (Connect22's own specs at 0.9 to sit in the 36px row); labels are outlined Calibri Bold */
.sc-c { display: inline-flex; align-items: center; gap: 7px; height: var(--ags-h); padding: 0 16px; border: 1px solid transparent; background: none;
  transition: transform var(--spring-snap-duration) var(--spring-snap), box-shadow 200ms ease, background-color 200ms ease, filter 200ms ease; }
.sc-c__l { display: block; height: 20px; width: var(--w); flex: none; overflow: visible; }
.sc-c__i { display: block; width: 14px; height: 14px; flex: none; }
.sc-c--primary { padding: 0 13px 0 18px; border-radius: 11px; border-color: #ad1fca; background: linear-gradient(#ad1fca, #87189d); }
.sc-c--secondary { padding: 0 13px 0 18px; border-radius: 11px; border-color: #87189d; background: #fff; }   /* 12 Nov: same shape as the primary (was 0 11px 0 8px, radius 7) */
.sc-c--tag { --ags-h: 22px; padding: 0 9px; border-radius: 5px; border-color: #bbf7d0; background: #f0fdf4; }
.sc-c--icon { width: var(--ags-h); padding: 0; justify-content: center; border-radius: 50%; border-color: rgb(239 239 244 / 0.9); background: #fff;
  box-shadow: 0 0 1px rgb(148 148 148 / 0.06), 0 1.5px 1.5px rgb(148 148 148 / 0.05), 0 3px 1.5px rgb(148 148 148 / 0.03); }
.sc-c--icon svg { display: block; width: 18px; height: 18px; }
@media (hover: hover) {
  .sc-c:hover { transform: translateY(-1px); }
  .sc-c--primary:hover { filter: brightness(1.06); box-shadow: 0 8px 18px -8px rgb(135 24 157 / 0.6); }
  .sc-c--secondary:hover { background: #faedfc; }
  .sc-c--tag:hover { background: #dcfce7; }
  .sc-c--icon:hover { box-shadow: 0 6px 14px -6px rgb(0 47 108 / 0.35); }
}
.sc-c:active { transform: translateY(0) scale(0.97); transition-duration: 80ms; }
@media (prefers-reduced-motion: reduce) { .sc-c { transition: none; } }
/* a floating widget replaying its own states (the SC WorkHub Assistant): the panel brings its own shadow, so no screen chrome */
.frame--widget .frame__tile { display: grid; place-items: center; padding: 4% 6%; container-type: inline-size; }
.frame--widget.frame--cycle .cyc { width: min(44cqw, 400px); overflow: visible; border-radius: 0; box-shadow: none; background: none; }
@media (max-width: 809px) { .frame--widget.frame--cycle .cyc { width: min(86cqw, 360px); } }
/* a page toured by hand (main.js: tours): the page slides inside the window; a popup can open over it */
.frame--tour .frame__window { position: relative; aspect-ratio: 16 / 9; }
.case-section .frame--tour .frame__window img.tour__scr { position: absolute; inset: 0; z-index: 5; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; animation: none; transition: opacity 0.45s ease; }
.case-section .frame--tour .frame__window img.tour__scr.was { opacity: 1; z-index: 5; transition: none; }
.case-section .frame--tour .frame__window img.tour__scr.on { opacity: 1; z-index: 6; }
.frame--tour .tapdot { z-index: 8; }
.case-section .frame--tour .frame__window img.tour__page { position: absolute; left: 0; top: 0; width: 100%; height: auto; object-fit: fill;
  will-change: transform; animation: none; }
.frame--tour .tour__dim { position: absolute; inset: 0; z-index: 3; background: rgb(15 18 30 / 0.32); opacity: 0; transition: opacity 0.3s ease; pointer-events: none; }
.case-section .frame--tour .frame__window img.tour__ov { position: absolute; left: 50%; top: 50%; z-index: 4; width: 66.7%; height: auto;
  object-fit: fill; translate: -50% -50%; scale: 0.96; opacity: 0; border-radius: 10px; box-shadow: 0 18px 40px -16px rgb(15 18 30 / 0.45);
  transition: opacity 0.28s ease, scale 0.38s cubic-bezier(0.2, 0, 0, 1); pointer-events: none; }
.frame--tour.ov-on .tour__dim { opacity: 1; }
.case-section .frame--tour.ov-on .frame__window img.tour__ov { opacity: 1; scale: 1; }
/* a replaying phone inside a pair sits like the phones beside it */
.frame-pair .frame--phone .frame__tile { flex: 1; padding: 8% 6%; }
.case-section .frame-pair .frame--tall .frame__tile img { width: 58%; height: auto; }
.frame-pair .frame--phone .phone { --w: 42cqw; }
/* phone screens in the iPhone mockup (.phone, as the animated phone), two to a frame; the pair keeps both frames one height */
.frame--phones .frame__tile { flex: 1; display: grid; place-items: center; padding: 8% 6%; container-type: inline-size; }
.phones { display: flex; justify-content: center; gap: 6cqw; }
.phones .phone { --w: 42cqw; }
.phones .phone__screen { display: block; position: relative; }
.case-section .frame .phones .phone__screen img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 0; box-shadow: none; }
/* "Aa" drawn from exported glyph outlines (Neo Sans Pro can't be hosted): cap height matches the 40px text specimens */
.ds__aa--svg { display: block; height: 29px; width: calc(29px * var(--ar)); margin: 2px 0 9px; fill: var(--text-primary); }
/* Qatar Rail components: HTML shells in the components' own colours, labels/icons as outlined glyphs, one height */
.qr-c { display: inline-flex; align-items: center; height: var(--ags-h); padding: 0 14px; border-radius: 9px; background: none;
  transition: transform var(--spring-snap-duration) var(--spring-snap), box-shadow 200ms ease, background-color 200ms ease, filter 200ms ease; }
.qr-c svg { display: block; height: var(--ags-h); width: var(--w); flex: none; overflow: visible; }
.qr-c--primary { background: #a30134; box-shadow: 0 1px 2px rgb(163 1 52 / 0.25); }
.qr-c--secondary { background: #fff; box-shadow: inset 0 0 0 1px #a30134; }
.qr-c--tag { --ags-h: 23px; padding: 0 6.5px; border-radius: 6.5px; }   /* the Figma tag (28px, 8px padding and radius) at the row's scale */
.qr-c--ok { background: #dcfce7; box-shadow: inset 0 0 0 1px #bbf7d0; }
.qr-c--info { background: #cffafe; box-shadow: inset 0 0 0 1px #a5f3fc; }
.qr-c--bad { background: #ffe4e6; box-shadow: inset 0 0 0 1px #fecdd3; }
/* AI badge: the Figma badge's teal-to-lime outline (1px) around a white fill */
.qr-c--badge { padding: 0 10px; border-radius: 7px; border: 1px solid transparent !important; background: linear-gradient(#fff, #fff) padding-box, linear-gradient(90deg, #5eead4, #84cc16) border-box; }
/* icon button: the dashboard header's notification bell, a round light button with the unread dot */
.qr-ib--bell { border-radius: 50%; background: #fafafa; box-shadow: inset 0 0 0 1px #efeff4; overflow: visible; }
.qr-ib--bell svg { overflow: visible; }
@media (hover: hover) { .qr-ib.qr-ib--bell:hover { background: #fafafa; transform: translateY(-1px); box-shadow: inset 0 0 0 1px #efeff4, 0 8px 18px -8px rgb(41 41 41 / 0.35); } }
/* icon button (the portal's sidebar toggle, unused since 10 Nov): default = outline icon, hover = beige tile, pressed = tile + filled icon */
.qr-ib { display: grid; place-items: center; width: var(--ags-h); height: var(--ags-h); padding: 0; border-radius: 9px; background: none;
  transition: transform var(--spring-snap-duration) var(--spring-snap), background-color 200ms ease; }
.qr-ib svg { display: block; width: 100%; height: 100%; }
.qr-ib .qr-ib__on, .qr-ib[aria-pressed="true"] .qr-ib__off { display: none; }
.qr-ib[aria-pressed="true"] .qr-ib__on { display: inline; }
.qr-ib[aria-pressed="true"] { background: #ebe2d5; }
.qr-ib:active { transform: scale(0.94); transition-duration: 80ms; }
@media (hover: hover) {
  .qr-c:hover { transform: translateY(-1px); }
  .qr-c--primary:hover { background: #94012f; box-shadow: 0 8px 18px -8px rgb(163 1 52 / 0.6); }
  .qr-c--tag:hover, .qr-c--badge:hover { filter: saturate(1.25) brightness(0.98); }
  .qr-ib:hover { background: #ebe2d5; }
}
.qr-c:active { transform: translateY(0) scale(0.97); transition-duration: 80ms; }
@media (max-width: 700px) {
  .frame--phones .frame__tile { padding: 24px 16px; }
  .frame--cycle .cyc, .chat { border-radius: 8px 8px 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .case-section .frame .cyc__s.on, .qr-c, .qr-ib, .cyc__l { transition: none; }
}
/* dark swatches stay visible on the dark frame */
:root[data-theme="dark"] .ds__chip { box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.14); }

/* ---------- Mobile fixes (12 Nov, Hanan picked all five from docs/mobile-fixes-compare.html) ---------- */
/* #1 tap areas: the hit area grows, nothing visible moves. Theme switch 20 -> 44px; footer text links fill their 34px rows */
.theme-toggle { position: relative; }
.theme-toggle::before { content: ""; position: absolute; inset: -12px; }
.case-hero__theme.theme-toggle::before, .credential__bar .theme-toggle::before { inset: -2px; }
.site-footer nav a { position: relative; }
.site-footer nav a::before { content: ""; position: absolute; inset: -4px -6px; }
/* #3 the Visit Qatar cover: on phones the frame is taller so the phone can be bigger (129 -> ~200px wide at 390) */
@media (max-width: 600px) {
  .case-cover--phone { aspect-ratio: 4 / 4.4; }
  .case-cover--phone .mock--phone { --w: 56cqw; --pad: 1.7cqw; border-radius: 8.7cqw; }
  .case-cover--phone .mock--phone img { border-radius: 7.1cqw; }
}
/* #5 tap a still screen to see it larger (phones and tablets; main.js: viewer) */
.zoomable { cursor: zoom-in; }
.viewer { position: fixed; inset: 0; z-index: 2147483000; display: flex; flex-direction: column; justify-content: center; gap: 14px;
  background: #0a0a0c; opacity: 0; transition: opacity 0.22s ease; touch-action: pinch-zoom; }
.viewer.on { opacity: 1; }
.viewer__pan { overflow: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.viewer__pan::-webkit-scrollbar { display: none; }
/* wide screens open at twice the screen's width (readable), never taller than 64% of it; pan sideways, pinch for more */
.viewer__pan img { display: block; width: var(--vw); height: auto; max-width: none; margin: 0 auto; border-radius: 0; box-shadow: none; }
.viewer__pan.fit img { width: 100%; }
.viewer__close:focus:not(:focus-visible) { outline: none; }
.viewer__cap { margin: 0; padding: 0 16px; text-align: center; font-size: 13px; font-weight: 600; color: rgb(255 255 255 / 0.7); }
.viewer__close { position: absolute; top: 16px; right: 16px; width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: rgb(255 255 255 / 0.14); color: #fff; font-size: 22px; line-height: 1; cursor: pointer; }
@media (prefers-reduced-motion: reduce) { .viewer { transition: none; } }
