/* =========================================================
   Alesia Titova — Portfolio
   Structure inspired by editorial dark portfolios (guglieri.com):
   bold oversized type, name + local time header, hairline nav.
   ========================================================= */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap');
/* Inter is the same family guglieri.com uses for its body/nav text (verified
   via document.fonts). Its display headline uses a custom "Raveo Variable"
   font that isn't publicly licensed, so headlines here use Inter at Black
   (900) — the heaviest legitimately-available cut — for a similarly bold feel. */

:root {
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* ---- dark theme (default) ---- */
  --bg: #0a0a0a;
  --bg-alt: #111111;
  --text: #f5f5f5;
  --text-muted: #9a9a9a;
  --text-faint: #6b6b6b;
  --border: #262626;
  --accent: #7c8cff;
  --accent-text: #0a0a0a;
  --card-bg: #131313;
  --chip-bg: #1a1a1a;
  --shadow: 0 20px 40px -20px rgba(0,0,0,0.6);

  /* Neutral placeholder gray for not-yet-added images (moodboard).
     Intentionally NOT redefined per theme — stays a consistent mid-gray
     "missing image" swatch whether the site is in dark or light mode. */
  --placeholder: #8a8a8a;
  --placeholder-light: #c2c2c2;
}

:root[data-theme="light"] {
  --bg: #fafafa;
  --bg-alt: #f0f0f0;
  --text: #111111;
  --text-muted: #55555a;
  --text-faint: #8a8a8a;
  --border: #e2e2e2;
  --accent: #4148c9;
  --accent-text: #ffffff;
  --card-bg: #ffffff;
  --chip-bg: #eeeeee;
  --shadow: 0 20px 40px -20px rgba(0,0,0,0.15);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #fafafa;
    --bg-alt: #f0f0f0;
    --text: #111111;
    --text-muted: #55555a;
    --text-faint: #8a8a8a;
    --border: #e2e2e2;
    --accent: #4148c9;
    --accent-text: #ffffff;
    --card-bg: #ffffff;
    --chip-bg: #eeeeee;
    --shadow: 0 20px 40px -20px rgba(0,0,0,0.15);
  }
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  transition: background-color .3s ease, color .3s ease;
  overflow-x: hidden;
}

.container {
  width: 100%;
  padding: 0 32px;
}

a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
img { max-width: 100%; display: block; }

/* ---------------- Top bar ---------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
}

.topbar-grid {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 40px;
  padding: 28px 32px 22px;
}

.topbar-id {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
}

.topbar-name {
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.01em;
}

.topbar-clock {
  font-size: 0.85rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.topbar-lead {
  max-width: 440px;
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--text-muted);
  text-align: right;
}

.hairline {
  height: 1px;
  background: var(--border);
  width: 100%;
}

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 32px;
}

.main-nav {
  display: flex;
  gap: 28px;
}

.main-nav a {
  font-size: 0.85rem;
  color: var(--text-muted);
  transition: color .2s ease;
}

.main-nav a:hover { color: var(--text); }

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.theme-toggle {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color .2s ease, transform .2s ease;
}
.theme-toggle:hover { border-color: var(--text-muted); transform: scale(1.05); }
.theme-toggle svg { width: 17px; height: 17px; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }

.nav-toggle {
  display: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: transparent;
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
}
.nav-toggle span {
  width: 15px;
  height: 1.5px;
  background: var(--text);
  display: block;
}

/* ---------------- Hero ---------------- */
/* Full-screen hero: fills the viewport height, title block vertically
   centered in the remaining space, companies strip pushed down to the
   bottom edge (with breathing room from min-height + padding). */
.hero {
  min-height: 78vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 72px 0 40px;
}

.hero-container {
  flex: 1;
  display: flex;
  align-items: center;
}

/* Positions the title/button block so it starts exactly at the horizontal
   center of the page and extends to the right — text stays left-aligned
   inside that block, it's just the block itself that's pushed over. */
