/* The site's own styles: layout and page components. Colors and fonts are
   design E's tokens (tokens.css, loaded first). The CV page adds cv-base.css
   and cv-screen.css. The pages' layouts are still the temporary first pass;
   they move to design E one by one (step 7). */

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

/* The page is a column: header, main, footer. main takes the height left
   over (flex: 1 below), so on a short page the footer still sits at the
   bottom of the window. 100dvh is the visible height on phones, where the
   browser's toolbars come and go. */
body {
  margin: 0;
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  font: 1rem/1.6 var(--font-body);
  color: var(--ink);
  background: var(--paper);
}

/* Links in ink with a light underline; red only on hover. The red is the
   design's sparing accent: as the color of every link it would be everywhere. */
a {
  color: var(--ink);
  text-decoration-color: var(--chip-border);
  text-underline-offset: 3px;
}
a:hover { color: var(--accent); text-decoration-color: currentColor; }

/* Keyboard focus: a 2px ink ring 3px outside whatever has focus (links,
   course rows, the video, gallery photos). :focus-visible shows it when
   focus comes from the keyboard, not after a mouse click. Ink on white is
   17.4:1; WCAG asks at least 3:1 for a focus indicator. */
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* Images never overflow their container; height follows the width. */
img { max-width: 100%; height: auto; }

/* padding-inline sets only the left and right padding. The shorthand
   padding: 0 1rem would also set top and bottom to 0, and as a class rule
   it beats the main rule below, so main never got its vertical padding.
   In the body's flex column, auto margins would also shrink each block to
   its content's width, so width: 100% keeps it full width (up to the max). */
.container { width: 100%; max-width: 60rem; margin: 0 auto; padding-inline: 1rem; }

/* ---------- Header ---------- */

/* Design E's header: a document's letterhead. The name in the display
   font, the menu in small tracked capitals like the CV's role line, an
   ink rule below like the rule under the CV's header. */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem 2rem;
  padding-block: 1.25rem;
  border-bottom: 1px solid var(--ink);
}
.site-header ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; }

/* The header is all links, so they need no underline to say "link":
   the place says it. Hover still turns them red (the a:hover rule). */
.site-header a { text-decoration: none; }

