/* =========================================================================
   juliancefai.com — A3
   One stylesheet, seven pages. Light and dark ship together as two token
   blocks; there is no toggle and no JavaScript anywhere on the site.
   ========================================================================= */

/* ---------- Fonts ------------------------------------------------------- */

/* One typeface for the whole site. Newsreader carries everything from 13px
   labels to 39px page titles, which is why the optical-size axis is kept
   variable rather than pinned — at 13px it opens up and thickens, at 39px it
   tightens and refines. That axis is the reason a single serif can do the job
   of the three families this replaced.
   wght 400–700 covers body, labels (500) and <strong> (700). */
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/newsreader.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- Tokens ------------------------------------------------------ */

:root {
  /* Clay — a warm terracotta-grey sheet, marked in purple.
     This is the site's palette: light for everyone, regardless of the
     visitor's system setting. See the dark block below. */
  --paper:      #E8E0DB;
  --surface:    #F4EFEB;
  --rule:       #CEC3BC;

  /* One dark grey for all text — headings, body, labels, nav, footer alike.
     --ink and --secondary are kept as separate names so a second step can be
     reintroduced later by changing one value, but today they are the same
     colour and hierarchy is carried by size, weight and letter-spacing. */
  --ink:        #4A424C;
  --secondary:  #4A424C;

  --accent:     #643181;

  /* Section accent rotation. Tuned per mode, never reused across modes. */
  --accent-work:        #643181;
  --accent-builds:      #6D3181;
  --accent-experiments: #773181;
  --accent-community:   #573181;
  --accent-games:       #813181;

  /* Type — one family. The three names are kept so the rules below stay
     readable as roles, not because they resolve to different fonts. */
  --display: "Newsreader", Georgia, "Times New Roman", serif;
  --body:    "Newsreader", Georgia, "Times New Roman", serif;
  --mono:    "Newsreader", Georgia, "Times New Roman", serif;

  /* One 1.25 ratio, used everywhere. */
  --t--2: 0.8125rem;
  --t--1: 0.9375rem;
  --t-0:  1rem;
  --t-1:  1.25rem;
  --t-2:  1.5625rem;
  --t-3:  1.953rem;
  --t-4:  2.441rem;

  /* 4px base, fixed steps. Layout uses gap, never per-element margins. */
  --s-1:  4px;
  --s-2:  8px;
  --s-3:  12px;
  --s-4:  16px;
  --s-5:  24px;
  --s-6:  32px;
  --s-7:  48px;
  --s-8:  64px;
  --s-9:  96px;
  --s-10: 128px;

  --measure: 65ch;
  --column: 68rem;
  --label-col: 8.5rem;
}

/* ---------- Dark counterpart — present but dormant ----------------------
   The site is light by default for every visitor: this block is NOT wired to
   prefers-color-scheme, so a dark-set system still gets Clay.

   It is kept, fully solved and contrast-checked, so dark remains one step away
   rather than a rebuild. To enable it, either:
     a) set data-theme="dark" on <html> (a toggle would need JavaScript and a
        blocking inline script in the head of all seven pages, which is why the
        site does not ship one today), or
     b) change the selector below to @media (prefers-color-scheme: dark) to go
        back to following the system setting.

   Neither the light accent #643181 (1.92:1 here) nor the light text #4A424C
   (1.82:1) can be reused on this ground — both are near-invisible. The dark
   palette is a separate, lighter set, not an inversion. */

:root[data-theme="dark"] {
  /* The ink becomes the ground, keeping the same faint purple cast;
     the paper becomes the text. */
  --paper:     #1C181D;
  --surface:   #262129;
  --rule:      #352E38;

  /* Single text colour here too, mirroring the light palette. */
  --ink:       #D3CED4;
  --secondary: #D3CED4;

  --accent:    #AB79C8;

  /* Re-tuned, not reused — the same rotation reads as a bigger jump
     against a dark ground, so the steps are tightened. */
  --accent-work:        #AB79C8;
  --accent-builds:      #B275C7;
  --accent-experiments: #BA72C5;
  --accent-community:   #A17DCA;
  --accent-games:       #C36DC3;
}

/* ---------- Reset ------------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--t-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The whole point of keeping the opsz axis: let the browser pick the optical
     size from the rendered px size, so 13px labels and 39px titles are drawn
     from different masters of the same face. */
  font-optical-sizing: auto;
}