.hero-content {
  margin-left: 50%;
  max-width: 560px;
  text-align: left;
}

.hero-title {
  font-size: clamp(2.2rem, 4.6vw, 3.6rem);
  line-height: 1.12;
  font-weight: 900;
  letter-spacing: -0.02em;
  margin: 0 0 40px;
  max-width: 100%;
}

/* Plain white/text color — no accent tint. */
.hero-title .accent { color: inherit; }

.hero-row {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-bottom: 64px;
}

.pill-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: var(--text);
  color: var(--bg);
  padding: 15px 22px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.92rem;
  border: none;
  cursor: pointer;
  transition: transform .2s ease, opacity .2s ease;
}
.pill-btn:hover { transform: translateY(-2px); opacity: 0.9; }
.pill-btn svg { width: 16px; height: 16px; }
.pill-btn-lg { padding: 18px 28px; font-size: 1rem; }

/* Full-bleed: sits outside .container, so it spans the entire screen width
   rather than being capped at the 1180px content column. */
.hero-companies {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 28px;
  width: 100%;
  padding: 24px 32px 0;
  border-top: 1px solid var(--border);
}
.hero-companies li {
  font-size: 0.85rem;
  color: var(--text-muted);
}
.hero-companies strong { color: var(--text); font-weight: 600; }

/* Small case-preview thumbnails under a Work Experience entry (About page). */
/* Fixed height (2x the original 64px), width follows each image's own
   aspect ratio (--ar, set inline) instead of being force-cropped to a
   square — so every thumbnail in a row matches height but keeps its real
   proportions. Falls back to 4/3 for the gray placeholders, which have no
   real image to derive a ratio from. */
.case-thumbs { display: flex; gap: 6px; margin-top: 14px; }
.case-thumb {
  height: 128px;
  width: auto;
  aspect-ratio: var(--ar, 4 / 3);
  border-radius: 6px;
  background: var(--placeholder);
  background-size: cover;
  background-position: center;
  flex-shrink: 0;
}

/* ---------------- UA Experience page ---------------- */
/* Two-column layout: "UA Experience" heading in a narrow left column, the
   company list in a wide right column that stretches to the container's
   right edge (not the viewport edge — .container still has its normal side
   padding). 1fr / 3fr keeps the heading column compact (~1/4 width) and
   gives the content column the remaining ~3/4; column-gap pushes the
   content column further right and opens up visible air between the
   heading and the cases. */
.ua-row {
  display: grid;
  grid-template-columns: 1fr 3fr;
  column-gap: 72px;
}

.ua-list {
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.ua-company-head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 14px;
}
.ua-company-logo {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: var(--placeholder);
  flex-shrink: 0;
  overflow: hidden;
}
.ua-company-logo img { width: 100%; height: 100%; object-fit: cover; }

/* Name + role stack; flex:1 is what pushes the case-study button (or
   "Coming soon" label) all the way to the right edge of the head. */
.ua-company-titles { flex: 1; min-width: 0; }
.ua-company-head h3 { margin: 0 0 3px; font-size: 1.05rem; font-weight: 700; }
.ua-company-role {
  margin: 0;
  font-size: 0.88rem;
  color: var(--text-muted);
}

.case-study-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 14px 26px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text);
  background: transparent;
  white-space: nowrap;
  transition: background-color .2s ease, border-color .2s ease;
}
.case-study-btn:hover {
  background: color-mix(in srgb, var(--text) 8%, transparent);
  border-color: var(--text-muted);
}
/* Used in place of the button for projects with no case study up yet
   (Recraft, Prop.EXPERT) — same pill shape, muted and not clickable. */
.case-study-btn.is-disabled {
  color: var(--text-muted);
  cursor: default;
  pointer-events: none;
}

.ua-company > p {
  color: var(--text-muted);
  line-height: 1.7;
  font-size: 0.95rem;
  margin: 0 0 20px;
}

