/* Portfolio styles, loaded after /blog/blog.css (tokens, base, header and the
   post layout the work pages reuse). The build copies this file as is into
   static/portfolio/portfolio.css. */
:root {
  /* CTA tile: the panda sheet's sky, blue and ink, the only place they appear.
     Dark: the same hues on a deep blue. Text >= 7:1 on both ends of the gradient. */
  --cta-top-l: #fff;
  --cta-bottom-l: #d9e6f5;
  --bubble-l: #5da2e8;
  --cta-ink-l: #2b1f19;
  --cta-top-d: #242424;
  --cta-bottom-d: #1b2a3c;
  --bubble-d: #4a8ad0;
  --cta-ink-d: #ece6dc;
  --cta-top: var(--cta-top-l);
  --cta-bottom: var(--cta-bottom-l);
  --bubble: var(--bubble-l);
  --cta-ink: var(--cta-ink-l);
  @media (prefers-color-scheme: dark) {
    --cta-top: var(--cta-top-d);
    --cta-bottom: var(--cta-bottom-d);
    --bubble: var(--bubble-d);
    --cta-ink: var(--cta-ink-d);
  }
  @supports (color: light-dark(white, black)) {
    --cta-top: light-dark(var(--cta-top-l), var(--cta-top-d));
    --cta-bottom: light-dark(var(--cta-bottom-l), var(--cta-bottom-d));
    --bubble: light-dark(var(--bubble-l), var(--bubble-d));
    --cta-ink: light-dark(var(--cta-ink-l), var(--cta-ink-d));
  }
  --tile-radius: 10px;
}


/* ── Bento ──────────────────────────── */
.bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 9.5rem;
  grid-auto-flow: dense;
  gap: 0.75rem;
}
.bento.four { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 8.5rem; }
.tile {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--tile-radius);
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  isolation: isolate;
}
.tile.big { grid-column: span 2; grid-row: span 2; }
.tile.wide, .tile.cta { grid-column: span 2; }
.tile img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}
.tile:focus-visible { outline: 3px solid var(--green-dark); outline-offset: 3px; }
/* The caption sits on a dark gradient over the image, so it runs in the dark
   scheme whatever the OS setting (as the blog's narrow-screen cards do). */
.cap {
  position: absolute;
  inset: auto 0 0;
  display: flex;
  flex-wrap: wrap; /* only when the title's longest word and the year can't share the line */
  justify-content: space-between;
  align-items: flex-end;
  gap: 0 0.5rem;
  padding: 2.2rem 0.8rem 0.65rem;
  color-scheme: dark;
  color: var(--ink);
  isolation: isolate;
}
/* the dark bar, under the title and the year */
.cap::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(rgb(0 0 0 / 0), rgb(0 0 0 / 0.75) 2rem, rgb(0 0 0 / 0.85)); /* dark before the text starts */
}
.cap b {
  flex: 1 1 0;
  min-inline-size: min-content;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  line-height: 1.25;
  text-transform: uppercase;
}
.tile.big .cap b { font-size: 1rem; }
/* the year: a square tag in inverted colours, on the bottom line */
.cap span {
  padding: 0.1rem 0.35rem;
  background: var(--ink);
  color: var(--bg);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
}

/* ── CTA tile: the panda rises out of gooey bubbles (same effect as /billing/) ── */
.tile.cta {
  appearance: none;
  border: 0;
  padding: 0;
  font: inherit;
  text-align: start;
  cursor: pointer;
  overflow: visible; /* the panda's head pops out above the tile */
  color: var(--cta-ink);
  background: linear-gradient(180deg, var(--cta-top), var(--cta-bottom));
  box-shadow: inset 0 0 0 1px var(--rule);
}
.cta .goo { position: absolute; inset: 0; overflow: hidden; border-radius: inherit; }
.bubbles { position: absolute; inset: 0; filter: url('#goo'); }
.bubbles::before { /* the pool the bubbles detach from */
  content: '';
  position: absolute;
  inset: auto 52% -2rem -10%;
  block-size: 3.6rem;
  border-radius: 50%;
  background: var(--bubble);
}
.bubbles i {
  position: absolute;
  inset-block-end: -1rem;
  inset-inline-start: var(--x);
  inline-size: var(--s);
  block-size: var(--s);
  border-radius: 50%;
  background: var(--bubble);
  animation: rise var(--d) cubic-bezier(.45, 0, .7, 1) infinite;
  animation-delay: var(--delay);
}
@keyframes rise {
  from { transform: translateY(0) scale(1); }
  to { transform: translateY(-9rem) scale(0.45); }
}
/* clip the bottom and sides to the tile, leave the top open */
.cta .pop {
  position: absolute;
  inset: 0 auto 0 0;
  inline-size: 46%;
  clip-path: inset(-6rem 0 0 0 round 0 0 0 var(--tile-radius));
  pointer-events: none;
}
.cta .panda {
  position: absolute;
  inset: auto 0 -1.1rem; /* sunk below the edge, so the hop never shows the flat cut */
  margin-inline: auto;
  inline-size: 92%;
  block-size: auto;
  object-fit: contain;
  filter: drop-shadow(0 6px 10px rgb(43 31 25 / 0.25));
  transform-origin: 50% 100%;
}
.cta .say {
  position: absolute;
  inset: 0 0 0 46%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.9rem 1rem;
}
.cta .say b { font-size: 1rem; line-height: 1.25; text-wrap: balance; }
.cta .say em { font-style: normal; font-size: 0.82rem; font-weight: 700; color: var(--cta-ink); text-decoration: underline; text-underline-offset: 0.2em; }

