/* ==========================================================================
   adrianlin.me — shared stylesheet
   ========================================================================== */

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

:root {
  --bg: #080d1a;
  --bg-nav: rgba(8, 13, 26, 0.92);
  --text: #e8eaf0;
  --heading: #ffffff;
  --body: #b8bcc8;
  --dim: #9ca3af;
  --muted: #6b7280;
  --faint: #4b5563;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.15);
  --rule: rgba(255, 255, 255, 0.06);
  --surface: rgba(255, 255, 255, 0.03);
  --nav-h: 64px;
  /* Height of the footer bar. The scroll-to-top button parks above it,
     so the two can never collide at the bottom of a page. */
  --footer-h: 42px;

  /* ------------------------------------------------------------------
     TYPE SCALE — the only sizes on the site.
     Steps are numbered rather than named after where they are used, so a
     role can move a step without the token name turning into a lie.
     ------------------------------------------------------------------ */
  --fs-0: 11px;                     /* uppercase labels */
  --fs-1: 12px;                     /* captions, footer */
  --fs-2: 13px;                     /* meta, minor headings */
  --fs-3: 14px;                     /* small body, lists, UI */
  --fs-4: 15px;                     /* body copy, small titles */
  --fs-5: 17px;                     /* section heading */
  --fs-6: 20px;                     /* major heading */
  --fs-7: 28px;                     /* page title (24px on mobile) */
  --fs-8: clamp(32px, 4vw, 46px);   /* display */
  --fs-code: 12.5px;                /* monospace */

  --fw-light: 300;
  --fw-regular: 400;
  --fw-medium: 500;

  --lh-tight: 1.3;                  /* headings */
  --lh-snug: 1.6;                   /* meta, captions, UI */
  --lh-relaxed: 1.7;                /* small body, lists, callouts */
  --lh-loose: 1.8;                  /* body prose */
}

html[data-theme="light"] {
  --bg: #f5f5f2;
  --bg-nav: rgba(245, 245, 242, 0.92);
  --text: #111111;
  --heading: #111111;
  --body: #3f3f46;
  --dim: #52525b;
  --muted: #71717a;
  --faint: #a1a1aa;
  --border: rgba(0, 0, 0, 0.10);
  --border-strong: rgba(0, 0, 0, 0.18);
  --rule: rgba(0, 0, 0, 0.07);
  --surface: rgba(0, 0, 0, 0.03);
}

html { background: var(--bg); }
/* Keeps the footer at the bottom of the viewport on short pages, and after
   the content on long ones. Two grid rows do the whole job: the content row
   absorbs any slack, the footer row sizes to itself. Nothing is needed on the
   children.
   100svh = the SMALL viewport height, i.e. measured with mobile browser chrome
   showing. Plain 100vh is measured with it hidden, so on iOS the footer gets
   pushed just below the fold on short pages. The 100vh line is the fallback
   for browsers predating svh. */
body {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  /* Grid tracks size to their content's minimum by default, so a wide child
     (the code block) would stretch the column past the viewport. Pinning the
     column to 100% keeps overflow inside the element that scrolls. */
  grid-template-columns: 100%;
  background: var(--bg);
}

body {
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  color: var(--text);
  font-weight: var(--fw-light);
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
}

::selection { background: rgba(255,255,255,0.18); }

