/* kiyoshi.dev: a bento box. Night ground, coloured compartments, Zen Kaku Gothic. */
:root {
  --ground: #121016;
  --box: #221f29;
  --box-hover: #2a2633;
  --text: #efecf4;
  --muted: #9d97aa;
  --faint: #6e6879;
  --line: #4d4759;

  /* Japanese tones, one per compartment */
  --sakura: #e7849f;   --sakura-ink: #3b0c1b;
  --matcha: #8fb573;   --matcha-ink: #1d3010;
  --kin:    #e0b44f;   --kin-ink:    #3a2a03;
  --ai:     #3a4a7a;   --ai-ink:     #dfe5fb;
  --shu:    #e24b4a;

  /* Glass: what sits behind shows through, blurred. Tinted glass for the coloured compartments. */
  --glass: rgba(34, 31, 41, .52);
  --glass-hover: rgba(46, 42, 56, .6);
  --glass-edge: rgba(255, 255, 255, .09);
  --glass-light: rgba(255, 255, 255, .10);
  --r: 20px;
  --gap: 12px;
  --spring: linear(0, .009, .035 2.1%, .141 4.4%, .723 12.9%, .938 16.7%, 1.017 19.4%, 1.067, 1.099 24.9%, 1.108 26.6%, 1.1, 1.077 31.9%, 1.004 37.9%, .98 42%, .975 45.9%, .99 55.5%, 1.001 62.7%, 1.004 70%, 1);
  --font: "Zen Kaku Gothic New", -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }

/* The hover is two motions driven separately. Lift and scale spring (they overshoot and settle);
   tilt follows the pointer on a short, plain curve. One transition on `transform` would push every
   pointer move through the spring and make the tilt wobble behind the cursor, so each part is its
   own typed property with its own timing. */
@property --lift { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --sc   { syntax: "<number>"; inherits: false; initial-value: 1; }
@property --rx   { syntax: "<angle>";  inherits: false; initial-value: 0deg; }
@property --ry   { syntax: "<angle>";  inherits: false; initial-value: 0deg; }
html, body { margin: 0; }
#sky { position: fixed; inset: 0; width: 100vw; height: 100vh; z-index: 0; display: block; }
.bento, .foot { position: relative; z-index: 1; }
body {
  background: var(--ground);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.5;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Centred both ways: the box sits in the middle of the window, the footer below it. */
  justify-content: center;
  padding: 48px 20px 24px;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
/* `hidden` must win over any display a class sets, or hiding by attribute silently fails. */
[hidden] { display: none !important; }

/* ── The box ─────────────────────────────────────────────────────────────── */
.bento {
  width: 100%;
  max-width: 1040px;
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: 110px 150px 150px 72px;
  grid-template-areas:
    "profile listening listening live"
    "profile kodama    kodama    tsukumo"
    "profile kodama    kodama    soon"
    "profile contact   contact   clock";
}
.box {
  background: var(--glass);
  border: 0;
  /* The edge colours: light from the top left, the compartment's own tint at the bottom right. */
  --edge-a: rgba(255, 255, 255, .34);
  --edge-b: rgba(231, 132, 159, .30);
  box-shadow: inset 0 1px 0 var(--glass-light);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  backdrop-filter: blur(18px) saturate(1.3);
  border-radius: var(--r);
  padding: 18px 20px;
  overflow: hidden;
  position: relative;
  transition: background-color .18s ease;
}
a.box {
  transform: perspective(900px) translateY(var(--lift)) scale(var(--sc)) rotateX(var(--rx)) rotateY(var(--ry));
  transition: --lift .6s var(--spring), --sc .6s var(--spring),
              --rx .22s ease-out, --ry .22s ease-out, background-color .18s ease;
  will-change: transform;
}
a.box:hover { --lift: -6px; --sc: 1.025; }
a.box:active { --lift: -2px; --sc: .975; transition-duration: .12s, .12s, .22s, .22s, .18s; }

/* A gradient outline. CSS borders cannot take a gradient and keep rounded corners, so the edge is
   a layer of its own: a gradient the size of the box, with everything but a 1px ring masked away. */
.box::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none;
  background: linear-gradient(135deg, var(--edge-a), rgba(255, 255, 255, .05) 42%, rgba(255, 255, 255, .03) 60%, var(--edge-b));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}

/* Light that follows the pointer across the glass. */
a.box::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, .16), transparent 62%);
  opacity: 0; transition: opacity .3s ease;
}
a.box:hover::after { opacity: 1; }

.kicker { font-size: 12px; color: var(--muted); letter-spacing: .02em; display: flex; align-items: center; gap: 7px; }