/* Fixed 5-column grid: tiles are sized by fr units (not a fixed px), so
   exactly 5 always fit edge-to-edge across the content column's width,
   whatever that width is — no overflow, no clipping. Only the first 10
   placeholders (2 full rows) are shown; any extra .ua-example markup in the
   HTML beyond that is hidden rather than wrapping to a 3rd row. */
.ua-examples {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 16px;
  width: 100%;
}
.ua-example {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 6px;
  background: var(--placeholder-light);
}
.ua-example:nth-child(n + 11) {
  display: none;
}

@media (max-width: 560px) {
  .ua-examples { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .ua-example:nth-child(n + 7) {
    display: none;
  }
}

/* ---------------- UX/UI Works page ---------------- */
/* Same .ua-row / .ua-company skeleton as ua-experience.html, but each
   project shows just 2 large square images side by side instead of a grid
   of small squares. */
.uxui-examples {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  width: 100%;
}
.uxui-example {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  background: var(--placeholder-light);
  background-size: cover;
  background-position: center;
}

@media (max-width: 560px) {
  .uxui-examples { grid-template-columns: 1fr; gap: 12px; }
}

/* A .uxui-examples block can also be the <a class="case-study-trigger">
   itself (see EatMise on uxui-works.html) when a real case study page
   exists to link to — same grid, just clickable. */
.uxui-examples.case-study-trigger { display: grid; }

/* Variant: one wide image on top, three squares in a row below (see Opes
   Exchange) — same gap as the plain 2-up grid, just a 3-column track with
   the first item spanning all of them. */
.uxui-examples-1-3 { grid-template-columns: repeat(3, 1fr); }

/* A "wide" tile spans every column of whatever grid it's in and switches
   to its own aspect ratio instead of the square default — used both by the
   1-3 variant above and directly in the plain 2-up grid (see EatMise: 2
   squares, then two of these stacked as their own full-width rows). */
.uxui-example-wide {
  grid-column: 1 / -1;
  aspect-ratio: var(--ar, 16 / 9);
}

@media (max-width: 560px) {
  .uxui-examples-1-3 { grid-template-columns: 1fr; }
}

/* ---------------- Case study hover preview ---------------- */
/* Hovering a .case-study-trigger floats two tilted preview icons to the
   left of the cursor and swaps the custom cursor dot for a translucent
   "Case study" pill (see .is-hidden-for-case above). Markup for the icons
   and badge starts nested inside the trigger and gets re-parented to
   <body> by script.js — same reason .link-preview does that: an ancestor's
   .reveal transform would otherwise break position:fixed. */
.case-preview-icon {
  position: fixed;
  top: 0;
  left: 0;
  width: 200px;
  height: 200px;
  background: transparent;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  /* Two lighter, more diffuse layers read as a soft shadow — a single
     strong drop-shadow followed the icon's alpha silhouette too crisply
     and looked harsh/"dirty", especially where icons overlap. */
  filter: drop-shadow(0 6px 10px rgba(0,0,0,0.12)) drop-shadow(0 14px 28px rgba(0,0,0,0.14));
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -50%) rotate(var(--tilt, -6deg)) scale(0.85);
  transition: opacity .35s cubic-bezier(.22,1,.36,1), transform .35s cubic-bezier(.22,1,.36,1);
  z-index: 9990;
}
.case-preview-icon.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(var(--tilt, -6deg)) scale(1);
}
/* Each next icon renders in front of the previous one, fanning toward the
   cursor — the overlapping-cards look. Room for up to 5 (the .case-preview-
   badge sits at z-index 10000, comfortably above all of these). */
.case-preview-icon-2 { z-index: 9991; }
.case-preview-icon-3 { z-index: 9992; }
.case-preview-icon-4 { z-index: 9993; }
.case-preview-icon-5 { z-index: 9994; }
/* Slightly bigger than the 200px default (see Opes Exchange's icon-1). */
.case-preview-icon-lg {
  width: 230px;
  height: 230px;
}
/* In a 3-icon fan (see Liga Stavok) the two flanking icons sit in front of —
   and read slightly smaller than — the centered one behind them. */