.site-name {
  font: 700 1.25rem/1.2 var(--font-display);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.site-header nav a {
  font-family: var(--font-display);
  font-size: 0.9375rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* You are here: bold, and the red mark of the section headings under the
   start of the word. The mark is a background, so it takes no space and
   moves nothing; bold says the same without color. "page" is this page,
   "true" its section (a project page highlights Projects). */
.site-header [aria-current] {
  font-weight: 700;
  padding-bottom: 0.3em;
  background: linear-gradient(var(--accent), var(--accent)) left bottom / 1.375rem 2px no-repeat;
}
.site-header [aria-current]:hover { color: inherit; }

/* The language switch is a utility, not a page: a timecode-style label. */
.site-header .lang-switch { margin-left: auto; }
.lang-switch a {
  font: 500 0.8125rem/1.2 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Narrow screens: the name and the language switch share the first row;
   the menu gets a full-width row of its own below them. The one-row header
   needs 56rem in Russian and 51.3rem in English (measured, docs/DESIGN.md
   section 6), so it waits until the column has its full width (60rem, the
   .container's max-width): 4rem of slack for fonts that render wider. */
@media (max-width: 60rem) {
  .site-header nav { order: 1; flex-basis: 100%; }
}

main { flex: 1; padding-block: 2rem; }

/* ---------- Page headings ---------- */

/* Base styles for headings, wrapped in :where() so they have zero
   specificity: any class rule (.card h3, the CV's own headings) wins
   without a fight. :not(.cv *) keeps them out of the CV block, which has
   its own heading styles in cv-base.css. */

/* The page title: the display font in normal case. The CV's name is
   uppercase because it is a name on a document; a page title reads better
   as a title. clamp() makes it fluid: 2rem on phones, growing with the
   window (2vw) up to 2.75rem. */
:where(h1:not(.cv *)) {
  margin: 0 0 1rem;
  font: 700 clamp(2rem, 1.5rem + 2vw, 2.75rem)/1.1 var(--font-display);
}

/* Section headings: the CV's motif. An uppercase display label, then a
   hairline to the column edge with the red mark at its start, both drawn
   by ::after (two gradients, no image). The rule keeps at least 1.5rem
   when a long heading wraps, so the mark never disappears. */
:where(h2:not(.cv *)) {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  margin: 2.5rem 0 1rem;
  font: 700 1rem/1.4 var(--font-display);
  letter-spacing: 0.075em;
  text-transform: uppercase;
}
:where(h2:not(.cv *))::after {
  content: "";
  flex: 1 0 1.5rem;
  height: 2px;
  background:
    linear-gradient(var(--accent), var(--accent)) left center / 1.375rem 2px no-repeat,
    linear-gradient(var(--rule), var(--rule)) left center / 100% 1px no-repeat;
}

/* The line under the Home page's title: the role, like the CV's role
   line. */
.role {
  margin: -0.25rem 0 1.5rem;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ---------- Running text ---------- */

/* Text written in Markdown: the Home bio, the Sports texts, a project's
   sections. Lines at a readable measure, about 70 characters: longer
   lines make the eye lose its place on the way back to the next one.
   Lists get the CV's 4 × 4 px square bullets, as do the takeaways in an
   open Education course. */
.prose :is(p, ul, ol) { max-width: 40rem; }
:is(.prose, .courses details) ul { list-style: none; padding: 0; }
:is(.prose, .courses details) ul li { position: relative; padding-left: 0.875rem; }
:is(.prose, .courses details) ul li::before {
  content: "";
  position: absolute; left: 0; top: 0.65em;
  width: 4px; height: 4px;
  background: var(--text-3);
}

/* Definition lists in Markdown (term, then a line starting with ": "):
   the CV's Equipment layout, a grey label in a fixed column and the value
   beside it, no rules. Used for the hockey clubs by age. */
.prose dl {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: 0.375rem 1rem;
  max-width: 40rem;
}
.prose dt { color: var(--text-4); }
.prose dd { margin: 0; }

/* ---------- Spec sheets ---------- */

/* Label-value lists like the CV's equipment list: Contacts, and a project's
   gear and client. A mono label in a fixed column, the value beside it, a
   hairline under each pair. Each pair is a div, so the row (not the two
   cells) carries the rule, and align-items: baseline sets the small label
   on the value's text line. The label column is fixed, so the client row
   and the gear table on a project page line up: 10rem holds the longest
   label, «Стабилизатор / риг» (9.65rem), and the 1rem gap keeps it off
   the value. The width is the text's measure. */
.spec {
  max-width: 40rem;
  margin: 1.5rem 0 0;
  border-top: 1px solid var(--rule);
}
.spec div {
  display: grid;
  grid-template-columns: 10rem minmax(0, 1fr);
  column-gap: 1rem;
  align-items: baseline;
  padding-block: 0.875rem;
  border-bottom: 1px solid var(--rule);
}
.spec dt {
  font: 500 0.8125rem/1.2 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-4);
}
.spec dd { margin: 0; font-size: 1.125rem; }

/* Under a section heading, the heading's hairline is the sheet's top
   rule: a second line right below it would only double it. */
h2 + .spec { border-top: 0; }

/* Phones: the label above its value. */
@media (max-width: 30rem) {
  .spec div { grid-template-columns: minmax(0, 1fr); gap: 0.375rem; }
}

/* ---------- Footer ---------- */

/* The CV's contact lines at the foot of every page: an icon before each
   contact, and an ink rule above that mirrors the header's. */
.site-footer {
  border-top: 1px solid var(--ink);
  padding-block: 1.25rem 2rem;
  color: var(--text-3);
  font-size: 0.9375rem;
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; }
.site-footer li { display: flex; align-items: center; gap: 0.5rem; }
.site-footer .icon { flex: none; stroke: var(--text-4); }

/* Phones: one contact per line, each a 2rem row (the CV's tap rows). */
@media (max-width: 30rem) {
  .site-footer ul { flex-direction: column; gap: 0; }
  .site-footer li { min-height: 2rem; }
}

/* Hidden on screen, still read aloud by screen readers. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Home ---------- */

/* Photos side by side at the same height, uncropped. Each one grows in
   proportion to its aspect ratio (--aspect = width / height, set in the HTML). */
.home-photos { display: flex; align-items: flex-start; gap: 0.75rem; margin-block: 1.5rem; }
.home-photos img { flex: var(--aspect) 1 0; min-width: 0; }

/* Narrow screens: one photo per row, full width. */
@media (max-width: 30rem) {
  .home-photos { flex-direction: column; }
  .home-photos img { flex: none; width: 100%; }
}

/* ---------- Project cards ---------- */

/* Used on Projects, Home and Sports. The thumbnail and the title are one
   link; the title takes the display font of the page headings. */
.cards {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: 2rem 1.5rem;
}
.card a { display: block; color: inherit; text-decoration: none; }
.card h3 { margin: 0.75rem 0 0.25rem; font: 700 1.25rem/1.25 var(--font-display); }
.card a:hover h3, .card a:focus-visible h3 { color: var(--accent); }
.card p { margin: 0; font-size: 0.9375rem; line-height: 1.5; color: var(--text-3); }

/* position: relative makes the frame the reference for the format label;
   overflow: hidden clips the photo when it zooms on hover, as in the
   gallery. */
.card-thumb { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--ink); }
.card-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.3s;
}
.card a:hover .card-thumb img, .card a:focus-visible .card-thumb img { transform: scale(1.03); }

/* The frame format, like the readout on a camera's display: white mono
   text on translucent black, chrome of the video, not of the page. */
.card-format {
  position: absolute; left: 0.5rem; bottom: 0.5rem;
  padding: 0.125rem 0.375rem;
  font: 500 0.75rem/1.4 var(--font-mono);
  letter-spacing: 0.06em;
  color: #fff;
  background: rgb(0 0 0 / 0.65);
}

/* A project without a video yet: an empty frame with a mono label. */
.card-thumb--empty {
  display: grid; place-items: center;
  background: var(--placeholder);
  font: 500 0.75rem/1.2 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-4);
}

/* "All projects →" under the cards on Home and Sports, "← All projects"
   above a project's title, and the Photos page's section links: mono
   capitals, like the language switch, still underlined like every link in
   the text. */
.more { margin: 1.5rem 0 0; }
.more a, .back a, .jump-links a, .not-found li a { font: 500 0.8125rem/1.2 var(--font-mono); letter-spacing: 0.06em; text-transform: uppercase; }

/* ---------- Project pages ---------- */

/* The back link above the title, styled like "All projects →" (.more). */
.back { margin: 0 0 1rem; }

/* The summary under a title (projects, Education). */
.lead { max-width: 40rem; font-size: 1.125rem; line-height: 1.5; }

/* ---------- Video player ---------- */

/* The box keeps the video's shape before and after the player loads,
   so nothing on the page jumps when it's clicked. */
.video { position: relative; aspect-ratio: 16 / 9; background: #000; margin-block: 1.5rem; }
.video--vertical { aspect-ratio: 9 / 16; max-width: 22rem; }

.video-facade, .video iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
}
.video-facade img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The round play button, drawn with CSS (no image file needed). */
.video-play {
  position: absolute; top: 50%; left: 50%;
  width: 4.5rem; height: 4.5rem;
  translate: -50% -50%;
  border-radius: 50%;
  background: rgb(0 0 0 / 0.65);
  transition: background 0.15s;
}
.video-play::after {             /* the triangle */
  content: "";
  position: absolute; top: 50%; left: 54%;
  translate: -50% -50%;
  border-style: solid;
  border-width: 0.9rem 0 0.9rem 1.5rem;
  border-color: transparent transparent transparent #fff;
}
.video-facade:hover .video-play,
.video-facade:focus-visible .video-play { background: var(--accent); }

/* ---------- Photos ---------- */

.jump-links ul {
  list-style: none;
  margin: 0 0 1.5rem; padding: 0;
  display: flex; flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
}

/* Justified rows: each photo at its natural aspect ratio, uncropped, all
   photos in a row the same height (the Home photos use the same idea).
   An item starts at aspect × 15rem wide and grows in proportion to its
   aspect, so widths stay proportional to aspects and heights stay equal.
   The ::after filler is the last item: it soaks up most of the last row's
   free space, so a short last row keeps its photos near 15rem tall instead
   of blowing them up. */
.gallery {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}
.gallery li { flex: var(--aspect) 1 calc(var(--aspect) * var(--row, 15rem)); }
.gallery::after { content: ""; flex: 10 1 0; }
.gallery a {
  display: block;
  aspect-ratio: var(--aspect);
  overflow: hidden;
  background: var(--placeholder);
}
.gallery img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.3s;
}
.gallery a:hover img, .gallery a:focus-visible img { transform: scale(1.03); }