img { max-width: 100%; height: auto; display: block; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Shared primitives ------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--column);
  margin-inline: auto;
  padding-inline: clamp(var(--s-5), 5vw, var(--s-8));
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--surface);
  color: var(--ink);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--t--2);
  z-index: 10;
}
.skip:focus { left: var(--s-4); top: var(--s-4); }

/* The eyebrow / label voice — mono, small, tracked, upper. */
.eyebrow {
  font-family: var(--mono);
  font-size: var(--t--2);
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--secondary);
  margin: 0;
}

.lede {
  font-size: var(--t-1);
  line-height: 1.55;
  max-width: 46rem;
  margin: 0;
}

.prose { max-width: var(--measure); }
.prose p { margin: 0 0 var(--s-5); }
.prose p:last-child { margin-bottom: 0; }

/* Supporting text. With a single-colour palette this can no longer step down by
   tone, so it steps down by size instead — otherwise a supporting paragraph is
   indistinguishable from the lede it sits under. */
.dim { color: var(--secondary); }
.lede.dim { font-size: var(--t-0); }

/* Placeholder copy — visibly unfinished, so it can't ship by accident. */
.ph {
  color: var(--secondary);
  background: repeating-linear-gradient(
    -45deg, transparent, transparent 4px, var(--rule) 4px, var(--rule) 5px
  );
  padding: 0.05em 0.3em;
  border-radius: 2px;
  font-style: normal;
}

/* Links in running prose — underline is the accent, text stays ink. */
.prose a,
.link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
.prose a:hover,
.link:hover { text-decoration-thickness: 2px; }

/* ---------- Masthead / nav ---------------------------------------------- */

.masthead { border-bottom: 1px solid var(--rule); }

.nav {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3) var(--s-5);
  padding-block: var(--s-5);
}

.nav-name {
  font-family: var(--display);
  font-size: var(--t-1);
  font-weight: 500;
  letter-spacing: 0.01em;
  color: inherit;
  text-decoration: none;
}
.nav-name:hover { text-decoration: underline;
  text-decoration-color: var(--accent); text-underline-offset: 0.2em; }

.nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: 0.06em;
}
.nav-links a {
  color: var(--secondary);
  text-decoration: none;
  padding-block: var(--s-1);
  border-bottom: 1px solid transparent;
}
.nav-links a:hover { color: var(--ink); border-bottom-color: var(--accent); }
.nav-links a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* ---------- Page head --------------------------------------------------- */

.page-head { padding-block: clamp(var(--s-7), 8vw, var(--s-9)) var(--s-7); }

.page-head h1 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(var(--t-2), 5.5vw, var(--t-4));
  line-height: 1.12;
  letter-spacing: -0.011em;
  margin: var(--s-4) 0 0;
  max-width: 22ch;
}

/* The page-title hairline is the one place the section accent is strongest. */
.page-head h1::after {
  content: "";
  display: block;
  width: var(--s-8);
  height: 2px;
  background: var(--accent);
  margin-top: var(--s-5);
}

.page-head .lede { margin-top: var(--s-5); }

/* ---------- Ruled rows — the core layout device ------------------------- */
/* A label column and a hairline. Not cards, not boxes. Never more than
   four or five items in one group. */

.rows {
  border-top: 1px solid var(--rule);
  margin: 0;
  padding: 0;
  list-style: none;
}

.row {
  border-bottom: 1px solid var(--rule);
  display: grid;
  grid-template-columns: var(--label-col) 1fr auto;
  gap: var(--s-5);
  align-items: baseline;
  padding-block: var(--s-5);
}

.row .lab {
  font-family: var(--mono);
  font-size: var(--t--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--secondary);
  padding-top: 0.35em;
}

.row .ttl {
  display: block;
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-2);
  line-height: 1.2;
}

.row .dsc {
  display: block;
  color: var(--secondary);
  font-size: var(--t--1);
  margin-top: var(--s-2);
  max-width: 48ch;
}

.row .arw {
  font-family: var(--mono);
  color: var(--secondary);
  align-self: center;
}

/* Whole-row link: the anchor covers the row without nesting interactives. */
.row-link { position: relative; }
.row-link a.stretch { color: inherit; text-decoration: none; }
.row-link a.stretch::after {
  content: "";
  position: absolute;
  inset: 0;
}
.row-link:hover .ttl {
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.16em;
}
.row-link:hover .arw { color: var(--accent); }
/* Focus ring: ring the whole row where :has() is available, and fall back to
   ringing the title text where it isn't. The fallback comes first so a browser
   without :has() still gets a visible indicator rather than none at all. */