.case-preview-icon-sm {
  width: 180px;
  height: 180px;
}
/* Half size, for a scattered cluster of small badge icons (see Star2Pay). */
.case-preview-icon-xs {
  width: 100px;
  height: 100px;
}
/* Same case-study icons, ~2.2x smaller — used on About's compact
   .case-thumbs previews instead of the full-size ones on uxui-works.html.
   -tiny pairs with the plain/default 200px icon, -tiny-sm with -sm (180px). */
.case-preview-icon-tiny {
  width: 90px;
  height: 90px;
}
.case-preview-icon-tiny-sm {
  width: 80px;
  height: 80px;
}
/* Rounds off a screenshot/card icon's own corners (see Opes Exchange's QR
   card) instead of showing it edge-to-edge. */
.case-preview-icon-rounded {
  border-radius: 20px;
  overflow: hidden;
}

.case-preview-badge {
  position: fixed;
  top: 0;
  left: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 13px 22px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 55%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--bg);
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.7);
  transition: opacity .3s ease, transform .3s ease;
  z-index: 10000;
}
.case-preview-badge.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

@media (max-width: 680px) {
  /* No mouse cursor to follow on touch devices — skip the preview, same as
     .link-preview. */
  .case-preview-icon, .case-preview-badge { display: none; }
}

/* ---------------- Case study pages (e.g. case-eatmise.html) ---------------- */
.case-back-link {
  display: inline-block;
  margin-bottom: 40px;
  font-size: 0.9rem;
  color: var(--text-muted);
  transition: color .2s ease;
}
.case-back-link:hover { color: var(--text); }

/* Same sticky-in-a-stretched-grid-cell trick as .info-label (see the note
   there): .info-label-cell stretches to the full height of .ua-list next to
   it, and this is what sticks inside that tall box as the write-up scrolls —
   logo, title, role and intro description staying in view on the left. */
.case-side {
  position: sticky;
  top: 200px;
}

.case-hero {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 24px;
}
.case-hero h1 {
  margin: 0 0 3px;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.01em;
}

.case-description {
  color: var(--text-muted);
  line-height: 1.7;
  font-size: 1rem;
  max-width: 680px;
  margin: 0 0 48px;
}

/* Long-form case study body: a heading + description/bullets, repeated as
   many times as the write-up needs, interleaved with .case-images blocks
   between them (see case-star2pay.html). */
.case-section { margin: 0 0 56px; }
/* When this body sits inside .ua-list (the sticky-sidebar layout — see
   case-star2pay.html), .ua-list's own flex `gap` already spaces every
   block out, so drop the block's own bottom margin instead of stacking
   both and doubling the gap. */
.ua-list > .case-images,
.ua-list > .case-section {
  margin-bottom: 0;
}
.case-section .case-description { margin: 0 0 20px; }
.case-section .case-description:last-child { margin-bottom: 0; }
.case-section-heading {
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 16px;
  color: var(--text);
}

.case-images {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  margin-bottom: 56px;
}
.case-images:last-child { margin-bottom: 0; }
/* Same idea as .uxui-examples-1-3: a wide tile on top, three squares below
   (see the Opes Exchange case study). */
.case-images-1-3 { grid-template-columns: repeat(3, 1fr); }
.case-image {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  background: var(--placeholder-light);
  background-size: cover;
  background-position: center;
}
/* Same idea as .uxui-example-wide: spans the full row and switches to a
   wide aspect ratio instead of the square default. */
.case-image-wide {
  grid-column: 1 / -1;
  aspect-ratio: var(--ar, 16 / 9);
}

@media (max-width: 680px) {
  .case-images { grid-template-columns: 1fr; }
}

/* ---------------- Gallery (images only, no headings) ---------------- */
/* A stack of masonry blocks with side padding and gaps between tiles.
   Masonry via CSS multi-column: each tile keeps its own aspect ratio
   (landscape / portrait / square) so real photos of any orientation adapt
   to one another. Column count varies block-to-block (2 vs 3 per row) for
   a livelier collage feel — a single multi-column container can't mix
   column widths within itself, hence the separate blocks. */