/* Phones: a lower starting row, so two or three photos share a row instead
   of each portrait filling the screen on its own. */
@media (max-width: 30rem) {
  .gallery { --row: 10rem; gap: 0.5rem; }
}

/* ---------- Photo viewer (lightbox) ---------- */

/* The dialog covers the whole window; the photo sits in the middle. */
.lightbox {
  width: 100vw; height: 100dvh;
  max-width: none; max-height: none;
  margin: 0; padding: 0; border: 0;
  background: rgb(0 0 0 / 0.96);
}
.lightbox[open] { display: grid; place-items: center; }  /* only when open */
.lightbox::backdrop { background: rgb(0 0 0 / 0.6); }

.lightbox img {
  max-width: calc(100vw - 7rem);   /* leave room for the arrow buttons */
  max-height: calc(100dvh - 4rem);
  width: auto; height: auto;
}
/* Phones: the photo gets the full width; the buttons float over it. */
@media (max-width: 40rem) {
  .lightbox img { max-width: 100vw; }
}

.lightbox button {
  position: absolute;
  width: 3rem; height: 3rem;
  border: 0; border-radius: 50%;
  background: rgb(255 255 255 / 0.15);
  color: #fff;
  font-size: 2rem; line-height: 1;
  cursor: pointer;
}
.lightbox button:hover, .lightbox button:focus-visible { background: var(--accent); }
/* Over the black viewer, an ink ring would vanish: white there. */
.lightbox :focus-visible { outline-color: #fff; }
.lightbox-close { top: 1rem; right: 1rem; }
.lightbox-prev, .lightbox-next { top: 50%; translate: 0 -50%; }
.lightbox-prev { left: 1rem; }
.lightbox-next { right: 1rem; }

/* ---------- Education ---------- */

/* Year and subject headings: the display font of the card titles. The
   years beside a year's label are a timecode, like the CV's dates. */
:is(.coursework, .reading) h3 {
  margin: 2rem 0 0.75rem;
  font: 700 1.25rem/1.25 var(--font-display);
}
.dates {
  margin-left: 0.5rem;
  font: 400 0.8125rem/1 var(--font-mono);
  color: var(--text-2);
}

/* Semesters: a mono label, like the spec sheets' labels. */
.coursework h4 {
  margin: 1.25rem 0 0.25rem;
  font: 500 0.8125rem/1.2 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-4);
}

