/* ==========================================================================
   rexchekal.com: the holding page, 2026-10-25
   Laid out on Extra Extra's system (~/Sites/extra-extra/site.css): Geist at 400,
   Geist Mono labels in caps, a hairline frame and a footer bar, and one loud
   block with the Extra Extra wordmark. Every colour comes from the theme engine
   (assets/theme.js), a new palette colour on every load (D-012): --ground and
   --ink are the page, --muted the secondary text (held at 6:1). The block is a misprint
   on paper whose inks derive from the same colour (assets/misprint.js, D-013).
   The values below are the no-JS fallback.
   ========================================================================== */
:root {
  --ground: #F6F7F7;
  --ink: #15161A;
  --muted: color-mix(in oklab, var(--ink) 70%, var(--ground));
  --quiet: color-mix(in oklab, var(--ink) 58%, var(--ground));   /* the line under a name or title, lightest at AA; theme.js sets it */
  --line: color-mix(in srgb, var(--ink) 16%, var(--ground));   /* the hairlines; they carry no text */
  --paper: #FFFFFF;    /* the Extra Extra block's paper and inks: assets/misprint.js sets them from the theme */
  --paper-ink: var(--ink);
  --ink-a: var(--ink);
  --ink-b: var(--orange);
  --orange: #FF5A1F;   /* the misprint's second ink when the page has no hue (assets/misprint.js); it carries no text */
  --green: #16A34A;    /* the availability dot only */
  --text: "Geist", system-ui, sans-serif;
  --mono: "Geist Mono", ui-monospace, monospace;
  --pad: 24px;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--ground); color: var(--ink); font: 400 16px/1.5 var(--text); }