.gallery-section { padding: 0; }

.moodboard-full {
  width: 100%;
  padding: 0 32px 14px;
}
.moodboard-full .moodboard-item { margin-bottom: 0; }

.moodboard-grid {
  columns: 2;
  column-gap: 14px;
  column-fill: balance;
  width: 100%;
  padding: 0 32px;
  /* No bottom padding: the trailing .moodboard-item's own margin-bottom
     (14px) already provides the gap before the next block, and margins
     don't collapse out through a multicol container's edge — adding
     padding here on top of that doubled the vertical gap to 28px while
     the horizontal column-gap stayed 14px, making spacing uneven. */
}

.moodboard-grid.cols-3 { columns: 3; }

/* --ar is set inline per tile to the image's real width/height, so the tile
   shape matches the photo almost exactly and background-size:cover has
   little to nothing left to crop. Falls back to square if --ar is unset
   (e.g. the empty gray placeholders on the About page). */
.moodboard-item {
  width: 100%;
  aspect-ratio: var(--ar, 1 / 1);
  break-inside: avoid;
  margin: 0 0 14px;
  border-radius: 6px;
  background: var(--placeholder);
  background-size: cover;
  background-position: center;
}

@media (max-width: 900px) {
  .moodboard-grid.cols-3 { columns: 2; }
}

@media (max-width: 640px) {
  .moodboard-grid { columns: 1; padding: 0 20px; }
  .moodboard-full { padding: 0 20px 14px; }
}

/* Strict 3-up grid — unlike .moodboard-grid (CSS multi-column masonry,
   which lets column heights drift apart and can leave uneven gaps at the
   bottom of a column), this is a real grid: every row lines up, and the
   14px gap is identical horizontally and vertically. Tiles fall back to
   the default square aspect ratio (no per-image --ar) so every row is the
   same height — the tradeoff that makes an even grid possible. */
.moodboard-grid-even {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  width: 100%;
  padding: 0 32px;
}
.moodboard-grid-even .moodboard-item { margin: 0; }

@media (max-width: 900px) {
  .moodboard-grid-even { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .moodboard-grid-even { grid-template-columns: 1fr; padding: 0 20px; }
}

/* ---------------- Sections generic ---------------- */
/* padding-top/bottom only (not the shorthand) — #contact combines this with
   .container, and the shorthand would otherwise clobber .container's left/
   right padding since both are single-class selectors of equal specificity. */
.section { padding-top: 96px; padding-bottom: 96px; }

.section-subtitle {
  color: var(--text-muted);
  max-width: 560px;
  font-size: 1rem;
  line-height: 1.6;
  margin: 0 0 48px;
}

/* ---------------- About: Info & Work Experience ---------------- */
/* Same two-column idea as the footer contact block: label flush left,
   content column starting at the horizontal center. Items stretch (default)
   rather than align-items:start so .info-label-cell's grid cell is as tall
   as the content column — that height is what gives the sticky heading
   inside it room to travel down the section as you scroll, instead of
   scrolling away.
   The sticky heading is deliberately NOT the grid item itself: a grid item
   sized via align-items:stretch doesn't reliably support position:sticky on
   itself in every browser, so a plain (non-positioned) wrapper div takes the
   stretch, and the <h2> sticks inside it. */
.info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
}

/* Plain grid item that stretches to the row's full height (see note above);
   holds nothing but the sticky <h2 class="info-label">. */
.info-label-cell {
  min-width: 0;
}

/* Also used for the "UA Experience" heading in .ua-row (ua-experience.html),
   which relies on the same stretch + sticky wrapper pattern. */
.info-label {
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0;
  position: sticky;
  top: 200px;
}

.info-content p {
  color: var(--text-muted);
  line-height: 1.7;
  font-size: 1.02rem;
  max-width: 640px;
  margin: 0 0 20px;
}