/* ==========================================================================
   GLOBAL TYPE SYSTEM
   --------------------------------------------------------------------------
   THIS IS THE COMPLETE LIST OF TEXT STYLES ON THE SITE. Every piece of text
   on every page gets its size, weight, line-height, letter-spacing and colour
   from exactly one role below. Do not add a new one, and do not set
   font-size / font-weight / line-height / letter-spacing anywhere else in
   this file.

   Two ways to use a role:
     - the ELEMENT       <h3>…</h3>            gets the role and its rhythm
     - the CLASS         <div class="t-h3">    gets the role only

   Component rules further down set layout (margins, borders, backgrounds,
   grids) and may re-point a role at a different COLOUR token when the colour
   is the point of the component (.note, .disclaimer, .pill). They never
   change a size, weight or line-height.

     ROLE            ELEMENT   SIZE   WEIGHT  COLOUR    USED FOR
     .t-display      —         46-32  400     heading   home / 404 name
     .t-h1           h1        28/24  400     heading   page + project titles
     .t-h2           h2        20     400     heading   major section heading
     .t-h3           h3        17     400     heading   section heading
     .t-h4           h4        15     500     heading   small titles, card titles, logo
     .t-h5           h5        13     500     dim       figure-group heading
     .t-label        h6        11     500     dim       uppercase eyebrow label
     .t-label-strong —         12     500     text      eyebrow carrying a section alone
     .t-lead         —         15     300     dim       deck under a title
     .t-body         p         15     300     body      body copy
     .t-body-sm      li        14     300     body      lists, secondary prose, notes
     .t-strong       —         14     400     text      affiliation lines, text not to be skimmed
     .t-strong-loud  —         14     500     heading   a credential in a list: the role line on /experience/
     .t-ui           —         14     400     muted     nav and interface text
     .t-meta         —         13     300     muted     metadata, descriptions, years
     .t-caption      figcaption 12    300     muted     figure captions, footer
     .t-code         pre, code 12.5   300     dim       code blocks

   Plus two INLINE MODIFIERS, which are not roles: they set no size and no
   line-height, so they keep whatever role the surrounding text carries.
     strong, b       one weight step up (500) and one colour step brighter
     a in prose      colour and underline only (see .detail-body p a below)
   ========================================================================== */

/* ---- display + headings ---- */
.t-display {
  font-size: var(--fs-8);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
  color: var(--heading);
}

h1, .t-h1 {
  font-size: var(--fs-7);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  color: var(--heading);
}
h1 { margin-bottom: 48px; }

h2, .t-h2 {
  font-size: var(--fs-6);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  color: var(--heading);
}
h2 { margin-bottom: 20px; }

h3, .t-h3 {
  font-size: var(--fs-5);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  color: var(--heading);
}
h3 { margin-bottom: 18px; }

h4, .t-h4 {
  font-size: var(--fs-4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: 0.01em;
  color: var(--heading);
}
h4 { margin: 28px 0 12px; }

/* Fifth level labels a GROUP of figures rather than a single one. Kept
   visually distinct from a caption (smaller, lighter, centred) so the two
   cannot be confused. */
h5, .t-h5 {
  font-size: var(--fs-2);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: 0.02em;
  color: var(--dim);
}
h5 { margin: 24px 0 0; }

/* Two eyebrow labels, quiet and loud. The quiet one marks a block inside a
   page that already has a title above it; the loud one carries a section on
   its own, where nothing larger is doing the work. */
h6, .t-label {
  font-size: var(--fs-0);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
}

.t-label-strong {
  font-size: var(--fs-1);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
}
h6 { margin-bottom: 14px; }

/* ---- prose ---- */
.t-lead {
  font-size: var(--fs-4);
  font-weight: var(--fw-light);
  line-height: var(--lh-loose);
  color: var(--dim);
}

p, .t-body {
  font-size: var(--fs-4);
  font-weight: var(--fw-light);
  line-height: var(--lh-loose);
  color: var(--body);
}

/* Paragraph rhythm inside prose blocks only. :where() keeps this at zero
   specificity, so any role class on a paragraph still wins outright — which
   is what retired the old p:not([class]) hack. */
:where(.about-body, .detail-body, .contact-body) p + p { margin-top: 16px; }

/* Inline emphasis inside prose. NOT a role: it sets no size and no
   line-height, so it keeps whatever role its paragraph already carries and
   only steps the weight up within the existing scale, lifting the colour one
   step with it. Same shape as the prose link rule further down - an inline
   modifier, not another role.
   It has to exist: nothing else on the site resets <strong>, so without this
   a bolded phrase renders at the browser default 700, which is off the
   300/400/500 scale entirely and reads as a different typeface. */
strong, b {
  font-weight: var(--fw-medium);
  color: var(--text);
}

li, .t-body-sm {
  font-size: var(--fs-3);
  font-weight: var(--fw-light);
  line-height: var(--lh-relaxed);
  color: var(--body);
}

.t-strong {
  font-size: var(--fs-3);
  font-weight: var(--fw-regular);
  line-height: var(--lh-relaxed);
  color: var(--text);
}

/* Two strongs, quiet and loud - the same pairing as .t-label and
   .t-label-strong. The loud one is for a credential a reader scans a LIST
   for: same size as .t-strong so it stays subordinate to the 15px name above
   it, but medium weight and heading colour so it lifts off the description
   below. Deliberately not .t-h4, which at 15/500 ties with the name and makes
   a row read as two stacked titles. Added on an explicit decision - see
   NOTES.md, "The three kinds". */
.t-strong-loud {
  font-size: var(--fs-3);
  font-weight: var(--fw-medium);
  line-height: var(--lh-relaxed);
  color: var(--heading);
}

.t-ui {
  font-size: var(--fs-3);
  font-weight: var(--fw-regular);
  line-height: var(--lh-snug);
  letter-spacing: 0.02em;
  color: var(--muted);
}

.t-meta {
  font-size: var(--fs-2);
  font-weight: var(--fw-light);
  line-height: var(--lh-snug);
  color: var(--muted);
}

figcaption, .t-caption {
  font-size: var(--fs-1);
  font-weight: var(--fw-light);
  line-height: var(--lh-snug);
  letter-spacing: 0.01em;
  color: var(--muted);
}

pre, code, .t-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-code);
  font-weight: var(--fw-light);
  line-height: 1.65;
  color: var(--dim);
}