a { color: inherit; text-decoration: none; }
p, h1, h2, ul { margin: 0; padding: 0; font: inherit; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.label { font: 400 12px/1.4 var(--mono); letter-spacing: .06em; text-transform: uppercase; }
.gray { color: var(--muted); }

.frame { max-width: 720px; min-height: 100svh; margin: 0 auto; display: flex; flex-direction: column;
  border-left: 1px solid var(--line); border-right: 1px solid var(--line); }
.bar { display: flex; justify-content: space-between; align-items: center; height: 48px; padding: 0 var(--pad); border-bottom: 1px solid var(--line); }
/* the availability flag sits under the intro (Rex, 2026-10-27, moved from beside Contact).
   Its green dot pings, the standard live-status mark (Tailwind's animate-ping): a ring the
   dot's colour grows to 2.4 times its size and fades, every 1.2 s; the dot carries no text. */
.avail { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.avail i { position: relative; width: 8px; height: 8px; border-radius: 50%; background: var(--green); }
.avail i::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: inherit;
  animation: ping 1.2s cubic-bezier(0, 0, .2, 1) infinite; }
@keyframes ping { 75%, 100% { transform: scale(2.4); opacity: 0; } }
.cell { display: grid; gap: 16px; padding: 40px var(--pad); border-bottom: 1px solid var(--line); }

/* the h1: Extra Extra's second heading size (Rex, 2026-10-26: "make the h1 bigger") */
.hello { font-size: 48px; font-weight: 300; line-height: 1.05; letter-spacing: -0.02em; margin-bottom: 16px; }   /* Light: Rex, "h1 is too heavy" */
/* the intro sits back in the secondary gray, so the h1 leads (Rex, 2026-10-26: "make the intro a
   lighter font... its all reading as one block") */
.lede { font-size: 16px; line-height: 1.5; color: var(--muted); max-width: 40em; }   /* body regular (Rex, 2026-10-26: "drop it to that") */
/* on a ground of the dot's own hue the dot takes the ink, so it never vanishes */
:root[data-theme="green"] .avail i { background: var(--ink); }

/* the Extra Extra block, the whole of it a link: paper, with the wordmark printed in two
   inks a few pixels out of register, overprinting darker where they meet (Rex picked
   the misprint 2026-10-25). On a pale page the paper takes a hairline along its bottom. */
.block { display: grid; gap: 16px; padding: 40px var(--pad); background: var(--paper); color: var(--paper-ink); }
:root[data-misprint-edge] .block { box-shadow: inset 0 -1px 0 var(--line); }   /* bottom only: the cell above draws the top and the frame the sides (Rex, 2026-10-27: "we only need top and bottom dividers") */
.block:focus-visible { outline-color: var(--ink); outline-offset: 3px; }
/* The wordmark is inline (_includes/extra-mark.njk) so its edges can boil, like a
   hand-drawn cartoon's line; Rex picked the boil 2026-10-25 over a shout and a hop. */
.riso { margin-bottom: 16px; position: relative; display: block; width: min(280px, 60%); aspect-ratio: 832 / 791; }
.plate { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; mix-blend-mode: multiply; }
.plate-a { color: var(--ink-a); transform: translate(-3px, -2px); }
.plate-b { color: var(--ink-b); transform: translate(3px, 2px); }
.block-text { display: grid; gap: 16px; }
.block-text > span:first-child { font-size: 20px; line-height: 1.4; max-width: 30ch; }
.visit { display: inline-flex; }

/* Clients: the portfolio's logo marquee (site.css, 2026-09-21), rows written by
   scripts/build-marquee.py. Each logo is a mask in the page's ink, so it takes the
   load's colour; each track holds its set twice and travels half its width, so the
   loop has no jump; the rows run edge to edge of the frame. Rex, 2026-10-26: "put my
   client cloud on the page? and have it move". */
.logo-bleed { margin: 8px calc(-1 * var(--pad)) 0; display: grid; gap: 24px; }
.marquee { overflow: hidden; }
.marquee-track { display: flex; align-items: center; width: max-content; min-height: 56px; margin: 0; padding: 0; list-style: none; will-change: transform; }
.logo { display: block; flex: none; margin-right: 64px; background: currentColor;
  -webkit-mask-size: contain; -webkit-mask-position: center; -webkit-mask-repeat: no-repeat;
          mask-size: contain;         mask-position: center;         mask-repeat: no-repeat; }
.track-left  { animation: marquee-left  var(--dur, 64s) linear infinite; }
.track-right { animation: marquee-right var(--dur, 78s) linear infinite; }
@keyframes marquee-left  { from { transform: translateX(0); }    to { transform: translateX(-50%); } }
@keyframes marquee-right { from { transform: translateX(-50%); } to { transform: translateX(0); } }
@media (hover: hover) and (pointer: fine) { .marquee:hover .marquee-track { animation-play-state: paused; } }
/* the reduced-motion stops hold until the footer switch says Motion on (body.moving); without the script they always hold */
@media (prefers-reduced-motion: reduce) {
  body:not(.moving) .marquee { overflow-x: auto; }
  body:not(.moving) .marquee-track { animation: none !important; transform: none !important; }
}

/* Work at TXI: a sideways rail copied from Contessa's .scroller.vrail (via site.css's .rail):
   a flex row, horizontal scroll only (overflow-y stays hidden so a trackpad never bounces it),
   no scrollbar, the first card on the text margin and the last stopping on the right margin
   (the row's own end padding does it; a margin on the last card as well doubled the gap,
   measured 2026-10-27). The padding-block keeps the focus ring unclipped. */
.rail { display: flex; gap: 16px; list-style: none; overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain; scroll-snap-type: x proximity; scroll-padding-left: var(--pad);
  margin: 0 calc(-1 * var(--pad)); padding: 4px var(--pad); scrollbar-width: none; }
.rail::-webkit-scrollbar { display: none; }
.rail > li { flex: 0 0 max(280px, calc((100% - 64px) / 2)); display: flex; scroll-snap-align: start; }   /* two cards to a frame and a 48px edge of the third (Rex: "like 2 not 2.5", then "too wide"), 280px on a phone */
/* a card stacks the image, full bleed, then label, title, description, client; the client sits at the foot so the row's feet align */
.card { flex: 1; display: flex; flex-direction: column;
  border: 1px solid var(--line); transition: border-color 150ms ease-out; }   /* a border, not an inset shadow, so the image sits inside the line (Rex, 2026-10-27) */
.card-img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }   /* full bleed, cropped tight (Rex, 2026-10-27); the TXI case study's own image, masters in assets/img/txi/src/ */
.card-body { flex: 1; display: flex; flex-direction: column; gap: 8px; padding: 24px; }
.card-title { font-size: 20px; line-height: 1.3; margin-top: 8px; }
.card-foot { margin-top: auto; padding-top: 16px; }
.card-foot .arrow { margin-left: 8px; vertical-align: 1px; }
.card:focus-visible { outline-offset: -2px; }

