/* Kseniia Dakotova — portfolio. Implemented from the Figma design file
   (Desktop 1280 = pixel reference; Tablet 800 / Mobile 375 = layout reference).
   Fonts: free substitutes for the design's Season TRIAL faces (OFL, self-hosted
   variable fonts): Newsreader ≈ Season Serif/Mix, Hanken Grotesk ≈ Season Sans.
   To switch back to licensed Season: run tools/build-fonts.mjs and restore the
   Season @font-face block from git history. */

/* ---------- fonts ---------- */
@font-face { font-family: 'Newsreader'; src: url('/assets/fonts/newsreader.woff2') format('woff2'); font-weight: 200 800; font-style: normal; font-display: swap; }
@font-face { font-family: 'Newsreader'; src: url('/assets/fonts/newsreader-italic.woff2') format('woff2'); font-weight: 200 800; font-style: italic; font-display: swap; }
@font-face { font-family: 'Hanken Grotesk'; src: url('/assets/fonts/hanken-grotesk.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Hanken Grotesk'; src: url('/assets/fonts/hanken-grotesk-italic.woff2') format('woff2'); font-weight: 100 900; font-style: italic; font-display: swap; }

/* ---------- reset / tokens ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --ink: #292d32;
  /* WCAG AA: lifted from the design's 45% black (3.35:1) to 55% (4.74:1) — designer approved 2026-07-11 */
  --body: rgba(41, 45, 50, .55);
  --soft: #f5f5f5;
  --pink: #f793ce;
  /* WCAG AA: readable dark variant of --pink for TEXT (4.9:1) — #f793ce itself is 2.1:1, decor only */
  --pink-text: #c23a86;
  /* Figma angular gradient: 0° at 3 o'clock => CSS `from 90deg`. Wrapped first stop ≈ #fc808c (pink stop = --pink). */
  --grad: conic-gradient(from 90deg, #fc808c 0%, #ff7464 16.74%, #b6e5ea 34.54%, #f793ce 72.97%, #fc808c 100%);
  --serif: 'Newsreader', Georgia, serif;
  --sans: 'Hanken Grotesk', 'Helvetica Neue', Arial, sans-serif;
  --mix: 'Newsreader', Georgia, serif;
}

html { scroll-behavior: smooth; }
body {
  position: relative; /* containing block for the absolute .hero-glow backdrop */
  background: #fff;
  color: var(--ink);
  font: 550 16px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
}
/* header + main sit above the hero-glow backdrop (which is z-index 0) */
.site-header, main { position: relative; z-index: 1; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
section[id] { scroll-margin-top: 24px; }

.container { max-width: 1000px; margin-inline: auto; padding-inline: 60px; }
.section { padding: 120px 0; }

h2 {
  /* design says 800/470 in Season units; Newsreader runs heavier — 660/420 match visually */
  font: 660 48px/1.2 var(--serif);
  letter-spacing: -.02em;
  color: var(--ink);
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 50px;
  border-radius: 62px;
  font: 550 16px/1.45 var(--sans);
  color: var(--ink);
  white-space: nowrap;
}
.btn-primary { position: relative; background: var(--ink); color: #fff; padding: 12px 24px; }
.btn-secondary { border: 2px solid var(--ink); padding: 12px 24px; transition: border-color .25s; }
.btn-circle { width: 50px; height: 50px; border: 2px solid var(--ink); flex: none; transition: border-color .25s; }
.btn-row { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }

.btn-pair { position: relative; display: inline-flex; border-radius: 62px; }

.arrow { width: 34px; height: 34px; transition: transform .3s; }
.rot-n { transform: rotate(90deg); }   /* base icon points left */
.rot-ne { transform: rotate(135deg); }
.rot-e { transform: rotate(180deg); }

/* border-beam ring (hover): a comet of the brand gradient travels around the
   2px border band over a soft static ring (cult-ui style, our colors) */
@property --beam-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@keyframes border-beam { to { --beam-a: 360deg; } }
.btn-primary::after, .btn-pair::after,
button.btn-circle::after, a.btn-circle::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 62px;
  padding: 2px;
  background:
    conic-gradient(from var(--beam-a),
      transparent 0deg 235deg,
      color-mix(in srgb, #fc808c 55%, transparent) 262deg,
      #ff7464 296deg,
      #b6e5ea 326deg,
      #f793ce 352deg,
      transparent 360deg),
    conic-gradient(from 90deg,
      color-mix(in srgb, #fc808c 40%, #fff) 0%,
      color-mix(in srgb, #ff7464 40%, #fff) 16.74%,
      color-mix(in srgb, #b6e5ea 55%, #fff) 34.54%,
      color-mix(in srgb, #f793ce 45%, #fff) 72.97%,
      color-mix(in srgb, #fc808c 40%, #fff) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask-composite: exclude;
  opacity: 0;
  transition: opacity .25s;
  pointer-events: none;
}
.btn-primary:hover::after, .btn-primary:focus-visible::after,
.btn-pair:hover::after, .btn-pair:focus-visible::after,
button.btn-circle:hover::after, a.to-top:hover::after,
button.btn-circle:focus-visible::after, a.to-top:focus-visible::after {
  animation: border-beam 2.6s linear infinite;
}
.btn-primary::after { inset: 0; }
.btn-pair::after { inset: 0; z-index: 1; }
button.btn-circle, a.btn-circle { position: relative; }
button.btn-circle::after, a.btn-circle::after { inset: -2px; padding: 2px; }

.btn-primary:hover::after, .btn-primary:focus-visible::after { opacity: 1; }

/* secondary pair: two touching pills merge into one on hover */
.btn-pair:hover::after, .btn-pair:focus-visible::after { opacity: 1; }
.btn-pair:hover .btn-secondary, .btn-pair:focus-visible .btn-secondary,
.btn-pair:hover .btn-circle, .btn-pair:focus-visible .btn-circle { border-color: transparent; }
/* the arrow turns -> and slides in beside the text; -12px lands the glyph so the
   pill reads 24 | text | 24 | arrow | 24 — even padding on both ends */
.btn-pair:hover .arrow, .btn-pair:focus-visible .arrow { transform: translateX(-12px) rotate(180deg); }

/* standalone circle buttons (testimonials, back-to-top) */
button.btn-circle { background: none; transition: border-color .25s, transform .25s; }
button.btn-circle:hover, a.to-top:hover,
button.btn-circle:focus-visible, a.to-top:focus-visible { border-color: transparent; }
button.btn-circle:hover::after, a.to-top:hover::after,
button.btn-circle:focus-visible::after, a.to-top:focus-visible::after { opacity: 1; }

/* the gradient ring doubles as the focus indicator on these controls */
.btn-primary:focus-visible, .btn-pair:focus-visible,
button.btn-circle:focus-visible, a.to-top:focus-visible { outline: none; }

/* the wand cursor is large and covers small targets — while it's active, give each control
   a roomy invisible hit pad so the hover state (and click) fire as the wand approaches,
   before it hides the icon. Generous vertically (no neighbours above/below), tighter
   horizontally so adjacent controls' pads meet in the gap without overlapping each other's
   box. Off for touch/reduced-motion (no wand), where fingers need tight targets. */
html.wand-on .btn-primary::before,
html.wand-on .btn-pair::before,
html.wand-on button.btn-circle::before,
html.wand-on a.btn-circle::before,
html.wand-on .social::before {
  content: "";
  position: absolute;
  inset: -22px -12px;
}

/* ---------- social icons (mask -> gradient on hover) ---------- */
.social-row { display: flex; align-items: center; }
.social { position: relative; } /* anchor for the wand hit pad (see html.wand-on ::before) */
.social-icon {
  display: block;
  background: var(--ink);
  -webkit-mask: var(--icon) center / contain no-repeat;
          mask: var(--icon) center / contain no-repeat;
  transition: background .2s, transform .25s cubic-bezier(.34, 1.56, .64, 1);
}
.icon-behance { --icon: url('/assets/icons/behance.svg'); }
.icon-dribbble { --icon: url('/assets/icons/dribbble.svg'); }
.icon-linkedin { --icon: url('/assets/icons/linkedin.svg'); }
/* the wand covers small icons — on hover they pop up (springy scale) and recolour to the
   brand gradient, so the icon peeks out and clearly reads as active */
.social:hover .social-icon, .social:focus-visible .social-icon { background: var(--grad); transform: scale(1.3); }
@media (forced-colors: active) {
  .social-icon, .social:hover .social-icon { forced-color-adjust: none; background: LinkText; }
}
.social-sm { gap: 24px; }
.social-sm .social-icon { width: 24px; height: 24px; }
.social-lg { gap: 24px; padding-top: 20px; }
.social-lg .social-icon { width: 48px; height: 48px; }

/* ---------- header / nav ---------- */
.site-header { display: flex; justify-content: center; padding: 24px 60px; }
.nav-pill {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 40px;
  width: 300px;
  height: 55px;
  padding: 16px 40px;
  border-radius: 40px;
  background: var(--soft);
}
.nav-pill a { font: 550 16px/1.45 var(--sans); color: var(--ink); transition: opacity .2s; }
.nav-pill a:hover { opacity: .55; }
.nav-plain { background: transparent; }

/* ---------- glass (Figma "Glass": #f5f5f5 @ 20% + backdrop blur) on the nav pill ----------
   Frosts the hero glow drifting behind it.
   (Design 23:570: only the nav and marquee chips are glass — the buttons are plain.) */
:root { --glass-blur: 18px; }
.site-header .nav-pill {
  background: rgba(245, 245, 245, .2);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.35);
          backdrop-filter: blur(var(--glass-blur)) saturate(1.35);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55),
              inset 0 0 0 1px rgba(255, 255, 255, .25),
              0 8px 22px rgba(41, 45, 50, .06);
}

/* ---------- hero ---------- */
.hero { overflow: hidden; background: transparent; }

/* hero glow: the soft star backdrop (Figma frame 24:3878) sits behind the header + hero
   and dissolves into white before "What I Bring". The glass nav/chips frost it; the body
   stays white below. Static, so it's kept even under reduced-motion. */
.hero-glow {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 860px;
  z-index: 0;
  pointer-events: none;
  background: url(/assets/img/hero-glow.webp) no-repeat 58% 40% / cover;
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 62%, transparent 96%);
          mask: linear-gradient(to bottom, #000 0%, #000 62%, transparent 96%);
}
.hero-body { height: 636px; display: flex; flex-direction: column; justify-content: center; }
.hero-content {
  height: 477px;
  padding: 40px 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 32px;
}
.hero-text { display: flex; flex-direction: column; gap: 24px; }
.hero-title {
  font: 420 56px/1.1 var(--serif);
  letter-spacing: -.02em;
  color: var(--ink);
  max-width: 880px;
}
.hero-title b { font-weight: 660; }
.hero-title i { font-style: italic; font-weight: 420; }

/* hero typewriter: the headline types itself out, holds, erases, and loops.
   Only active when JS runs (html.tw, set by an inline guard so no-JS shows full text).
   Characters are hidden (space reserved -> no layout shift) until the caret reaches them. */
html.tw .hero-title { visibility: hidden; }
.hero-title .tw-c { visibility: hidden; }
.hero-title .tw-c.on { visibility: visible; }
.tw-caret {
  visibility: visible;
  display: inline-block;
  width: 3px;
  height: .74em;
  margin: 0 .04em -.04em;
  background: currentColor;
  border-radius: 1.5px;
  vertical-align: baseline;
  animation: tw-blink 1.05s steps(1) infinite;
}
.tw-caret.solid { animation: none; opacity: 1; } /* steady while actively typing/erasing */
@keyframes tw-blink { 0%, 45% { opacity: 1; } 45.01%, 100% { opacity: 0; } }

/* marquee: full-bleed strip clipped by the hero */
.marquee { margin-inline: calc(50% - 50vw); overflow: hidden; }
.marquee-track { display: flex; width: max-content; animation: marquee var(--marquee-dur, 45s) linear infinite; animation-delay: var(--marquee-delay, 0s); }
.marquee-group { display: flex; gap: 10px; padding-right: 10px; }
@keyframes marquee { to { transform: translateX(-50%); } }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 33px;
  padding: 8px 20px;
  border-radius: 40px;
  background: rgba(245, 245, 245, .2);
  -webkit-backdrop-filter: blur(12px) saturate(1.3);
          backdrop-filter: blur(12px) saturate(1.3);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 0 0 1px rgba(255, 255, 255, .22);
  font: italic 400 12px/1.45 var(--sans);
  color: var(--ink);
  white-space: nowrap;
  transition: background .4s ease, box-shadow .4s ease;
}
.chip i { width: 6px; height: 6px; border-radius: 50%; flex: none; background: var(--c); }
/* the wand paints chips one by one as it passes near (old-site effect);
   .painted is set by main.js and stays */
.chip.painted {
  background: color-mix(in srgb, var(--c) 24%, #fff);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 55%, #fff);
  -webkit-backdrop-filter: none;
          backdrop-filter: none; /* painted chips are solid colour, not glass */
}
/* the strip freezes while the wand is over it — easier to aim */
.marquee:hover .marquee-track { animation-play-state: paused; }
/* no wand on touch screens — chips simply live in color there */
@media (hover: none) {
  .chip {
    background: color-mix(in srgb, var(--c) 24%, #fff);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 55%, #fff);
    -webkit-backdrop-filter: none;
            backdrop-filter: none; /* touch: no wand, chips are simply coloured */
  }
}

/* ---------- about ---------- */
.about h2 { margin-bottom: 32px; }
/* two independent columns with one uniform vertical rhythm (24px everywhere) */
.about-grid { display: flex; gap: 32px; }
.about-col { width: 424px; display: flex; flex-direction: column; gap: 24px; }
/* the intro hugs the column bottom so both columns end on the same line */
.about-hi { margin-top: auto; }
.about-photo { position: relative; display: block; width: 296px; height: 296px; border-radius: 50%; overflow: hidden; }
.about-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the photo comes to life in color on hover */
.about-photo-color { opacity: 0; transition: opacity .45s ease; }
.about-photo:hover .about-photo-color { opacity: 1; }
.about p { color: var(--body); }
.about .social-row { margin-top: 32px; }

/* ---------- experience ---------- */
.experience h2 { margin-bottom: 32px; }
.xp-wrap { position: relative; padding-left: 38px; }
.xp-rail {
  position: absolute;
  left: 5px;
  top: 12px;
  bottom: 0;
  width: 1px;
  background: linear-gradient(180deg, #292d32, #f5f5f5);
}
.xp-list { display: flex; flex-direction: column; gap: 32px; }
.xp-entry { position: relative; }
.xp-entry::before {
  content: "";
  position: absolute;
  left: -39px;
  top: 3px;
  width: 13px;
  height: 16px;
  background: var(--pink);
  -webkit-mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="13" height="16" viewBox="0 0 13 16"><path d="M6.21405 1.54578C7.54171 5.28132 7.92743 6.12991 11.4445 8.11831C8.59087 9.55511 8.05086 10.6197 6.21405 14.6908C3.93122 10.7369 4.96509 10.6968 0.983643 8.11831C4.73366 6.11448 5.11938 4.88017 6.21405 1.54578Z" fill="black"/></svg>') center / contain no-repeat;
          mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="13" height="16" viewBox="0 0 13 16"><path d="M6.21405 1.54578C7.54171 5.28132 7.92743 6.12991 11.4445 8.11831C8.59087 9.55511 8.05086 10.6197 6.21405 14.6908C3.93122 10.7369 4.96509 10.6968 0.983643 8.11831C4.73366 6.11448 5.11938 4.88017 6.21405 1.54578Z" fill="black"/></svg>') center / contain no-repeat;
  transition: background-color .4s;
}
.xp-head { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 20px; }
.xp-who h3 { font: 580 24px/1 var(--mix); letter-spacing: -.015em; color: var(--ink); margin-bottom: 4px; }
.xp-role { color: var(--pink-text); transition: color .4s; }
.xp-dates { color: var(--ink); }
.xp-bullets li { position: relative; padding-left: 14px; color: var(--body); }
.xp-bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9.5px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--pink);
  transition: background-color .4s;
}

/* wand mode starts the Experience accents neutral — the wand paints them (old-site effect);
   without the wand (touch, reduced motion, narrow windows) they are simply colored */
html.wand-on .xp-entry:not(.painted)::before { background: #d3d5d8; }
html.wand-on .xp-role:not(.painted) { color: var(--body); }
html.wand-on .xp-bullets li:not(.painted)::before { background: var(--ink); }

/* Experience timeline: items flow in one by one as the block scrolls into view
   (ported from the designrocket "What You'll Learn" curriculum). The entry box
   itself doesn't fade — its star, heading and each bullet cascade in line by line. */
html.js .xp-entry[data-reveal] { opacity: 1; transform: none; }
html.js .xp-entry[data-reveal]::before {
  opacity: 0;
  transform: scale(.3);
  transition: opacity .5s ease, transform .5s cubic-bezier(.34, 1.56, .64, 1), background-color .4s;
}
html.js .xp-entry[data-reveal].in::before { opacity: 1; transform: none; }
html.js .xp-entry[data-reveal] .xp-head,
html.js .xp-entry[data-reveal] .xp-bullets li {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.22, .61, .36, 1);
}
html.js .xp-entry[data-reveal].in .xp-head,
html.js .xp-entry[data-reveal].in .xp-bullets li { opacity: 1; transform: none; }
/* stagger: star + heading first, then each bullet a beat later */
html.js .xp-entry[data-reveal].in .xp-head { transition-delay: .05s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(1) { transition-delay: .13s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(2) { transition-delay: .20s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(3) { transition-delay: .27s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(4) { transition-delay: .34s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(5) { transition-delay: .41s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(6) { transition-delay: .48s; }
html.js .xp-entry[data-reveal].in .xp-bullets li:nth-child(7) { transition-delay: .55s; }

/* ---------- portfolio ---------- */
.portfolio h2 { margin-bottom: 32px; }
.cards-group { display: flex; gap: 32px; }
.cards-group + .cards-group { margin-top: 32px; }
.cards-col { display: flex; flex-direction: column; gap: 32px; width: 424px; }
.card { position: relative; display: block; border-radius: 16px; overflow: hidden; }
.card img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
.card:hover img { transform: scale(1.04); }
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(41, 45, 50, .4) 50%, rgba(102, 102, 102, 0) 100%);
}
.card-luxury { height: 340px; }
.card-luxury::after { background: linear-gradient(180deg, rgba(41, 45, 50, .4) 39.4%, rgba(102, 102, 102, 0) 100%); }
.card-equimarket { height: 290px; }
.card-ecommerce { height: 260px; }
.card-ecommerce::after { background: linear-gradient(180deg, rgba(41, 45, 50, .45) 44.4%, rgba(102, 102, 102, 0) 100%); }
.card-expomaster { height: 370px; }
.card-ginclub { height: 542px; }
.card-studhub { height: 240px; }
.card-fitness { height: 270px; }
.card-fitness::after { background: linear-gradient(180deg, rgba(41, 45, 50, .08) 50%, rgba(102, 102, 102, 0) 100%); }
.card-label {
  position: absolute;
  top: 32px;
  left: 32px;
  right: 32px;
  z-index: 1;
  color: #fff;
  font: 580 24px/1 var(--mix);
  letter-spacing: -.015em;
}
.portfolio-cta { display: flex; justify-content: center; margin-top: 32px; }
.portfolio-cta-cell { display: none; }

/* ---------- services ---------- */
.services-cols { display: flex; gap: 48px; }
.services-cols h2 { width: 367px; flex: none; }
.services-list { width: 465px; margin-left: auto; display: flex; flex-direction: column; gap: 16px; }
.service { border: 2px solid var(--ink); border-radius: 16px; padding: 24px; }
.service header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.service header img { flex: none; }
.service h3 { font: 580 24px/1 var(--mix); letter-spacing: -.015em; color: var(--ink); }
.service p { color: var(--body); }

/* ---------- core skills ---------- */
.skills h2 { margin-bottom: 32px; }
.skills-grid {
  display: grid;
  grid-template-columns: 267px 146px 219px 191px;
  gap: 20px;
  width: max-content;
}
.skills-grid li {
  height: 60px;
  border: 2px solid var(--ink);
  border-radius: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px 40px;
  font: 580 20px/1 var(--mix);
  letter-spacing: -.015em;
  color: var(--ink);
  white-space: nowrap;
}

/* ---------- testimonials ---------- */
.testimonials { padding: 48px 0; }
.t-card {
  width: 720px;
  min-height: 298px;
  margin-inline: auto;
  background: #fff;
  border-radius: 16px;
  padding: 16px 80px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 24px;
}
.t-head { display: flex; align-items: center; gap: 16px; }
.t-head h2 { flex: 1; }
.t-quotes { flex: none; }
.t-slides { position: relative; }
.t-slide { color: var(--ink); }
.t-slide:not(.is-active) { display: none; }
.t-slide.is-active { animation: t-in .45s ease; }
@keyframes t-in { from { opacity: 0; transform: translateY(6px); } }
.t-nav { display: flex; justify-content: center; gap: 24px; margin-top: 24px; }

/* ---------- contact ---------- */
.contact-inner { display: flex; flex-direction: column; align-items: center; gap: 32px; text-align: center; }
.contact-sub { max-width: 600px; color: var(--body); }
.contact .btn-row { justify-content: center; }

/* ---------- footer ---------- */
.site-footer {
  border-top: 1px solid rgba(41, 45, 50, .1);
  padding: 64px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* ---------- wand cursor ---------- */
.wand {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 9999;
  width: 60px;
  height: 128px;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s;
  will-change: transform;
}
.wand img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* soft pink halo + gentle idle sway (ported from the old site) */
  filter: drop-shadow(0 0 10px rgba(247, 147, 206, .95)) drop-shadow(0 0 28px rgba(247, 147, 206, .6));
  animation: wand-sway 2.8s ease-in-out infinite;
}
@keyframes wand-sway {
  0%, 100% { transform: rotate(12deg); }
  50% { transform: rotate(6deg) translateY(-2px); }
}
html.wand-on .wand.is-visible { opacity: 1; }
html.wand-on, html.wand-on a, html.wand-on button { cursor: none; }

/* ---------- reveals ---------- */
html.js [data-reveal] { opacity: 0; transform: translateY(16px); transition: opacity .7s ease, transform .7s ease; }
html.js [data-reveal].in { opacity: 1; transform: none; }

/* ---------- tablet (<=1024, reference frame 800) ---------- */
@media (max-width: 1024px) {
  .container { max-width: 800px; }
  .section { padding: 96px 0; }
  h2 { font-size: 40px; }

  .about-grid { flex-direction: column; gap: 24px; }
  .about-col { width: auto; }
  .about-photo { width: 200px; height: 200px; }

  .cards-col { width: calc(50% - 16px); }
  .card { height: auto; aspect-ratio: 324 / 274; }
  .card-ginclub { aspect-ratio: 324 / 580; }
  .card-label { font-size: 20px; }
  /* WCAG AA: at <=1024px the label is normal-size text — darken the light e-commerce cover */
  .card-ecommerce::after { background: linear-gradient(180deg, rgba(41, 45, 50, .55) 44.4%, rgba(102, 102, 102, 0) 100%); }

  .services-cols { gap: 32px; }
  .services-cols h2 { width: 234px; }
  .services-list { width: auto; flex: 1; }
  .service h3 { font-size: 20px; }
  .xp-who h3 { font-size: 20px; }
  .testimonials { padding: 48px 0; }

  .skills { padding: 120px 0; }
  .skills-scroll { overflow-x: auto; scrollbar-width: none; margin-inline: calc(50% - 50vw); padding-inline: max(60px, calc(50vw - 340px)); }
  .skills-scroll::-webkit-scrollbar { display: none; }

  .t-card { width: min(640px, 100%); }
  .t-head h2 { font-size: 40px; }
  .t-quotes { width: 82px; height: 82px; }

  .contact-sub { max-width: 500px; }
  .site-footer { padding: 64px 32px; }
}

/* ---------- mobile (<=640, reference frame 375) ---------- */
@media (max-width: 640px) {
  .container { padding-inline: 24px; }
  .section { padding: 80px 0; }
  h2 { font-size: 32px; letter-spacing: -.01em; }

  .hero .container { padding-inline: 16px; }
  .hero-body { height: 591px; }
  .hero .btn-row { gap: 11px; }
  .hero-content { height: 100%; }
  .hero-title .br-d { display: none; }
  /* narrow screens crop the glow to its hot core — shorten it to the mobile hero
     and calm the saturation so the headline stays comfortably readable */
  .hero-glow { height: 720px; opacity: .62; }

  .about-photo { width: 194px; height: 194px; align-self: center; }

  .xp-head { flex-direction: column; align-items: flex-start; gap: 12px; }
  .xp-wrap { padding-left: 38px; }
  .xp-who h3 { font-size: 18px; }

  .portfolio h2 { margin-bottom: 24px; }
  .cards-group { gap: 24px; }
  .cards-group + .cards-group { margin-top: 24px; }
  .cards-col { width: calc(50% - 12px); gap: 24px; }
  .card, .card-ginclub { aspect-ratio: 151.5 / 200; }
  .card-label { font-size: 18px; top: 24px; left: 24px; right: 24px; }
  /* the CTA moves into the empty grid cell under the Gin Club card (as in the mobile frame) */
  .portfolio-cta { display: none; }
  .portfolio-cta-cell { display: flex; aspect-ratio: 151.5 / 200; align-items: center; justify-content: center; }

  .services-cols { flex-direction: column; gap: 40px; }
  .services-cols h2 { width: auto; }
  .service h3 { font-size: 18px; }

  .skills { padding: 120px 0; }
  .skills .container { padding-inline: 16px; }
  .skills-scroll { padding-inline: 16px; }

  .testimonials { padding: 48px 0; }
  .testimonials .container { padding-inline: 16px; }
  .t-card { padding: 16px; min-height: 0; }
  .t-head h2 { font-size: 32px; }

  .site-footer { padding: 64px 24px; }
  .site-footer .nav-pill { width: auto; padding: 16px 20px; gap: 24px; }
}

/* ---------- wide screens: proportional upscale of the 1280 design frame ---------- */
@media (min-width: 1400px) { body { zoom: 1.125; } }  /* 1440-1512: MacBook 13-15" default */
@media (min-width: 1600px) { body { zoom: 1.25; } }   /* 1680-1728: MacBook 16", small desktops */
@media (min-width: 1920px) { body { zoom: 1.5; } }    /* FullHD+ */
@media (min-width: 2400px) { body { zoom: 1.875; } }  /* QHD/4K */

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .marquee-track { animation: none; }
  .btn-primary::after, .btn-pair::after,
  button.btn-circle::after, a.btn-circle::after { animation: none !important; }
  .wand img { animation: none; }
  html.js [data-reveal] { opacity: 1; transform: none; transition: none; }
  html.js .xp-entry[data-reveal]::before,
  html.js .xp-entry[data-reveal] .xp-head,
  html.js .xp-entry[data-reveal] .xp-bullets li { opacity: 1; transform: none; transition: none; }
  /* typewriter off: show the whole headline, hide the caret */
  html.tw .hero-title, .hero-title .tw-c { visibility: visible; }
  .tw-caret { display: none; }
  .card img, .arrow, .btn-secondary, .btn-circle { transition: none; }
  .social-icon { transition: background .2s; } /* keep the colour swap, drop the scale motion */
  .social:hover .social-icon, .social:focus-visible .social-icon { transform: none; }
  .wand { display: none; }
  html.wand-on, html.wand-on a, html.wand-on button { cursor: auto; }
}