/* ---------- NAV ---------- */
nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 48px;
  z-index: 100;
  background: var(--bg-nav);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

.logo { text-decoration: none; }

nav ul { display: flex; align-items: center; gap: 32px; list-style: none; }

nav a { text-decoration: none; transition: color 0.2s ease; cursor: pointer; }
nav a:hover, nav a.active { color: var(--heading); }

/* A glyph, not text: its size is an icon dimension and stays off the scale. */
.toggle {
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 18px; line-height: 1;
  transition: color 0.2s; padding: 4px; font-family: inherit;
}
.toggle:hover { color: var(--heading); }

/* ---------- PAGE SHELL ---------- */
.page {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: calc(var(--nav-h) + 8vh) 48px 64px;
}
.page::-webkit-scrollbar { width: 4px; }
.page::-webkit-scrollbar-track { background: transparent; }
.page::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 2px; }

.inner { width: 100%; max-width: 600px; }
.inner.wide { max-width: 760px; }

/* ---------- HOME ---------- */
.home-inner { max-width: 560px; text-align: left; }
.home-inner h1 { margin-bottom: 8px; }

.home-sub { margin-bottom: 24px; }
.home-desc { margin-bottom: 32px; }

.home-topics { border-left: 1px solid rgba(255,255,255,0.12); padding-left: 20px; }
html[data-theme="light"] .home-topics { border-left-color: rgba(0,0,0,0.14); }
.home-topics h6 { margin-bottom: 12px; }

.home-topics ul { list-style: none; display: flex; flex-direction: column; gap: 6px; }

.home-highlights { margin-top: 44px; padding-top: 36px; border-top: 1px solid var(--rule); }

/* Publications sit directly above the highlights and borrow their rule and
   spacing, so the two blocks read as one rhythm rather than two designs. */
.home-publications { margin-top: 44px; padding-top: 36px; border-top: 1px solid var(--rule); }

/* The last publication's own bottom border already separates the two blocks;
   without this the section rule lands beside it as a stray double line. */
.home-publications + .home-highlights { padding-top: 0; border-top: 0; }

/* The venue is <em> only to lift it one colour step - it is not italicised,
   which would fight the rest of the page. Author on line one, venue on line
   two; page numbers and city live in the paper, not here. */
.pub-cite em { font-style: normal; color: var(--dim); }

/* ---------- ABOUT ---------- */
.about-section {
  margin-top: 36px;
  padding-top: 36px;
  border-top: 1px solid var(--rule);
}