.row-link a.stretch:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
@supports selector(a:has(b)) {
  .row-link:has(a.stretch:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
  }
  .row-link a.stretch:focus-visible { outline: none; }
}

@media (max-width: 44rem) {
  .row {
    grid-template-columns: 1fr auto;
    gap: var(--s-2) var(--s-4);
  }
  .row .lab { grid-column: 1 / -1; padding-top: 0; }
}

/* ---------- Case-study block (Work) ------------------------------------- */

.case {
  border-top: 1px solid var(--rule);
  padding-block: var(--s-7);
}
.case:last-of-type { border-bottom: 1px solid var(--rule); }

.case-tags {
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: 0.06em;
  color: var(--secondary);
  margin: 0;
}

.case h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-3);
  line-height: 1.18;
  margin: var(--s-3) 0 0;
  max-width: 26ch;
}

.case-blocks {
  display: grid;
  gap: var(--s-5);
  margin-top: var(--s-6);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
}

.case-block {
  display: grid;
  grid-template-columns: var(--label-col) 1fr;
  gap: var(--s-5);
  align-items: baseline;
}

.case-block .k {
  font-family: var(--mono);
  font-size: var(--t--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.case-block .v { margin: 0; max-width: var(--measure); }

.case-index {
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: 0.1em;
  color: var(--secondary);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 44rem) {
  .case-block { grid-template-columns: 1fr; gap: var(--s-2); }
}

/* ---------- Experiment entries ------------------------------------------ */

.exp {
  border-bottom: 1px solid var(--rule);
  display: grid;
  grid-template-columns: var(--label-col) 1fr;
  gap: var(--s-5);
  padding-block: var(--s-6);
}
.exps { border-top: 1px solid var(--rule); }

/* Status is a mono label, not a coloured pill — colour would make Parked
   read as a failure state. */
.status {
  font-family: var(--mono);
  font-size: var(--t--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--secondary);
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
}
.status::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  translate: 0 -0.15em;
  border: 1px solid var(--secondary);
}
.status[data-status="running"]::before { background: var(--accent); border-color: var(--accent); }
.status[data-status="answered"]::before { background: var(--secondary); }
.status[data-status="parked"]::before { background: transparent; }

.exp h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-2);
  line-height: 1.2;
  margin: 0;
  max-width: 30ch;
}

.exp .question {
  margin: var(--s-3) 0 0;
  max-width: var(--measure);
}

.exp .why {
  margin: var(--s-4) 0 0;
  max-width: var(--measure);
  border-left: 2px solid var(--rule);
  padding-left: var(--s-4);
  color: var(--secondary);
  font-size: var(--t--1);
}

.exp-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  list-style: none;
  margin: var(--s-5) 0 0;
  padding: 0;
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: 0.06em;
}
.exp-links a {
  color: var(--secondary);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 2px;
}
.exp-links a:hover { color: var(--ink); border-bottom-color: var(--accent); }

/* The graduation link is the most important one on the page. */
.exp-links .graduated a {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.exp-links .graduated a:hover { color: var(--accent); border-bottom-width: 2px; }

@media (max-width: 44rem) {
  .exp { grid-template-columns: 1fr; gap: var(--s-3); }
}

/* ---------- Build entries ----------------------------------------------- */

.build {
  border-top: 1px solid var(--rule);
  padding-block: var(--s-7);
  display: grid;
  gap: var(--s-6);
  grid-template-columns: 1fr;
}
.builds { }
.build:last-of-type { border-bottom: 1px solid var(--rule); }

@media (min-width: 52rem) {
  .build { grid-template-columns: 1fr 1fr; gap: var(--s-7); align-items: start; }
}

.build h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-3);
  line-height: 1.18;
  margin: var(--s-3) 0 0;
  max-width: 24ch;
}

.build .body { margin-top: var(--s-4); max-width: var(--measure); }
.build .body p { margin: 0 0 var(--s-4); }
.build .body p:last-child { margin-bottom: 0; }

/* Photography sits on a hairline border so white-background shots don't
   glare against the dark ground. */