.info-subhead {
  font-size: 1.05rem;
  font-weight: 700;
  margin: 28px 0 14px;
  color: var(--text);
}

.info-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 640px;
  margin: 0 0 32px;
}
.info-list li {
  position: relative;
  padding-left: 24px;
  color: var(--text-muted);
  line-height: 1.6;
  font-size: 0.98rem;
}
.info-list li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 0.55em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}
/* Theme-aware dots specifically for case-study bullet lists (see
   case-star2pay.html) instead of the accent color used elsewhere (e.g.
   About's "What I do"): white on the dark theme, black on the light theme. */
.case-section .info-list li::before {
  background: var(--text);
}

.tag-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-width: 680px;
}
.tag-pill {
  padding: 7px 14px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  border: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--text-muted);
}

.experience-list {
  display: flex;
  flex-direction: column;
  gap: 56px;
  max-width: 680px;
}

.experience-head {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 16px;
}
.experience-logo {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: var(--placeholder);
  flex-shrink: 0;
  overflow: hidden;
}
.experience-titles { flex: 1; }
.experience-titles h3 {
  margin: 0 0 4px;
  font-size: 1.05rem;
  font-weight: 700;
}
.experience-role {
  margin: 0;
  font-size: 0.88rem;
  color: var(--text-muted);
}
.experience-dates {
  flex-shrink: 0;
  font-size: 0.78rem;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--chip-bg);
  border: 1px solid var(--border);
  color: var(--text-muted);
  white-space: nowrap;
}
.experience-item p {
  color: var(--text-muted);
  line-height: 1.7;
  font-size: 0.95rem;
  margin: 0 0 12px;
}

.experience-meta {
  margin: 0 0 4px;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.experience-bullets {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.experience-bullets li {
  position: relative;
  padding-left: 18px;
  color: var(--text-muted);
  line-height: 1.6;
  font-size: 0.95rem;
}
.experience-bullets li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

.experience-skills {
  margin: 8px 0 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.experience-skills strong { color: var(--text); }

/* Every entry's description sits behind the same gray rail, whether it's a
   single paragraph, a bullet list, or a project blurb + skills line — one
   consistent look across all Work Experience cards. */
.experience-body {
  margin-top: 16px;
  padding-left: 24px;
  border-left: 2px solid var(--border);
}
.experience-body > *:last-child { margin-bottom: 0; }

@media (max-width: 680px) {
  .info-grid { grid-template-columns: 1fr; gap: 20px; }
  .ua-row { grid-template-columns: 1fr; gap: 20px; }
  .experience-head { flex-wrap: wrap; }
  .experience-dates { margin-left: 72px; }
}

/* ---------------- Contact (inside footer) ---------------- */
/* Two columns: plain text on the left (flush with the page's normal left
   edge), bold link list starting at the horizontal center — matches the
   reference layout (text left, links starting mid-page). */
.footer-contact-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  align-items: start;
}

/* Text + email live in the same <p>, so every line (incl. the email) shares
   one line-height with no extra gap between them. */
.footer-contact-text {
  font-size: clamp(1.3rem, 2.4vw, 1.7rem);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.5;
  margin: 0;
  color: var(--text);
}

.footer-contact-email {
  color: var(--text);
  transition: color .2s ease;
}
.footer-contact-email:hover { color: var(--text-muted); }

.social-links {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-weight: 700;
  font-size: clamp(1.3rem, 2.4vw, 1.7rem);
}
.social-links a:hover { color: var(--text-muted); }

/* Small tilted brand-icon badge that follows the mouse cursor (positioned
   via JS in script.js, which sets left/top on mousemove and toggles
   .is-visible). position:fixed + viewport coordinates from the mousemove
   event, so it tracks the cursor regardless of where the link sits. The
   icon SVGs already include their own rounded-square background, so this
   element just sizes and places them — no extra radius/background needed.
   --tilt is set per-icon inline (see HTML) so each badge leans a slightly
   different way instead of all sharing one angle. */
.link-preview {
  position: fixed;
  left: 0;
  top: 0;
  width: 72px;
  height: 72px;
  background: transparent;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  filter: drop-shadow(0 14px 24px rgba(0,0,0,0.35));
  opacity: 0;
  pointer-events: none;
  transform: rotate(var(--tilt, -6deg)) scale(0.85);
  transition: opacity .35s cubic-bezier(.22,1,.36,1), transform .35s cubic-bezier(.22,1,.36,1);
  z-index: 200;
}

.link-preview.is-visible {
  opacity: 1;
  transform: rotate(var(--tilt, -6deg)) scale(1);
}

@media (max-width: 680px) {
  /* No mouse cursor to follow on touch devices — skip the preview. */
  .link-preview { display: none; }
}

/* ---------------- Custom cursor ---------------- */
/* A small white dot with mix-blend-mode: difference — this is what makes it
   auto-invert against whatever is underneath (black on light backgrounds,
   white on dark ones) with no JS color detection needed. Only enabled (via
   the .has-custom-cursor class added in script.js) on devices with an
   actual mouse, so touch devices keep their normal behavior. */
.custom-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  mix-blend-mode: difference;
  pointer-events: none;
  opacity: 0;
  z-index: 9999;
  transition: opacity .2s ease, width .15s ease, height .15s ease;
}
.custom-cursor.is-active { opacity: 1; }
.custom-cursor.is-hovering-link { width: 22px; height: 22px; }
/* Hidden while hovering a .case-study-trigger — the "Case study" badge
   (.case-preview-badge) takes over as the cursor there instead. */
.custom-cursor.is-hidden-for-case { opacity: 0; }

.has-custom-cursor,
.has-custom-cursor a,
.has-custom-cursor button,
.has-custom-cursor .moodboard-item.is-clickable,
.has-custom-cursor .lightbox-image,
.has-custom-cursor .case-study-trigger {
  cursor: none;
}

/* ---------------- Footer ---------------- */
.site-footer { border-top: 1px solid var(--border); }
/* Feed (index.html) only — no divider between the moodboard and the footer. */
.site-footer.no-top-border { border-top: none; }
.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 28px 32px;
  font-size: 0.82rem;
  color: var(--text-faint);
}
.footer-inner a:hover { color: var(--text); }

