/* raayoni — tobias.raayoni-last.com
 *
 * Index after dominofactory.net: a Muuri grid of greyscale-at-rest tiles.
 * Entry after fabriziopoltronieri.com: fixed parallax hero, narrow centred
 * column, and a hierarchy that switches typeface by purpose — sans small-caps
 * for titles, mono for metadata, serif for prose.
 *
 * Both references hard-code hex and are dark-only. Everything here goes through
 * custom properties so the light/dark switch is not a retrofit.
 */

/* ── Lato, self-hosted ───────────────────────────────────────────────────
 * SIL Open Font License, so redistribution is fine. Self-hosted rather than
 * loaded from Google's CDN: no third-party request on a site aimed partly at
 * German and EU cultural institutions, and no external dependency in a static
 * build. latin-ext is needed for the client names — Kežmarok, szerk, Schmück.
 *
 * Lato ships 400, 700 and 900 only. There is no 800 or 600, so the weights
 * below are snapped to what actually exists rather than letting the browser
 * synthesise.
 */
@font-face { font-family: Lato; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/lato-400-normal-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: Lato; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/lato-400-normal-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: Lato; font-style: italic; font-weight: 400; font-display: swap;
  src: url(../fonts/lato-400-italic-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: Lato; font-style: italic; font-weight: 400; font-display: swap;
  src: url(../fonts/lato-400-italic-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: Lato; font-style: normal; font-weight: 700; font-display: swap;
  src: url(../fonts/lato-700-normal-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: Lato; font-style: normal; font-weight: 700; font-display: swap;
  src: url(../fonts/lato-700-normal-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: Lato; font-style: normal; font-weight: 900; font-display: swap;
  src: url(../fonts/lato-900-normal-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: Lato; font-style: normal; font-weight: 900; font-display: swap;
  src: url(../fonts/lato-900-normal-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }

/* ── palette ─────────────────────────────────────────────────────────────
 * Contrast note: the entry reference sets metadata at #444 and subheads at
 * #555 on a #111 ground — about 1.9:1 and 2.6:1, which fails WCAG AA badly.
 * The recessive hierarchy is kept, but the quiet tones are lifted to pass.
 */
:root {
  --font-sans:  Lato, "Helvetica Neue", Arial, system-ui, sans-serif;
  --font-mono:  "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-serif: "Source Serif 4", Charter, Georgia, "Times New Roman", serif;

  --measure: 60%;          /* entry column width, per the reference */
  --accent:  #ffa07a;      /* lightsalmon, from the reference */
}

:root, [data-theme="dark"] {
  /* Not decoration: without color-scheme the browser treats the document as
     light, so the canvas it paints between documents, and the scrollbar, are
     white. On Gecko that is the white frame you see on every navigation. */
  color-scheme: dark;
  --ground:     #111;
  --ground-alt: #191919;
  --title:      #aaa;
  --body:       #bbb;
  --sub:        #777;      /* lifted from #555 */
  --meta:       #8d8d8d;   /* lifted from #444 */
  --rule:       #2a2a2a;
  --tile:       #1a1a1a;
  --panel-lift: rgba(0,0,0,.6);
  --thumb-rest: grayscale(100%) contrast(1.05);
}

[data-theme="light"] {
  color-scheme: light;
  --ground:     #f7f6f4;
  --ground-alt: #efeeea;
  --title:      #2b2b2b;
  --body:       #343434;
  --sub:        #6a6a6a;
  --meta:       #5f5f5f;
  --rule:       #dcdad4;
  --tile:       #eceae5;
  --panel-lift: rgba(0,0,0,.22);
  /* grayscale alone reads washed out on a pale ground; a little contrast and
     a touch of darkening keeps the tile deliberate rather than faded */
  --thumb-rest: grayscale(100%) contrast(1.12) brightness(.94);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    color-scheme: light;
    --ground: #f7f6f4; --ground-alt: #efeeea; --title: #2b2b2b; --body: #343434;
    --sub: #6a6a6a; --meta: #5f5f5f; --rule: #dcdad4; --tile: #eceae5;
    --panel-lift: rgba(0,0,0,.22);
    --thumb-rest: grayscale(100%) contrast(1.12) brightness(.94);
  }
}

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

html, body { margin: 0; min-height: 100%; }

body {
  background: var(--ground);
  color: var(--body);
  font-family: var(--font-serif);
  font-size: 1.3em;
  line-height: 1.6;
  letter-spacing: .0611111rem;
  -webkit-font-smoothing: antialiased;
  transition: background-color .35s ease, color .35s ease;
}

a { color: var(--body); text-decoration: none; border-bottom: 1px solid var(--rule); }
a:hover { color: var(--accent); border-bottom-color: var(--accent); }

h1, h2, h3 { font-family: var(--font-sans); font-weight: 900; text-align: left; margin: 0; }
/* Lato has no true small caps, so this is browser-synthesised. At weight 900
   and display size it holds; for real control swap to:
     text-transform: uppercase; font-size: 3em; letter-spacing: .02em; */
h1 { font-size: 4em; color: var(--title); font-variant-caps: all-small-caps;
     padding: 3em 0 0; line-height: 1; }
h1.tight { padding-top: .35em; }
h2 { font-size: 2.2em; color: var(--title); }
h3 { font-size: 1.8em; color: var(--sub); padding: 0 15vw 2vh 0; }
h4 { font-family: var(--font-mono); font-weight: 400; font-size: 1.2em; color: var(--meta); margin: 0; }

p { margin: 0; padding: 0 0 3vh; }

/* ── chrome ───────────────────────────────────────────────────────────── */
.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; gap: 1.2rem; align-items: baseline; flex-wrap: wrap;
  padding: .9rem 5vw; background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(8px); border-bottom: 1px solid var(--rule);
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .04em;
}
.bar a, .bar button { border: 0; background: none; color: var(--meta); cursor: pointer;
  font: inherit; padding: 0; text-transform: lowercase; }
.bar a:hover, .bar button:hover, .bar .on { color: var(--accent); }
.bar .me { color: var(--title); font-weight: 700; margin-right: auto; text-transform: none; }
.bar .sep { color: var(--rule); }

/* ── index grid ───────────────────────────────────────────────────────── */
.controls {
  display: flex; gap: .55rem 1rem; flex-wrap: wrap; align-items: center;
  padding: 2.2rem 5vw .4rem; font-family: var(--font-mono);
  font-size: .72rem; letter-spacing: .04em;
}
.controls .label { color: var(--sub); margin-right: .2rem; }
.controls button { background: none; border: 1px solid var(--rule); border-radius: 2px;
  color: var(--meta); cursor: pointer; font: inherit; padding: .22rem .55rem; }
.controls button:hover { color: var(--accent); border-color: var(--accent); }
.controls button[aria-pressed="true"] { color: var(--ground); background: var(--title); border-color: var(--title); }
.controls .count { color: var(--sub); margin-left: auto; }

.grid { position: relative; padding: 1rem 5vw 8vh; }
.item { display: block; position: absolute; width: 25%; padding: .55rem; z-index: 1; }
.item.muuri-item-hidden { z-index: 0; }
.item-content { position: relative; }
@media (max-width: 1500px) { .item { width: 33.333%; } }
@media (max-width: 1000px) { .item { width: 50%; } }
@media (max-width:  620px) { .item { width: 100%; } }

.hoverthumb { position: relative; overflow: hidden; background: var(--tile);
  aspect-ratio: 4 / 3; border: 1px solid var(--rule); }
.hoverthumb img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; transition: transform 1.2s ease; }

/* Hovering a tile dims its siblings rather than colourising the target. Same
 * job — one thing legible at a time across images of uneven quality — without
 * needing a greyscale duplicate of every thumbnail. */
.grid:hover .item:not(.head) .item-content { opacity: .34; filter: saturate(.55); }
.grid .item:not(.head) .item-content:hover { opacity: 1; filter: none; }
.item-content { transition: opacity .32s ease, filter .32s ease; }
.item-content:hover .hoverthumb img { transform: scale(1.03); }
@media (hover: none) { .grid:hover .item .item-content { opacity: 1; filter: none; } }

/* No surviving image: the tile becomes typographic rather than broken.
   ~35 entries are in this position — see ../../IMAGES.md */
.hoverthumb.empty { display: grid; place-items: center; aspect-ratio: 4 / 3; }
.hoverthumb.empty span { font-family: var(--font-mono); font-size: .68rem;
  color: var(--sub); letter-spacing: .12em; text-transform: uppercase; }

.item .content { padding: .7rem 0 0; }
.item .title { font-family: var(--font-sans); font-weight: 700; font-size: 1.05rem;
  line-height: 1.12; color: var(--title); margin-bottom: .3rem; }
.item .year { font-family: var(--font-mono); font-size: .68rem; color: var(--sub); }
.item .description { font-size: .82rem; line-height: 1.35; color: var(--body);
  margin: .3rem 0 .4rem; }
.item .tags { font-family: var(--font-mono); font-size: .66rem; color: var(--meta); }
.item .tags span { margin-right: .45rem; }
.item a.cover { position: absolute; inset: 0; border: 0; }

/* ── entry ────────────────────────────────────────────────────────────── */
/* The hero stops short of the fold and the prose panel rides up over it, so
 * the page reads as having something below rather than ending at the image.
 * A full-height hero gave no affordance to scroll at all.
 */
.hero { height: 82vh; background-attachment: fixed; background-position: 50%;
  background-repeat: no-repeat; background-size: cover; position: relative; }
@media (max-width: 600px) { .hero { background-attachment: scroll; height: 56vh; } }

.pages { width: 100vw; display: flex; background: var(--ground);
  position: relative; z-index: 2; }
/* The lift only applies when an image hero actually precedes the panel. Putting
   it on .pages unconditionally pulled the title under the sticky bar on
   timeline, disciplines and tags, which have no hero at all. */
.hero + .pages { margin-top: -5.5rem;
  box-shadow: 0 -26px 46px -14px var(--panel-lift); }
@media (max-width: 600px) { .hero + .pages { margin-top: -3.5rem; } }

/* Listing pages start at the top of the document, so they need clearance from
   the sticky bar in their own right. */
.pages > .frame > h1.tight:first-child { padding-top: 2.6rem; }
.hero + .pages > .frame > h1.tight:first-child,
.markplate + h1.tight { padding-top: .35em; }

/* a quiet cue on the hero itself */
.scrollcue { position: absolute; left: 50%; bottom: 6.6rem; transform: translateX(-50%);
  z-index: 3; font-family: var(--font-mono); font-size: .62rem; letter-spacing: .22em;
  text-transform: uppercase; color: var(--title); opacity: .75;
  text-shadow: 0 1px 10px rgba(0,0,0,.65); pointer-events: none;
  animation: cue 2.6s ease-in-out infinite; }
@keyframes cue { 0%,100% { transform: translate(-50%,0); } 50% { transform: translate(-50%,6px); } }
.frame { width: var(--measure); display: block; margin: auto; }
@media (max-width: 600px) { .frame { width: 100%; } }

.text { padding: 5vh 0 20vh; }
@media (max-width: 600px) {
  h1 { font-size: 2.5em; padding: 15vw 5vw 0; }
  h2 { font-size: 1.8em; padding-left: 5vw; }
  h3 { font-size: 1.4em; padding: 2vh 5vw 0; }
  h4 { padding: 2vw 5vw 0; }
  p  { font-size: 1em; padding: 2vh 5vw; }
  .text { padding: 5vh 0; }
}

/* the credit line — For / HiredBy / With / PhotosBy, set in mono */
.credits { font-family: var(--font-mono); font-size: .78rem; line-height: 1.75;
  color: var(--meta); padding: 0 0 3vh; }
.credits .rel { color: var(--sub); }
.credits a { border-bottom-color: var(--rule); }
@media (max-width: 600px) { .credits { padding: 0 5vw 3vh; } }

.entry-meta { font-family: var(--font-mono); font-size: .72rem; color: var(--sub);
  letter-spacing: .06em; padding: .4rem 0 2vh; }
.entry-meta a { border: 0; color: var(--meta); }
.entry-meta a:hover { color: var(--accent); }
@media (max-width: 600px) { .entry-meta { padding-left: 5vw; } }

.body img { max-width: 100%; height: auto; display: block; margin: 0 0 3vh; }
/* Width-only sizing left embeds at their source width/height attributes (or
   the 300x150 default when absent) scaled down to fit, not up to fill — the
   height attribute then held while the width shrank, squashing the frame. */
.body iframe, .body embed { width: 100%; aspect-ratio: 16/9; border: 0; margin: 0 0 3vh; }
/* Migrated entries carry a bare background-image div as an inline banner.
   Unsized, the image showed only its native-resolution top-left corner. */
.body .para { width: 100%; background-size: cover; background-position: center;
  background-repeat: no-repeat; margin: 0 0 3vh; }
.body h2 { font-size: 1.5em; padding: 2vh 0 1vh; }

/* ── listings ─────────────────────────────────────────────────────────── */
.rows { list-style: none; margin: 0; padding: 0 0 8vh; }
.rows li { display: flex; gap: 1.2rem; align-items: baseline; padding: .55rem 0;
  border-bottom: 1px solid var(--rule); }
.rows .yr { font-family: var(--font-mono); font-size: .72rem; color: var(--sub);
  min-width: 3.4rem; }
.rows .ti { font-family: var(--font-sans); font-weight: 700; font-size: 1rem;
  color: var(--title); }
.rows .ct { font-family: var(--font-mono); font-size: .66rem; color: var(--meta);
  margin-left: auto; }
.rows a { border: 0; }
.rows a:hover .ti { color: var(--accent); }

.lede { padding: 1vh 0 4vh; color: var(--sub); font-size: 1.05em; }
.cloud { padding: 0 0 8vh; font-family: var(--font-mono); font-size: .8rem; line-height: 2.2; }
.cloud a { margin-right: 1rem; }

footer { border-top: 1px solid var(--rule); padding: 3vh 5vw 6vh;
  font-family: var(--font-mono); font-size: .7rem; color: var(--sub); }
footer a { border: 0; color: var(--meta); }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
  .hero { background-attachment: scroll; }
}

/* ── the mark ─────────────────────────────────────────────────────────────
 * The swift, as used on invoices. Inlined so fill="currentColor" resolves,
 * which means it inverts with the theme from one asset: white on the dark
 * ground, black on the light one.
 */
.bar .me { display: inline-flex; align-items: center; gap: .55rem; }
.mark { height: 1.45rem; width: auto; display: block; color: var(--title); }
.bar .me:hover .mark { color: var(--accent); }

/* Larger on the about page, where it is the identity rather than navigation. */
.markplate { display: block; margin: 0 0 2vh; }
.markplate .mark { height: 5.5rem; }
@media (max-width: 600px) { .markplate { padding-left: 5vw; } }

/* ── engagement grouping ──────────────────────────────────────────────────
 * Entries belonging to a long relationship sit together under a full-width
 * header. ClipAward is nine entries over four years spanning design,
 * projection and animation — a flat grid cannot say that.
 */
.item.head { width: 100%; padding: 2.4rem .55rem .5rem; }
.item.head:first-child { padding-top: .6rem; }
.grouphead { border-bottom: 1px solid var(--rule); padding-bottom: .5rem;
  display: flex; gap: 1rem; align-items: baseline; flex-wrap: wrap; }
.gname { font-family: var(--font-sans); font-weight: 900; font-size: 1.45rem;
  color: var(--title); font-variant-caps: all-small-caps; letter-spacing: .01em; }
.gmeta { font-family: var(--font-mono); font-size: .68rem; color: var(--sub);
  letter-spacing: .04em; }
/* Flat arrangements hide the headers; so does any active filter. */
.grid:not([data-grouped]) .item.head { display: none; }

/* ── contact ──────────────────────────────────────────────────────────────
 * The address is the point of this page, so it is set at display size rather
 * than buried in a list. The old page hid it behind a document.write()
 * obfuscation that Markdown rendered as visible source, so it was neither
 * clickable nor hidden.
 */
.bigmail { font-family: var(--font-sans); font-weight: 700; font-size: 1.9em;
  line-height: 1.2; padding: 1vh 0 3vh; word-break: break-word; }
.bigmail a { border-bottom-width: 2px; }

.profiles { list-style: none; margin: 0; padding: 2vh 0 3vh;
  font-family: var(--font-mono); font-size: .82rem; }
.profiles li { display: flex; gap: .9rem; align-items: baseline; padding: .3rem 0; }
.profiles .rel { color: var(--sub); min-width: 6.2rem; }
.profiles a { border-bottom-color: var(--rule); }
@media (max-width: 600px) {
  .bigmail, .profiles { padding-left: 5vw; padding-right: 5vw; }
  .bigmail { font-size: 1.4em; }
}
/* no-JS fallback wording, kept quiet so it does not read as emphasis */
.bigmail i { font-style: normal; color: var(--sub); font-size: .62em;
  font-family: var(--font-mono); padding: 0 .15em; }

/* Static pages start directly under the bar: no hero, so they need their own
   top clearance rather than inheriting an empty 30vh placeholder. */
.pages > .frame > .markplate:first-child { padding-top: 3.2rem; }
.pages > .frame > .markplate:first-child + h1.tight { padding-top: .1em; }