.courses, .books { list-style: none; margin: 0 0 1.5rem; padding: 0; max-width: 40rem; }

/* One course per row: a rule under each, the whole title row is the
   click target. display: flex replaces the browser's triangle marker
   (it belongs to display: list-item); ::before draws a plus instead. */
.courses > li { border-bottom: 1px solid var(--rule); }
.courses summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-block: 0.625rem;
  cursor: pointer;
}
.course-title { flex: 1; font-weight: 700; }
.courses summary:hover .course-title { color: var(--accent); }

/* The plus: two 2px bars drawn as gradients, like the heading marks. Open,
   the vertical bar goes and a minus is left. It is not text, so screen
   readers say nothing extra; they announce expanded or collapsed. */
.courses summary::before {
  content: "";
  flex: none;
  width: 0.75rem; height: 0.75rem;
  background:
    linear-gradient(var(--text-4), var(--text-4)) center / 100% 2px no-repeat,
    linear-gradient(var(--text-4), var(--text-4)) center / 2px 100% no-repeat;
}
.courses details[open] > summary::before {
  background: linear-gradient(var(--text-4), var(--text-4)) center / 100% 2px no-repeat;
}

/* The grade on the right, as a timecode. */
.grade {
  font: 400 0.8125rem/1.2 var(--font-mono);
  color: var(--text-2);
}