/* ── Profile ─────────────────────────────────────────────────────────────── */
.profile {
  grid-area: profile;
  background: rgba(231, 132, 159, .82);
  color: var(--sakura-ink);
  --edge-a: rgba(255, 230, 238, .75);
  --edge-b: rgba(255, 255, 255, .20);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 24px;
}
.avatar { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; border: 3px solid rgba(59, 12, 27, .18); }
.profile h1 { font-size: 26px; font-weight: 700; line-height: 1.15; margin: 0 0 6px; }
.tagline { margin: 0 0 20px; font-size: 14px; }
.socials { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.socials a { font-size: 14px; font-weight: 500; border-bottom: 1.5px solid rgba(59, 12, 27, .25); padding-bottom: 1px; }
.socials a:hover { border-color: var(--sakura-ink); }

/* ── Now listening ───────────────────────────────────────────────────────── */
.listening { grid-area: listening; display: flex; align-items: center; gap: 16px; }
.listening:hover { background: var(--glass-hover); }
.cover {
  width: 72px; height: 72px; flex-shrink: 0; border-radius: 12px;
  background: #34303d center / cover no-repeat;
}
.cover.is-silent { background: #2c2835; display: flex; align-items: center; justify-content: center; }
.kao { font-size: 13px; color: var(--muted); white-space: nowrap; letter-spacing: -.02em; }
.cover:not(.is-silent) .kao { display: none; }
.listening-body { display: flex; flex-direction: column; min-width: 0; }
.track { font-size: 16px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
.artist { font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── Live ────────────────────────────────────────────────────────────────── */
.live { grid-area: live; background: rgba(78, 98, 160, .26); --edge-b: rgba(150, 170, 235, .55); color: var(--ai-ink); display: flex; flex-direction: column; justify-content: space-between; }
.live .kicker { color: var(--ai-ink); font-weight: 500; font-size: 13px; }
.dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(223, 229, 251, .35); flex-shrink: 0; }
.live.is-live .dot { background: var(--shu); box-shadow: 0 0 0 0 rgba(226, 75, 74, .6); animation: pulse 1.8s infinite; }
.live-game { font-size: 12.5px; opacity: .8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@keyframes pulse { 70% { box-shadow: 0 0 0 8px rgba(226, 75, 74, 0); } 100% { box-shadow: 0 0 0 0 rgba(226, 75, 74, 0); } }

/* ── Projects ────────────────────────────────────────────────────────────── */
.project { display: flex; flex-direction: column; }
.project-name { font-size: 17px; font-weight: 700; }
.project-sub { font-size: 12.5px; opacity: .8; margin-top: 2px; }

.kodama { grid-area: kodama; padding-bottom: 0; }
.kodama:hover { background: var(--glass-hover); }
.project-head { display: flex; align-items: center; justify-content: space-between; }
.project-logo { height: 20px; width: auto; }
.project-desc { font-size: 13.5px; color: var(--muted); margin: 10px 0 14px; max-width: 420px; }
.shot {
  display: block; width: 100%; margin-top: auto;
  border-radius: 12px 12px 0 0; border: 1px solid #34303d; border-bottom: 0;
  object-fit: cover; object-position: top; height: 150px;
}
.badge { font-size: 11px; font-weight: 500; padding: 3px 10px; border-radius: 99px; }
.badge-alpha { background: #34502a; color: #cfe9bf; }

/* Coming soon: dashed and quiet. The look is shared; where each sits in the grid is its own. */
.tsukumo { grid-area: tsukumo; }
.remote { grid-area: soon; }
.soon {
  background: rgba(18, 16, 22, .25); border: 1.5px dashed var(--line); color: var(--muted); box-shadow: none;
  justify-content: flex-end;
}
.soon::before { display: none; }   /* keeps its dashes, no gradient edge */
.soon .project-name { color: var(--text); opacity: .75; }

/* ── Playful text links: letters hop one after another, a kaomoji pops out ── */
.fun { display: inline-block; }
.fun .ch { display: inline-block; }
.fun:hover .ch { animation: hop .5s cubic-bezier(.3, 1.6, .5, 1) both; animation-delay: calc(var(--i) * 32ms); }
@keyframes hop { 0% { transform: translateY(0); } 40% { transform: translateY(-5px); } 100% { transform: translateY(0); } }

/* The kaomoji is not placed at the link but at a fixed, empty spot of its compartment: the link
   itself is not positioned, so the pseudo-element anchors to the .box around it. Every link of a
   compartment shows its face in the same place, large enough to read. */
.fun::after {
  content: attr(data-kao);
  position: absolute; right: 24px; bottom: 22px;
  transform: scale(.3) rotate(-18deg); transform-origin: 80% 80%;
  opacity: 0; pointer-events: none; white-space: nowrap;
  font-size: 30px; font-weight: 500; line-height: 1; letter-spacing: -.02em;
  transition: transform .42s cubic-bezier(.3, 1.7, .5, 1), opacity .2s ease;
}
.fun:hover::after { transform: scale(1) rotate(0); opacity: 1; }
.contact .fun::after { right: 22px; bottom: auto; top: calc(50% - 12px); font-size: 24px; color: var(--sakura); transform-origin: center; }

/* ── Contact ─────────────────────────────────────────────────────────────── */
.contact { grid-area: contact; display: flex; align-items: center; gap: 22px; font-size: 14px; color: var(--muted); }
.contact a:hover { color: var(--text); }

/* ── Clock ───────────────────────────────────────────────────────────────── */
.clock { grid-area: clock; display: flex; align-items: center; gap: 12px; padding: 12px 16px; }
.clock-face { width: 40px; height: 40px; flex-shrink: 0; }
.clock-face .ring { fill: rgba(255, 255, 255, .04); stroke: rgba(255, 255, 255, .22); stroke-width: 1; }
.clock-face .hand { stroke: var(--text); stroke-linecap: round; transform-origin: 20px 20px; }
.clock-face .hour { stroke-width: 2.4; }
.clock-face .minute { stroke-width: 1.6; opacity: .8; }
.clock-face .pin { fill: var(--sakura); }
.clock-body { display: flex; flex-direction: column; line-height: 1.2; }
.clock-time { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.clock-zone { font-size: 12px; color: var(--muted); }

.foot { color: rgba(239, 236, 244, .45); font-size: 12px; margin-top: 28px; display: flex; align-items: center; gap: 14px; }

/* ── Zero gravity ─────────────────────────────────────────────────────────── */
.float-btn {
  font: inherit; font-size: 12px; color: rgba(239, 236, 244, .7); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 11px 4px 9px; border-radius: 99px;
  background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .12);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  transition: background-color .18s ease, color .18s ease, transform .4s var(--spring);
}
.float-btn:hover { background: rgba(255, 255, 255, .11); color: var(--text); transform: translateY(-2px); }
.float-btn:active { transform: scale(.94); }
.float-btn:focus-visible { outline: 2px solid var(--sakura); outline-offset: 2px; }
.float-ico { color: var(--sakura); display: inline-block; transition: transform .6s var(--spring); }
.float-btn[aria-pressed="true"] .float-ico { transform: rotate(180deg) scale(1.2); }

/* While floating, each compartment carries its own offset and turn, and nothing else: the hover lift,
   zoom and tilt would make it look bigger than the shape the physics bounces, and it would seem to
   sink into its neighbours. */
html.floating { overflow: hidden; }
.floating .bento { touch-action: none; user-select: none; -webkit-user-select: none; }
.floating .box, .floating a.box { transform: translate(var(--fx, 0px), var(--fy, 0px)) rotate(var(--fr, 0deg)); cursor: grab; }
.floating .box.grabbed { cursor: grabbing; z-index: 5; }
.floating img { -webkit-user-drag: none; }
/* Back into the grid: one springy flight home. */
.settling .box { transition: transform .95s var(--spring) !important; }

/* ── Narrow screens: the profile column becomes a strip across the top ───── */
@media (max-width: 760px) {
  body { padding: 20px 14px; }
  .bento {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto 96px 80px 260px 110px auto;
    grid-template-areas:
      "profile   profile"
      "listening listening"
      "live      clock"
      "kodama    kodama"
      "tsukumo   soon"
      "contact   contact";
  }
  .profile { flex-direction: row; align-items: center; gap: 16px; justify-content: flex-start; padding: 18px; }
  .avatar { width: 60px; height: 60px; }
  .tagline { margin-bottom: 10px; }
  .socials { flex-direction: row; flex-wrap: wrap; gap: 4px 14px; }
  .contact { flex-wrap: wrap; gap: 8px 18px; }
  /* No free spot is left in the strip or the wrapped contact row, and touch has no hover anyway:
     the letters still hop, the face stays away. */
  .fun::after { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  a.box, .box { transition: none; }
  a.box, a.box:hover, a.box:active { transform: none; }
  .live.is-live .dot { animation: none; }
  .fun:hover .ch { animation: none; }
  .fun::after { transition: opacity .2s ease; transform: none; }
  .float-btn { display: none; }
}