figure.shot { margin: 0; }
figure.shot img,
figure.shot .placeholder {
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: 2px;
}
figure.shot figcaption {
  font-family: var(--mono);
  font-size: var(--t--2);
  color: var(--secondary);
  margin-top: var(--s-3);
  letter-spacing: 0.04em;
}

.placeholder {
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  padding: var(--s-5);
  text-align: center;
  font-family: var(--mono);
  font-size: var(--t--2);
  color: var(--secondary);
  line-height: 1.5;
}

/* ---------- Meta block (Games) ------------------------------------------ */

.meta {
  display: grid;
  grid-template-columns: var(--label-col) 1fr;
  gap: var(--s-3) var(--s-5);
  margin: var(--s-5) 0 0;
  border-top: 1px solid var(--rule);
  padding-top: var(--s-5);
  font-size: var(--t--1);
}
.meta dt {
  font-family: var(--mono);
  font-size: var(--t--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--secondary);
}
.meta dd { margin: 0; }

@media (max-width: 44rem) {
  .meta { grid-template-columns: 1fr; gap: var(--s-1) 0; }
  .meta dd { margin-bottom: var(--s-3); }
}

/* ---------- Sections ---------------------------------------------------- */

.section { padding-block: var(--s-8); }
.section > .eyebrow + h2 { margin-top: var(--s-4); }

.section h2 {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-3);
  line-height: 1.18;
  letter-spacing: -0.008em;
  margin: 0 0 var(--s-5);
  max-width: 28ch;
}

.section > h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t-1);
  line-height: 1.25;
  margin: 0 0 var(--s-3);
}

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

.foot {
  border-top: 1px solid var(--rule);
  margin-top: var(--s-9);
}
.foot-inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-6);
  justify-content: space-between;
  padding-block: var(--s-6) var(--s-8);
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--secondary);
}
.foot-inner a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule); }
.foot-inner a:hover { color: var(--ink); border-bottom-color: var(--accent); }
.foot-nav { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5); }

/* ---------- Per-section accent ------------------------------------------ */

body[data-section="work"]        { --accent: var(--accent-work); }
body[data-section="builds"]      { --accent: var(--accent-builds); }
body[data-section="experiments"] { --accent: var(--accent-experiments); }
body[data-section="community"]   { --accent: var(--accent-community); }
body[data-section="games"]       { --accent: var(--accent-games); }

/* ---------- Print ------------------------------------------------------- */
/* About is the page most likely to be printed, and a dark page prints as a
   wall of ink. Force the light palette regardless of system setting. */

@media print {
  :root, :root[data-theme="dark"] {
    --paper: #FFFFFF;
    --surface: #FFFFFF;
    --ink: #2E2830;
    --secondary: #2E2830;
    --rule: #BBBBBB;
    --accent: #4E2665;
  }
  body { font-size: 11pt; }
  .nav-links, .skip, .foot-nav { display: none; }
  .masthead { border-bottom: 1px solid var(--rule); }
  .case, .exp, .build, .row { break-inside: avoid; }
  .page-head { padding-block: 0 var(--s-5); }
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-family: var(--mono);
    font-size: 9pt;
    color: var(--secondary);
    word-break: break-all;
  }
}

/* =========================================================================
   Home page headline: the line slips, a robot rolls in and levels it.
   Zero JavaScript: every keyframe set shares one 7s timeline and ends in the
   resting state (headline level, robot off-stage). Only index.html uses it.
   ========================================================================= */

/* The track the robot rolls along. overflow:hidden is load-bearing — without
   it the robot exiting right creates a horizontal scrollbar on the page. */
.fix-stage {
  position: relative;
  overflow: hidden;      /* stops the departing robot creating a scrollbar */
  padding-bottom: var(--s-2);
}

/* The robot has to be anchored to the headline, not to the whole header block,
   or it rolls along under the lede instead of along the accent rule. */
.headline-wrap { position: relative; }

/* --- The headline ------------------------------------------------------- */
/* Rotates about its own left edge, like a sheet slipping on a desk. */
.fix-stage h1 {
  transform-origin: 0% 60%;
  will-change: transform;
  animation: slip 7s cubic-bezier(.4,0,.2,1) 1 both;
}

/* The existing accent hairline is the rail the robot runs on, so it stays
   put while the words above it tilt. */
.fix-stage h1::after { transition: none; }

/* Positive rotation = clockwise, so the right-hand end drops. The left edge is
   the pivot, which keeps the headline's left margin locked to the eyebrow above
   and the lede below — it reads as a sheet slipping off one pin, not as the
   whole block sliding. */