.award-list {
  list-style: none;
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.award-list li {
  padding-left: 12px;
  border-left: 1px solid var(--border-strong);
}

.portrait {
  width: 100%;
  max-height: 520px;
  object-fit: cover;
  border-radius: 3px;
  display: block;
  border: 1px solid var(--border);
}

/* ---------- EXPERIENCE SECTIONS ---------- */
/* Work / Research / Projects on /experience/. Spacing only: each section's
   list already draws its own top and bottom rules, so a border here would
   land beside the list's own and read as a stray double line - the same
   reason .home-publications + .home-highlights drops one. */
.exp-section + .exp-section { margin-top: 56px; }

/* ---------- PROJECT LIST ---------- */
.projects-list { width: 100%; }

.project-item {
  padding: 28px 0;
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  transition: opacity 0.25s ease;
  text-decoration: none;
  color: inherit;
}
.project-item:first-child { border-top: 1px solid var(--border); }

.projects-list:hover .project-item { opacity: 0.3; }
.projects-list:hover .project-item:hover { opacity: 1; }

.project-name { margin-bottom: 8px; }

/* A row that is really a position rather than a personal project: the role
   line sits between the name and the description. Work rows name the company,
   research rows the lab and advisor.
   It is the thing a reader scans these two sections for, so it takes the loud
   strong (.t-strong-loud) rather than the quiet one - the emphasis is in the
   type, not in any box drawn around it. This rule sets spacing only. */
.project-role { margin: -2px 0 8px; }

/* Marks a pinned project. Sits on the baseline of the project name. */
.pin {
  width: 12px;
  height: 12px;
  margin-right: 7px;
  color: var(--muted);
  vertical-align: -1px;
  flex: none;
}

.project-year {
  white-space: nowrap;
  margin-left: 24px;
  padding-top: 2px;
}

/* ---------- PROJECT DETAIL ---------- */
.back-link {
  display: inline-block;
  text-decoration: none;
  margin-bottom: 28px;
  transition: color 0.2s;
}
.back-link:hover { color: var(--heading); }

.detail-title { margin-bottom: 12px; }

/* Deck under the title: .t-lead is deliberately dimmer than body copy. */
.detail-lede { margin-bottom: 28px; }

/* Role / affiliation / dates, sitting between the title and the lede. Takes
   the same role as an FTC team line and a project row's affiliation line, so
   every "who and when" line on the site reads at one weight. */
.detail-meta { margin-bottom: 14px; }

.detail-section {
  margin-top: 40px;
  padding-top: 36px;
  border-top: 1px solid var(--rule);
}

.detail-body ul.plain {
  list-style: none;
  margin: 14px 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.detail-body ul.plain li {
  padding-left: 12px;
  border-left: 1px solid var(--border-strong);
}

/* --- FTC season blocks --- */

/* Team name + number: a quieter line under the season heading. */
.team { margin: -4px 0 0; }

/* The role sits on its own, with its own short rule. */
.role {
  padding-left: 12px;
  border-left: 1px solid var(--border-strong);
  margin-top: 16px;
}

/* Awards read as one block: a single continuous rule down the whole group
   rather than a separate stub beside each line, and tighter spacing between
   the awards than between the group and the role above it. */
.awards {
  list-style: none;
  margin: 10px 0 0;
  padding-left: 12px;
  border-left: 1px solid var(--border-strong);
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* A figure that should read as more prominent than the grid beside it,
   without going full column width. */
.video-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow: hidden;
  background: var(--surface);
}
.video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* An aside. Same size as the surrounding lists, one colour step quieter. */
.note {
  color: var(--dim);
  margin-top: 16px;
  padding: 14px 16px;
  background: var(--surface);
  border-left: 1px solid var(--border-strong);
  border-radius: 0 3px 3px 0;
}

/* Louder sibling of .note, for something the reader must not skim past.
   Carries its own accent tokens rather than the page's greys - that colour
   IS the point of the component, so it is redefined per theme below. */
.disclaimer {
  --disc-accent: #f0b429;
  --disc-tint: rgba(240, 180, 41, 0.10);
  --disc-edge: rgba(240, 180, 41, 0.32);

  margin: 0 0 26px;
  padding: 13px 18px;
  background: var(--disc-tint);
  border: 1px solid var(--disc-edge);
  border-left: 3px solid var(--disc-accent);
  border-radius: 0 4px 4px 0;
}

/* Amber that reads on a near-white ground; the dark-theme value is too light
   to hold contrast here. */
html[data-theme="light"] .disclaimer {
  --disc-accent: #b45309;
  --disc-tint: rgba(180, 83, 9, 0.07);
  --disc-edge: rgba(180, 83, 9, 0.28);
}

/* These labels belong to the figures BELOW them, so they sit close to those
   and further from the heading above. */
.detail-body h5 + figure, .detail-body h5 + .media-grid { margin-top: 8px; }


.pill {
  display: inline-block;
  margin-top: 20px;
  color: var(--dim);
  text-decoration: none;
  padding: 9px 16px;
  border: 1px solid var(--border-strong);
  border-radius: 2px;
  transition: color 0.2s, border-color 0.2s;
}
.pill:hover { color: var(--heading); border-color: var(--heading); }

.cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 26px;
}
.cta-row .pill { margin-top: 0; }

.pill.primary {
  color: var(--heading);
  background: var(--surface);
  border-color: var(--border-strong);
  box-shadow: inset 0 0 0 1px var(--border);
}
.pill.primary:hover { background: transparent; border-color: var(--heading); }

/* Closing link back to the paper. */
.paper-note {
  margin-top: 44px;
  padding-top: 28px;
  border-top: 1px solid var(--rule);
  text-align: center;
}
.paper-note a { color: var(--dim); text-decoration: none; transition: color 0.2s; }
.paper-note a:hover { color: var(--heading); }

/* A link inside prose. No type of its own - it keeps whatever role its
   paragraph carries and only changes colour and underline, which is the
   whole point of the component. Without this the browser default paints it
   link-blue, since nothing else on the site resets a bare <a>. */
.detail-body p a, .detail-body li a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: var(--border-strong);
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.detail-body p a:hover, .detail-body li a:hover {
  color: var(--heading);
  text-decoration-color: var(--heading);
}

/* Build-time syntax highlighting (Pygments token classes). Tuned to the site
   palette rather than a stock theme, so the code block does not fight the
   surrounding page. */
pre .k, pre .kt, pre .kd { color: #8ab4f8; }            /* keywords, types */
pre .nf { color: #c3a6ff; }                              /* function names */
pre .mf, pre .mi, pre .mh { color: #f0a373; }            /* numbers */
pre .s, pre .s1, pre .s2 { color: #9ece6a; }             /* strings */
pre .c1, pre .cm, pre .c { color: var(--muted); font-style: italic; }
pre .o, pre .p { color: var(--muted); }                  /* operators, punctuation */
pre .n { color: var(--body); }                           /* identifiers */

html[data-theme="light"] pre .k,
html[data-theme="light"] pre .kt,
html[data-theme="light"] pre .kd { color: #1a56b4; }
html[data-theme="light"] pre .nf { color: #7b3fb8; }
html[data-theme="light"] pre .mf,
html[data-theme="light"] pre .mi,
html[data-theme="light"] pre .mh { color: #b45309; }
html[data-theme="light"] pre .s,
html[data-theme="light"] pre .s1,
html[data-theme="light"] pre .s2 { color: #2f7a2f; }

/* ---------- MEDIA ---------- */
figure { margin: 22px 0; }

figure img, figure video {
  display: block;
  max-width: 100%;
  width: auto;
  height: auto;
  max-height: 620px;
  margin: 0 auto;
  border-radius: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
}

/* Images are centred inside the figure (margin: 0 auto) because they are
   often narrower than the column, so centre the caption to match. */
figcaption { margin-top: 9px; text-align: center; }

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  align-items: start;
  gap: 22px;
  margin: 22px 0;
}
.media-grid figure { margin: 0; }
.media-grid img, .media-grid video { max-height: 420px; }

/* Explicit two-column grids keep even pairs from orphaning a last item. */
.media-grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Two across, weighted 2:3 - for a pair where the second image carries more. */
.media-grid.split-2-3 { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }

/* Two across, weighted 4:3. Not a visual preference - it is the width ratio
   that makes a 4:3 photo and a 1:1 photo exactly the same height, so a row
   pairing the two sits level instead of leaving a hole under the shorter
   caption. 738px of column at 4:3 gives 422 and 316, both 316 tall. */
.media-grid.split-4-3 { grid-template-columns: minmax(0, 4fr) minmax(0, 3fr); }

/* Three across, with the last item given more room - used where the final
   image is the finished robot and deserves more weight than the iterations.
   -slight is the gentler version, for rows where the first image still needs
   to read clearly. */
.media-grid.uneven-3 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.4fr); }
.media-grid.uneven-3-slight { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.18fr); }

/* For source images smaller than the column, cap so they are never upscaled. */
.media-grid.narrow { grid-template-columns: repeat(2, minmax(0, 320px)); justify-content: center; }

figure.narrow   { max-width: 600px; margin-left: auto; margin-right: auto; }
figure.narrower { max-width: 460px; margin-left: auto; margin-right: auto; }

pre {
  margin: 20px 0;
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow-x: auto;
  scrollbar-width: thin;
}

/* ---------- CONTACT ---------- */
.contact-body p { margin-bottom: 36px; }

.contact-links { display: flex; flex-direction: column; gap: 20px; }

.contact-link {
  display: flex;
  align-items: baseline;
  gap: 16px;
  text-decoration: none;
  transition: color 0.2s;
  word-break: break-word;
}
.contact-link:hover { color: var(--heading); }

.contact-label {
  width: 84px;
  flex: 0 0 84px;
  white-space: nowrap;
}

/* ---------- FOOTER ---------- */
.footer {
  padding: 11px 48px;
  border-top: 1px solid var(--border);
  background: var(--bg-nav);
  backdrop-filter: blur(12px);
  z-index: 100;
}
.footer p { text-align: center; }

/* ---------- RESPONSIVE ---------- */
@media (max-width: 720px) {
  /* One token change resizes every page title and .t-h1 on the site. */
  :root { --fs-7: 24px; --nav-h: 56px; }
  nav { padding: 0 20px; }
  nav ul { gap: 18px; }
  nav a { font-size: var(--fs-2); }
  .page { padding: calc(var(--nav-h) + 40px) 20px 56px; }
  .footer { padding: 11px 20px; }
  h1 { margin-bottom: 32px; }
  .media-grid.media-grid { grid-template-columns: 1fr; }
  .project-item { padding: 22px 0; }
  .projects-list:hover .project-item { opacity: 1; }
}

@media (max-width: 460px) {
  nav { padding: 0 14px; }
  nav ul { gap: 13px; }
  .logo { font-size: var(--fs-2); }
  .toggle { font-size: 15px; padding: 2px; }
  .page { padding: calc(var(--nav-h) + 32px) 16px 48px; }
  .footer { padding: 11px 16px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ---------- SCROLL TO TOP ---------- */
.to-top {
  position: fixed;
  right: 28px;
  bottom: calc(var(--footer-h) + 16px);
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--bg-nav);
  backdrop-filter: blur(12px);
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  line-height: 1;
  z-index: 90;
  padding: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease, color 0.2s ease, border-color 0.2s ease, visibility 0.25s;
}

.to-top.visible { opacity: 1; visibility: visible; transform: translateY(0); }
.to-top:hover { color: var(--heading); border-color: var(--heading); }
.to-top:focus-visible { outline: 1px solid var(--heading); outline-offset: 3px; }

.to-top svg { width: 13px; height: 13px; display: block; }

@media (max-width: 720px) {
  .to-top { right: 16px; bottom: calc(var(--footer-h) + 12px); width: 34px; height: 34px; }
  .to-top svg { width: 12px; height: 12px; }
}