/* The open course: indented to the title's start (0.75rem plus + 0.75rem
   gap) and mono labels. The takeaways get the square bullets of .prose. */
.courses details[open] { padding-bottom: 0.875rem; }
.courses details > :not(summary) { margin-left: 1.5rem; }
.courses summary + p { margin-top: 0.25rem; }
.courses .label {
  margin: 1rem 0 0.25rem 1.5rem;
  font: 500 0.75rem/1.2 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-4);
}

.books li { margin-block: 0.625rem; }
.takeaway { margin: 0.125rem 0 0; color: var(--text-3); }

/* Book titles: italics in English, «guillemets» in Russian typography.
   The HTML stays the same; only the presentation follows the language. */
:lang(ru) cite { font-style: normal; quotes: "«" "»"; }
:lang(ru) cite::before { content: open-quote; }
:lang(ru) cite::after { content: close-quote; }

/* ---------- Sports ---------- */

/* Achievements: the year as a timecode in a narrow column, like the CV's
   dates, the events beside it, a rule under each year. Each year's <dt>
   and <dd>s are a div: the dt is pinned to column 1, the dds stack in
   column 2, and baseline alignment sets the year on its first event's
   line. */
.achievements dl { max-width: 40rem; margin: 0; }
.achievements dl > div {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr);
  column-gap: 1rem;
  row-gap: 0.375rem;
  align-items: baseline;
  padding-block: 0.75rem;
  border-bottom: 1px solid var(--rule);
}
.achievements dt {
  grid-column: 1;
  font: 400 0.875rem/1.2 var(--font-mono);
  color: var(--text-2);
}
.achievements dd { grid-column: 2; margin: 0; }
.result { color: var(--text-3); }

/* ---------- 404 page ---------- */

/* The message in both languages, side by side where there is room, each
   under its own section heading; stacked on phones. Each section spans
   three rows of the outer grid and lays its heading, text and links on
   them (subgrid), so the rows line up across the languages even when one
   text wraps onto more lines. The links are styled like "All projects →"
   (.more). */
.not-found { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2rem; }
.not-found section { display: grid; grid-row: span 3; grid-template-rows: subgrid; }
.not-found p { margin: 0; }
.not-found ul { display: grid; gap: 0.75rem; margin: 1.5rem 0 0; padding: 0; list-style: none; }

@media (max-width: 40rem) {
  .not-found { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Reduced motion ---------- */

/* Visitors whose system asks for less motion get no zoom on hover. The
   selectors repeat the hover rules, so as later rules of equal
   specificity they win. */
@media (prefers-reduced-motion: reduce) {
  .gallery a:is(:hover, :focus-visible) img,
  .card a:is(:hover, :focus-visible) .card-thumb img { transform: none; }
}