@keyframes slip {
  0%,  8%  { transform: rotate(0deg)     translateY(0); }
  /* it gives way, slowly at first then all at once */
  13%      { transform: rotate(0.5deg)   translateY(1px); }
  20%      { transform: rotate(3deg)     translateY(5px); }
  /* sits there looking wrong long enough that you want it dealt with,
     and long enough for the robot to arrive and get the level up */
  56%      { transform: rotate(3deg)     translateY(5px); }
  /* the fix: fast, with a tiny overshoot so it reads as a snap, not a glide */
  60%      { transform: rotate(-0.5deg)  translateY(-1px); }
  63%      { transform: rotate(0.14deg)  translateY(0); }
  66%, 100%{ transform: rotate(0deg)     translateY(0); }
}

/* --- The robot ---------------------------------------------------------- */
.robot {
  position: absolute;
  left: 0;
  /* h1::after (the accent rule) sits 24px below the text, 2px tall. Drop the
     robot so its wheels land on that rule. */
  bottom: -6px;
  width: 54px;
  height: auto;
  color: var(--accent);
  animation: trundle 7s cubic-bezier(.45,0,.3,1) 1 both;
  will-change: transform;
}
.robot svg { display: block; overflow: visible; }

@keyframes trundle {
  0%,  16% { transform: translateX(-90px); }
  /* rolls in and pulls up under the dropped right-hand end of the line —
     it has to stop where the problem is, or the fix looks like a coincidence */
  44%      { transform: translateX(clamp(140px, 30vw, 350px)); }
  /* holds, level up, while the line is still visibly wrong */
  68%      { transform: translateX(clamp(140px, 30vw, 350px)); }
  /* and carries on, job done */
  100%     { transform: translateX(calc(100% + 100vw)); }
}

/* Wheels turn only while it is actually moving. */
.robot .wheel {
  transform-origin: center;
  animation: roll 7s linear 1 both;
}
.robot .wheel-b { animation-name: roll-b; }

@keyframes roll {
  0%,16%   { transform: rotate(0deg); }
  44%      { transform: rotate(740deg); }
  68%      { transform: rotate(740deg); }   /* stopped, working */
  100%     { transform: rotate(2050deg); }
}
@keyframes roll-b {
  0%,16%   { transform: rotate(0deg); }
  44%      { transform: rotate(740deg); }
  68%      { transform: rotate(740deg); }
  100%     { transform: rotate(2050deg); }
}

/* The arm lifts the spirit level up to the line, then drops. */
.robot .arm {
  transform-origin: 30px 30px;
  animation: reach 7s cubic-bezier(.4,0,.2,1) 1 both;
}
@keyframes reach {
  0%, 44%  { transform: rotate(24deg); }
  /* level goes up and is held against the crooked line for a beat */
  50%      { transform: rotate(-7deg); }
  58%      { transform: rotate(-10deg); }
  64%      { transform: rotate(-10deg); }
  72%      { transform: rotate(24deg); }
  100%     { transform: rotate(24deg); }
}

/* The bubble in the level slides to centre at the moment the line goes true. */
.robot .bubble { animation: settle 7s cubic-bezier(.3,0,.2,1) 1 both; }
@keyframes settle {
  0%, 56%  { transform: translateX(-3.2px); }
  60%      { transform: translateX(0.7px); }
  64%      { transform: translateX(0); }
  100%     { transform: translateX(0); }
}

/* Eyes blink once while it lines up the shot. */
.robot .eye { animation: blink 7s steps(1,end) 1 both; }
@keyframes blink {
  0%, 46%  { transform: scaleY(1); }
  47%      { transform: scaleY(0.15); }
  49%      { transform: scaleY(1); }
  100%     { transform: scaleY(1); }
}
.robot .eye { transform-origin: center; transform-box: fill-box; }

/* --- Reduced motion ----------------------------------------------------- */
/* site.css already forces animation-duration to 0.01ms under
   prefers-reduced-motion. That lands every animation on its 100% frame, which
   is why every keyframe set above ENDS in the resting state: headline level,
   robot off-screen. Nothing here needs a second reduced-motion block, and the
   page is never left looking broken. */

/* In print the robot is just clutter beside the headline. */
@media print {
  .robot { display: none; }
  .fix-stage h1 { animation: none; }
}