/* ---------------- Reveal animation ---------------- */
/* Blocks fade up AND come into focus — starts slightly blurred (out of
   focus) and sharpens to blur(0) at the same time opacity/position settle,
   site-wide. */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  filter: blur(8px);
  transition: opacity 1.1s ease, transform 1.1s ease, filter 1.1s ease;
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}

/* ---------------- Responsive ---------------- */
@media (max-width: 860px) {
  .topbar-grid { flex-direction: column; gap: 14px; }
  .topbar-lead { text-align: left; }
  .hero-content { margin-left: 0; max-width: 100%; }
  .footer-contact-inner { grid-template-columns: 1fr; gap: 28px; }
}

@media (max-width: 680px) {
  .main-nav {
    position: fixed;
    /* Sits below the sticky header (measured height, see --header-h in
       script.js) rather than at the very top, so the header — and the
       close/hamburger icon in it — stays visible above the open panel. */
    top: var(--header-h, 76px);
    left: 0;
    right: 0;
    width: 100%;
    max-height: 50vh;
    background: var(--bg);
    /* Grid (not flex) so the column of links can be sized to its widest
       item (grid-template-columns: max-content) and that single column
       centered as a block via justify-content — giving a centered group
       whose item texts still share one left edge (justify-items: start),
       instead of each link centering independently at a different width. */
    display: grid;
    grid-template-columns: max-content;
    justify-content: start;
    justify-items: start;
    row-gap: 36px;
    /* Height is intrinsic (padding + content) rather than a fixed 50vh, so
       the gap above the first item and below the last stays small and
       symmetric instead of the group floating centered in a tall box. */
    padding: 28px 28px;
    /* Simple, quick fade instead of a slide-down panel. */
    opacity: 0;
    visibility: hidden;
    transition: opacity .12s ease, visibility .12s ease;
    z-index: 60;
  }
  .main-nav.open { opacity: 1; visibility: visible; }
  .main-nav a { font-size: 1.05rem; }
  .nav-toggle { display: flex; }

  /* Hamburger → close (×) morph, driven by .open on the button itself
     (kept separate from .main-nav's own .open so each element's CSS stays
     self-contained). */
  .nav-toggle span { transition: transform .25s ease, opacity .2s ease; }
  .nav-toggle.open span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
  .nav-toggle.open span:nth-child(2) { opacity: 0; }
  .nav-toggle.open span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

  /* Dimmed + blurred backdrop behind the open menu, covering the page
     content beneath it (injected by script.js, one shared div per page).
     Starts below the header (not inset:0) — the header's own background is
     only ~88% opaque, so a full-screen backdrop underneath it would bleed
     through and tint it gray; stopping the backdrop at --header-h keeps
     the header reading as a clean solid color. */
  .nav-backdrop {
    position: fixed;
    top: var(--header-h, 76px);
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(6px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .3s ease, visibility .3s ease;
    z-index: 45;
  }
  .nav-backdrop.open { opacity: 1; visibility: visible; }
  .container { padding: 0 20px; }
  .navbar, .topbar-grid { padding-left: 20px; padding-right: 20px; }
  .footer-inner { padding-top: 44px; padding-bottom: 44px; }

  /* Single-row mobile header: name + local time on the left, theme toggle
     + hamburger on the right — the lead paragraph and the desktop nav row
     are dropped from the visual row entirely rather than stacked above it.
     .topbar-grid collapses to display:contents so .topbar-id lays out
     directly inside the flex row on .topbar itself. .header-actions is
     pulled out with position:fixed instead of using display:contents on
     .navbar — .main-nav (the off-canvas drawer) is also position:fixed and
     a display:contents ancestor breaks its containing-block calculation
     (it collapsed to a ~180px sliver instead of full viewport height), so
     .navbar itself is left as a normal (harmless, now-empty) box. */
  .topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 20px;
  }
  .topbar-grid { display: contents; }
  .topbar-lead { display: none; }
  .topbar > .hairline { display: none; }
  .navbar { padding: 0; }
  .header-actions {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 61;
  }

  .hero { min-height: 80svh; padding: 80px 0 44px; }
  .hero-companies { padding-left: 20px; padding-right: 20px; }
  .section { padding-top: 64px; padding-bottom: 64px; }
}

