/* Mehedi Ahmed, portfolio.
   One page: an intro that ends in the Leave No Witnesses build, the work as a
   timeline (newest first), skills, contact.

   Type is Archivo, the family Liminal Games Studio's site uses, so the two
   read as related. Text sits at normal width. The timeline's years take the
   condensed end of the width axis, so the left column reads as a run of
   dates with the hardware each job shipped on beneath them. The skills hang
   off the same two columns, so the page lines up on them.

   Layout rules are written for wide screens first; the max-width blocks near
   the end take them down to one column for phones. */

:root {
  --gutter: clamp(16px, 4vw, 48px);
  --measure: 72rem;
  --text: 40rem;   /* reading width for paragraphs and lists */
  --when: 11.5rem; /* the timeline's date column */
  --col-gap: clamp(1.5rem, 4vw, 3rem);
  --header: 3.5rem;

  /* favicon.svg, favicon.ico, apple-touch-icon.png and the theme-color tags
     in index.html and 404.html repeat --bg and --fg; change them together */
  --bg: #f6f7fc;
  --fg: #0f111a;
  --muted: #575c78;
  --line: #dde0ec;
  --focus: #163ff3;
  /* Fills image and video frames until they load */
  --frame: #e6e8f2;
  /* The one accent: the timeline's years, the solid button, selection and
     link underlines. One blue in both themes, darker here so it reads on
     the light page. */
  --accent: #163ff3;
  --on-accent: #f6f7fc;

  /* The screenshot viewer is always night, so the screenshots carry the color */
  --viewer-bg: #08090f;
  --viewer-fg: #eceffd;
  --viewer-muted: #9298b8;

  /* Placeholder highlight for text that must be filled in before launch */
  --todo-bg: #ffe08a;
  --todo-fg: #14172f;

  --font: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #08090f;
    --fg: #eceffd;
    --muted: #9298b8;
    --line: #1f2236;
    --focus: #7b93ff;
    --frame: #141726;
    --accent: #7b93ff;
    --on-accent: #08090f;
    --viewer-bg: #040508;
    --viewer-fg: #eceffd;
    --viewer-muted: #9298b8;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #08090f;
  --fg: #eceffd;
  --muted: #9298b8;
  --line: #1f2236;
  --focus: #7b93ff;
  --frame: #141726;
  --accent: #7b93ff;
  --on-accent: #08090f;
  --viewer-bg: #040508;
  --viewer-fg: #eceffd;
  --viewer-muted: #9298b8;
  color-scheme: dark;
}