.rows { list-style: none; display: grid; }
.rows li { display: grid; grid-template-columns: 112px 1fr; gap: 16px; padding: 12px 0; border-top: 1px solid var(--line); }
.rows li > .label { padding-top: 3px; }
.role { display: block; color: var(--quiet); font-size: 14px; line-height: 1.45; }   /* body small, under the name (Rex, 2026-10-26); also the work cards and press rows */
.rows-plain li { display: block; }   /* skills: one per row, the experience list's rhythm */

.foot { margin-top: auto; display: flex; flex-wrap: wrap; border-top: 1px solid var(--line); }
.foot > * { display: flex; align-items: center; height: 48px; padding: 0 var(--pad); border-right: 1px solid var(--line); }
.foot .cta { background: var(--ink); color: var(--ground); }
.foot > :last-child { border-right: 0; margin-left: auto; }

/* Hovers follow the portfolio's colour system (site.css, DESIGN_SYSTEM.md): a text link
   underlines, never a colour fade; a button fills with the ink, or turns over to the
   ground when it is already ink; a drawn arrow slides 4px; a card's art grows a little;
   pressing lays the ink at 16%. Every state is the theme's own ink and ground, so each
   holds its contrast on every colour. */
.link { text-decoration: underline 1px transparent; text-underline-offset: .2em; transition: text-decoration-color 150ms ease-out; }
.arrow { display: inline-block; flex: none; width: 15px; height: 10px; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'%3E%3Cpath d='M0 6H16.6M11 0.6L16.6 6L11 11.4' fill='none' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 12'%3E%3Cpath d='M0 6H16.6M11 0.6L16.6 6L11 11.4' fill='none' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform 150ms ease-out; }
.visit, .foot .cta { align-items: center; gap: 10px; }
.foot .cta { box-shadow: inset 0 0 0 1px var(--ink); transition: background-color 150ms ease-out, color 150ms ease-out; }
.riso { transition: transform .5s cubic-bezier(.19, 1, .22, 1); }
@media (hover: hover) and (pointer: fine) {
  .link:hover, .block:hover .visit .link { text-decoration-color: currentColor; }
  .block:hover .arrow, .foot .cta:hover .arrow, .card:hover .arrow { transform: translateX(4px); }
  .card:hover { border-color: var(--ink); }
  .block:hover .riso { transform: scale(1.04); }
  .foot .cta:hover { background: var(--ground); color: var(--ink); }
}
.foot .cta:active { background: color-mix(in srgb, var(--ink) 16%, var(--ground)); color: var(--ink); }
/* Motion off (the footer switch, or the reduced-motion setting through it): everything that moves on its own holds */
body.still .marquee-track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { body:not(.moving) .avail i::after { animation: none; opacity: 0; } }
body.still .avail i::after { animation: none; opacity: 0; }
body.still .riso, body.still .arrow, body.still .card { transition: none; }
.foot .motion { appearance: none; border: 0; border-right: 1px solid var(--line); background: none; font: inherit; color: inherit; cursor: pointer; text-transform: inherit; letter-spacing: inherit; }
.foot .motion:focus-visible { outline-offset: -4px; }
@media (hover: hover) and (pointer: fine) { .foot .motion:hover { text-decoration: underline; text-underline-offset: .2em; } }
/* Below a desktop the frame fills the window edge to edge, no side gutters or side
   hairlines (Rex, 2026-10-25: "on responsive have it go full width as it gets to mobile"). */
@media (max-width: 520px) { .hello { font-size: 32px; } }
@media (max-width: 899px) { .frame { max-width: none; border-left: 0; border-right: 0; } }
@media (max-width: 520px) {
  .rows li { grid-template-columns: 1fr; gap: 2px; }
  .foot > :last-child { margin-left: 0; }
}