/* ---------------- Image lightbox ---------------- */
/* Click any .moodboard-item with an image to open it full-screen; click it
   again (or the backdrop, or the ✕) to close. Built + inserted via JS
   (script.js) so it doesn't need to be duplicated in every HTML page.
   cursor:zoom-in here is only a fallback for devices without the custom
   cursor (see .has-custom-cursor above, which sets cursor:none on these
   tiles too) — so the dot never gets swapped out for a native icon. */
.moodboard-item.is-clickable { cursor: zoom-in; }

.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px;
  z-index: 9990;
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s cubic-bezier(.22,1,.36,1), visibility 0s linear .45s;
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity .45s cubic-bezier(.22,1,.36,1);
}

.lightbox-image {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  border-radius: 8px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
  object-fit: contain;
  transform: scale(0.9);
  transition: transform .45s cubic-bezier(.22,1,.36,1);
  cursor: zoom-out;
}
.lightbox.is-open .lightbox-image { transform: scale(1); }

.lightbox-close {
  position: fixed;
  top: 24px;
  right: 24px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9991;
  transition: background-color .2s ease;
}
.lightbox-close:hover { background: rgba(255, 255, 255, 0.22); }
.lightbox-close svg { width: 18px; height: 18px; }

body.lightbox-open { overflow: hidden; }

@media (max-width: 640px) {
  .lightbox { padding: 20px; }
  .lightbox-close { top: 14px; right: 14px; }
}