/* Motion only for those who did not ask for less: image zoom, panda hop */
@media (prefers-reduced-motion: no-preference) {
  .tile img { transition: transform 0.6s cubic-bezier(.2, .7, .2, 1); }
  .tile:is(:hover, :focus-visible) img:not(.panda) { transform: scale(1.04); }
  .cta:is(:hover, :focus-visible) .panda { animation: hop 0.5s cubic-bezier(.3, 1.6, .5, 1); }
  /* After a view transition the morphing image covers its tile's caption until
     it lands, then would drop it in at once: captions stay hidden while the
     transition runs (.landing on <html>, set by the tile transition script)
     and fade in once it is over. A title that morphs keeps its name and stays;
     the stripped ones (view-transition-name: none) fade in with the bar. */
  .cap::before, .cap span, .cap b { transition: opacity 0.4s ease-out; }
  .landing .cap::before, .landing .cap span, .landing .cap b[style*="none"] { opacity: 0; }
}
@keyframes hop {
  40% { transform: translateY(-8px) rotate(-2deg); }
}
@media (prefers-reduced-motion: reduce) {
  .bubbles i { animation: none; display: none; }
}

/* ── Work page ──────────────────────── */
/* the facts under the lead: a spec sheet between hairlines, label on the
   left and value on the right, a size smaller and a tone lower than the body.
   Each row is a subgrid, so the labels share one column at any length. */
.work-meta {
  display: grid;
  grid-template-columns: max-content 1fr;
  margin: 0.9rem 0 0;
  border-block-end: 1px solid var(--rule);
  font-size: 0.88rem;
  color: var(--muted);
}
.work-meta div {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: baseline;
  padding: 0.4rem 0;
  border-block-start: 1px solid var(--rule);
}
.work-meta dt {
  padding-inline-end: 1.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.work-meta dd { margin: 0; min-inline-size: 0; font-weight: 600; }
.work-cover {
  display: block;
  inline-size: 100%;
  block-size: auto;
  margin-top: 1rem;
  border-radius: 8px;
  background: var(--surface);
}

/* ── Videos (Markdown .mp4 images): looping, muted, a play/pause toggle ── */
.video { position: relative; display: block; }
.video video { display: block; inline-size: 100%; block-size: auto; border-radius: 8px; background: var(--surface); }
/* dark disc with a white ring: readable on any frame, light or dark */
.video-toggle {
  position: absolute;
  inset: auto 0.6rem 0.6rem auto;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border: 2px solid rgb(255 255 255 / 0.9);
  border-radius: 50%;
  padding: 0;
  background: rgb(0 0 0 / 0.65);
  cursor: pointer;
}
.video-toggle::before {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  inline-size: 0.9rem;
  block-size: 1rem;
  background: #fff;
  /* play: a triangle, nudged right to look centred */
  clip-path: polygon(15% 0, 100% 50%, 15% 100%);
}
.video-toggle[aria-pressed="true"]::before {
  /* pause: two bars */
  clip-path: polygon(0 0, 35% 0, 35% 100%, 0 100%, 0 0, 65% 0, 100% 0, 100% 100%, 65% 100%, 65% 0);
}
.video-toggle:focus-visible { outline: 3px solid var(--green-dark); outline-offset: 2px; }

/* ── Phones: two columns, the big tile and the CTA full width ── */
@media (max-width: 40rem) {
  .bento, .bento.four { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 8rem; }
  .tile.big { grid-column: span 2; grid-row: span 2; }
}