/* Base */
*, *::before, *::after { box-sizing: border-box; }
/* Otherwise a class that sets display, like .btn, would show a hidden element */
[hidden] { display: none !important; }
html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header) + 1rem);
}
body {
  margin: 0;
  padding-inline: var(--gutter);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.wrap { max-width: var(--measure); margin-inline: auto; }
::selection { background: var(--accent); color: var(--on-accent); }
a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
  text-underline-offset: 0.22em;
  transition: text-decoration-color 0.2s ease;
}
a:hover { text-decoration-color: var(--accent); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Header. Stays at the top, frosted, so the sections are one tap away. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  backdrop-filter: blur(16px) saturate(1.5);
}
.site-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  column-gap: 1rem;
  min-height: var(--header);
}
.site-name {
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
}
.site-nav ul {
  display: flex;
  gap: clamp(1rem, 3vw, 2rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-nav a {
  display: block;
  padding-block: 0.75rem;
  color: var(--muted);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  transition: color 0.2s ease;
}
.site-nav a:hover { color: var(--fg); }

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0.5rem 1.5rem;
  border: 1.5px solid var(--fg);
  border-radius: 999px;
  background: transparent;
  color: var(--fg);
  cursor: pointer;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.btn:hover { background: color-mix(in srgb, var(--fg) 8%, transparent); }
.btn--solid { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.btn--solid:hover {
  border-color: color-mix(in srgb, var(--accent) 84%, var(--bg));
  background: color-mix(in srgb, var(--accent) 84%, var(--bg));
}
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.625rem; }

/* Intro: who, what and how to reach him, then the build itself, so a visitor
   sees the work before the first paragraph about it. On wide screens the
   name sits left and the lead right; the source order (name, title, lead,
   buttons) is the reading order at every width. */
.intro { padding-block: clamp(1.25rem, 4.5vw, 3.25rem) 0; }
.intro-text {
  display: grid;
  gap: 1.125rem var(--col-gap);
}
.intro h1 {
  margin: 0 0 0 -0.04em;
  font-size: clamp(2.75rem, 7.2vw, 5.25rem);
  font-weight: 760;
  line-height: 0.92;
  letter-spacing: -0.045em;
}
.intro .title {
  max-width: 26em;
  margin: 0.875rem 0 0;
  font-size: clamp(1.125rem, 1.9vw, 1.4375rem);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.lead {
  max-width: 34rem;
  margin: 0;
  line-height: 1.55;
  text-wrap: pretty;
}
.intro .actions { margin-top: 1.125rem; }
.intro .gallery { margin-top: clamp(2.25rem, 5vw, 3.5rem); }

/* Section headings */
.section-title {
  margin: 0 0 clamp(1rem, 3vw, 1.75rem);
  font-size: clamp(1.75rem, 3.6vw, 2.5rem);
  font-weight: 750;
  line-height: 1;
  letter-spacing: -0.03em;
}
.work { padding-top: clamp(3.5rem, 8vw, 6rem); }

/* Timeline. Each entry is a row: the years and platforms on the left,
   held in view while you read the entry, and the work on the right. */
.entry {
  display: grid;
  grid-template-columns: var(--when) minmax(0, 1fr);
  grid-template-areas: "when head" "when body";
  grid-template-rows: auto 1fr;
  column-gap: var(--col-gap);
  padding-block: clamp(1.75rem, 4.5vw, 2.75rem);
  border-top: 1px solid var(--line);
}
/* The rule sits between entries, so the first one goes without */
.section-title + .entry { padding-top: 0; border-top: 0; }
.entry-head { grid-area: head; }
.entry-body { grid-area: body; }
.when {
  grid-area: when;
  align-self: start;
  position: sticky;
  top: calc(var(--header) + 1.25rem);
  margin: 0;
}
.years {
  display: block;
  color: var(--accent);
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  font-stretch: 62%;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 0.95;
  letter-spacing: -0.01em;
}
.platforms {
  display: block;
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: 0.9375rem;
  font-stretch: 87.5%;
  line-height: 1.4;
}
.entry h3 {
  margin: 0;
  font-size: clamp(1.375rem, 2.4vw, 1.75rem);
  font-weight: 720;
  line-height: 1.15;
  letter-spacing: -0.022em;
}
.role { margin: 0.25rem 0 0; color: var(--muted); }
.entry-body p,
.points { max-width: var(--text); }
.entry-body p { margin: 0.75rem 0 0; text-wrap: pretty; }
.points { margin: 0.75rem 0 0; padding-left: 1.25rem; }
.points li { padding-left: 0.25rem; }
.points li + li { margin-top: 0.5rem; }
.points li::marker { color: var(--muted); }

/* A game or app inside an entry */
.project { margin-top: 2.25rem; }
.project h4 {
  margin: 0;
  font-size: 1.1875rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.015em;
}
.project h4 + p { margin-top: 0.25rem; }
.built { color: var(--muted); }

.links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; }
.links a { font-weight: 600; }
.entry-body .links { margin-top: 1.75rem; }

/* Screenshots. Every shot is a thumbnail, six to a row (three on phones),
   so within the timeline every gallery's thumbnails are the same size. A
   .gallery--lead also runs its first shot the full column: current work
   gets one, older roles get the thumbnails alone. Keep one aspect ratio
   within a gallery so its row lines up. Each shot opens the viewer, or the
   full-size image without script. */
.gallery { margin: 1.25rem 0 0; }
.gallery-shots {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.gallery-shots a {
  display: block;
  overflow: hidden;
  border-radius: 0.25rem;
  background: var(--frame);
  cursor: zoom-in;
}
.gallery-shots img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.5s var(--ease-out);
}
.gallery-shots a:hover img { transform: scale(1.05); }
.gallery--lead li:first-child { grid-column: 1 / -1; }
.gallery--lead li:first-child a { border-radius: 0.5rem; }
.gallery--lead li:first-child a:hover img { transform: scale(1.015); }
.gallery figcaption {
  max-width: var(--text);
  margin-top: 0.75rem;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.45;
}
.gallery figcaption a { color: var(--fg); font-weight: 600; }
/* A caption above the shots names the game before you see it */
.gallery figcaption:first-child { max-width: none; margin: 0 0 0.875rem; }
.gallery-name {
  display: block;
  margin-bottom: 0.125rem;
  color: var(--fg);
  font-size: clamp(1.1875rem, 1.8vw, 1.375rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.015em;
}

/* Videos. Each starts as its poster frame, which links to YouTube. With the
   script, pressing it swaps in the player right here. */
.media { margin: 0; }
.video {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  border-radius: 0.5rem;
  background: var(--frame);
  color: var(--fg);
}
.video img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* POP AR's poster is square; this keeps the TV in the 16:9 frame */
#pop-ar .video img { object-position: 50% 72%; }
.video-play {
  position: absolute;
  left: 0.625rem;
  bottom: 0.625rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4375rem 0.875rem 0.4375rem 0.75rem;
  border-radius: 999px;
  background: var(--bg);
  color: var(--fg);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.2;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.video-play::before {
  content: "";
  border-left: 0.6em solid currentColor;
  border-block: 0.375em solid transparent;
}
.video:hover .video-play { background: var(--fg); color: var(--bg); }
.media iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 0.5rem;
  background: var(--frame);
}

/* The 2017–18 games: three entries side by side, each topped by its video
   poster. The poster comes after the heading in the source, so screen
   readers meet the name first; the grid areas put it on top. */
.reel {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2.5rem var(--col-gap);
  padding-block: clamp(1.75rem, 4.5vw, 2.75rem);
  border-top: 1px solid var(--line);
}
.reel .entry {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "media" "when" "head" "body";
  grid-template-rows: auto;
  align-content: start;
  padding: 0;
  border: 0;
}
.reel .media { grid-area: media; margin-bottom: 1rem; }
.reel .when {
  position: static;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.125rem 0.75rem;
  margin-bottom: 0.5rem;
}
.reel .years { font-size: 1.625rem; }
.reel .platforms { margin-top: 0; }
.reel h3 { font-size: 1.3125rem; letter-spacing: -0.018em; }
.reel .entry-body p { margin-top: 0.5rem; }
.reel .project { margin-top: 1rem; }
.reel .project h4 { font-size: 1.0625rem; }
.reel .project h4 + p { margin-top: 0.25rem; }

/* Skills, laid out on the timeline's columns */
.skills { padding-top: clamp(3.5rem, 8vw, 6rem); }
.skills dl {
  display: grid;
  grid-template-columns: var(--when) minmax(0, var(--text));
  gap: 1rem var(--col-gap);
  margin: 0;
}
.skills dt { font-weight: 700; line-height: 1.5; }
.skills dd { margin: 0; }

/* Contact */
.contact { padding-block: clamp(4rem, 9vw, 6.5rem) clamp(3rem, 7vw, 5rem); }
.contact-intro { max-width: var(--text); margin: 0 0 1.25rem; font-size: 1.125rem; }
.contact-address {
  display: block;
  margin: 0 0 1.75rem -0.03em;
  /* Scales with the viewport so the address stays on one line on phones */
  font-size: clamp(1.25rem, 6.2vw, 3.75rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.035em;
  overflow-wrap: anywhere;
}
.copy-status { color: var(--muted); font-size: 0.9375rem; }
.contact .links { margin-top: 2rem; }

/* 404.html: the intro's name and title styles, with room before the footer */
.not-found { padding-bottom: clamp(4rem, 12vw, 9rem); }
.not-found .actions { margin-top: 1.75rem; }

/* Footer */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 2rem;
  padding-block: 1.5rem 2.5rem;
  color: var(--muted);
  font-size: 0.875rem;
}
.site-footer a { text-decoration: none; }
.site-footer a:hover { color: var(--fg); }

/* Screenshot viewer: a full-screen dialog. The screenshots sit on one
   track you can swipe; the buttons and arrow keys step along it. */
.viewer {
  --step: 5.5rem; /* width of the side columns that hold the step buttons */
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--viewer-bg);
  color: var(--viewer-fg);
}
.viewer[open] {
  display: grid;
  grid-template-columns: var(--step) minmax(0, 1fr) var(--step);
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "bar bar bar" "prev track next" ". status .";
  animation: viewer-in 0.2s ease-out;
}
.viewer::backdrop { background: var(--viewer-bg); }
:root:has(.viewer[open]) { overflow: hidden; }

.viewer-bar {
  grid-area: bar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem var(--gutter);
}
.viewer-title { margin: 0; font-weight: 650; }
.viewer-close {
  min-height: 2.75rem;
  padding: 0.375rem 1.25rem;
  border: 1.5px solid color-mix(in srgb, var(--viewer-fg) 35%, transparent);
  border-radius: 999px;
  background: transparent;
  color: var(--viewer-fg);
  cursor: pointer;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.viewer-close:hover {
  border-color: var(--viewer-fg);
  background: color-mix(in srgb, var(--viewer-fg) 10%, transparent);
}

.viewer-track {
  grid-area: track;
  display: flex;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  list-style: none;
  container-type: size;
}
.viewer-track::-webkit-scrollbar { display: none; }
.viewer[open] .viewer-track { animation: viewer-rise 0.35s var(--ease-out); }
.viewer-slide {
  flex: 0 0 100%;
  display: grid;
  place-items: center;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.viewer-slide img {
  display: block;
  /* As large as the track allows without cropping, and never past the
     file's own width, so small images aren't blown up */
  width: min(100cqw, 100cqh * var(--ratio), var(--max-width, 100cqw));
  height: auto;
  aspect-ratio: var(--ratio);
  border-radius: 0.5rem;
  background: color-mix(in srgb, var(--viewer-fg) 6%, transparent);
}

.viewer-step {
  align-self: center;
  justify-self: center;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--viewer-fg) 10%, transparent);
  color: var(--viewer-fg);
  cursor: pointer;
  transition: background-color 0.2s ease, opacity 0.2s ease;
}
.viewer-step:hover { background: color-mix(in srgb, var(--viewer-fg) 20%, transparent); }
/* A chevron drawn from two borders of a square */
.viewer-step::before {
  content: "";
  width: 0.625rem;
  height: 0.625rem;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  transform: translateX(-0.125rem) rotate(45deg);
}
.viewer-step--prev { grid-area: prev; }
.viewer-step--prev::before { transform: translateX(0.125rem) rotate(-135deg); }
.viewer-step--next { grid-area: next; }
.viewer-step[aria-disabled="true"] { opacity: 0.3; cursor: default; }
.viewer-step[aria-disabled="true"]:hover { background: color-mix(in srgb, var(--viewer-fg) 10%, transparent); }

.viewer-status {
  grid-area: status;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
  margin: 0;
  padding: 1rem 0 max(1.5rem, env(safe-area-inset-bottom));
  text-align: center;
}
.viewer-caption { font-weight: 600; }
.viewer-count {
  color: var(--viewer-muted);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}

@keyframes viewer-in { from { opacity: 0; } }
@keyframes viewer-rise { from { opacity: 0; transform: translateY(1rem) scale(0.98); } }

/* Placeholders. The draft banner shows for as long as any placeholder remains. */
.todo {
  padding: 0 0.25em;
  border-radius: 2px;
  background: var(--todo-bg);
  color: var(--todo-fg);
}
.draft-banner {
  display: none;
  margin: 1rem 0 0;
  padding: 0.75rem 1rem;
  border-radius: 0.5rem;
  background: var(--todo-bg);
  color: var(--todo-fg);
}
body:has(.todo) .draft-banner { display: block; }

/* Wide screens only: the intro splits in two, and long bullet lists pair up */
@media (min-width: 52rem) {
  .intro-text {
    grid-template-columns: minmax(0, 1fr) minmax(0, 27rem);
    align-items: end;
  }
  .lead { margin-bottom: 0.125rem; }
}
@media (min-width: 62rem) {
  /* Two balanced columns, read down the first, then the second */
  .points--pair {
    columns: 2;
    column-gap: 2.75rem;
    max-width: none;
    padding-left: 0;
  }
  .points--pair li {
    margin-left: 1.25rem;
    break-inside: avoid;
  }
  .points--pair li + li { margin-top: 0; }
  .points--pair li:not(:last-child) { margin-bottom: 0.75rem; }
}

/* Phones and narrow windows: one column. Each entry's dates sit above its
   title, so the timeline still reads down the page. */
@media (max-width: 52rem) {
  .entry,
  .skills dl { grid-template-columns: minmax(0, 1fr); }
  .entry {
    grid-template-areas: "when" "head" "body";
    grid-template-rows: auto;
  }
  .when {
    position: static;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.875rem;
    margin-bottom: 0.75rem;
  }
  .years { font-size: clamp(1.75rem, 8vw, 2.25rem); }
  .platforms { margin-top: 0; }
  .skills dl { row-gap: 0.125rem; }
  .skills dd + dt { margin-top: 1rem; }
}

/* The 2017–18 games on phones: one per row, a small poster beside the years
   and title, and the text full width beneath. The empty third row takes up
   any height the poster has over the years and title. */
@media (max-width: 48rem) {
  .reel { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .reel .entry {
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    grid-template-rows: auto auto 1fr auto;
    grid-template-areas: "media when" "media head" "media ." "body body";
    column-gap: 1rem;
  }
  .reel .media { align-self: start; margin-bottom: 0; }
  .reel .entry-body { margin-top: 0.25rem; }
  /* A playing video takes the full width again */
  .reel .entry:has(iframe) {
    grid-template-rows: auto;
    grid-template-areas: "media media" "when when" "head head" "body body";
  }
  .reel .entry:has(iframe) .media { margin-bottom: 1rem; }
  /* On a poster this small the play label becomes a round button. The
     words stay in the link for screen readers. */
  .reel .video-play {
    left: 0.375rem;
    bottom: 0.375rem;
    width: 2.25rem;
    height: 2.25rem;
    justify-content: center;
    gap: 0;
    padding: 0 0 0 0.125rem;
    font-size: 0;
  }
  .reel .video-play::before {
    border-left-width: 0.6875rem;
    border-block-width: 0.4375rem;
  }
}

@media (max-width: 40rem) {
  .gallery-shots { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.375rem; }

  /* The screenshot runs edge to edge; the step buttons drop below it */
  .viewer[open] {
    grid-template-columns: 4.5rem minmax(0, 1fr) 4.5rem;
    grid-template-areas: "bar bar bar" "track track track" "prev status next";
  }
  .viewer-slide img { border-radius: 0; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .viewer-track { scroll-behavior: auto; }
  .viewer[open],
  .viewer[open] .viewer-track { animation: none; }
  a, .btn, .site-nav a, .video-play, .viewer-close, .viewer-step,
  .gallery-shots img { transition: none; }
  .gallery-shots a:hover img,
  .gallery--lead li:first-child a:hover img { transform: none; }
}
