/* Zen Maru Gothic, self-hosted and cut down to the characters this page
   uses (about 19 kB per weight instead of 3.8 MB). The site's security
   policy allows no third-party fonts. If you add a word to data.json,
   rerun scripts/subset_ramen_font.py or its new characters will show in
   a fallback font. Licence: fonts/ZenMaruGothic-OFL.txt */
@font-face {
  font-family: "Zen Maru Gothic";
  src: url("fonts/ZenMaruGothic-Medium-subset.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Zen Maru Gothic";
  src: url("fonts/ZenMaruGothic-Bold-subset.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Zen Maru Gothic";
  src: url("fonts/ZenMaruGothic-Black-subset.woff2") format("woff2");
  font-weight: 900;
  font-display: swap;
}

/* =========================================================
   1. DESIGN TOKENS
   Change colours and sizes here and they update everywhere.
   Colours are picked from the artwork: table brown, wall green,
   daruma red, and a warm paper colour for the word card.
   ========================================================= */
:root {
  --page-bg: #2b211b;          /* dark roasted brown around the scene */
  --page-text: #efe6d6;
  --page-text-soft: #b9ab96;

  --card-bg: #fbf5e9;          /* warm paper */
  --card-ink: #2a211b;
  --card-ink-soft: #6f6253;
  --card-rule: #e6dcc8;
  --accent: #c8402f;           /* daruma red */
  --accent-ink: #ffffff;

  --hover-glow: rgba(255, 236, 186, 0.95);
  --focus-glow: #ffd36b;

  --radius: 18px;
  --font: "Zen Maru Gothic", "Hiragino Maru Gothic ProN", "Yu Gothic", system-ui, sans-serif;
}


/* =========================================================
   2. PAGE BASICS
   ========================================================= */
*,
*::before,
*::after {
  box-sizing: border-box;
}

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

body {
  background: var(--page-bg);
  color: var(--page-text);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}

/* Centres the scene in the window, with a 16px gutter on small screens */
.page {
  min-height: 100vh;
  min-height: 100svh;          /* "small viewport height" ignores mobile browser bars */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 56px 16px 16px;     /* top room for the back link */
}

/* Small way home to the portfolio, top left */
.back-link {
  position: absolute;
  top: 16px;
  left: 16px;
  padding: 6px 12px;
  border-radius: 999px;
  color: var(--page-text-soft);
  font-size: 0.9rem;
  font-weight: 700;
  text-decoration: none;
  transition: color 0.15s ease, background 0.15s ease;
}
.back-link:hover,
.back-link:focus-visible {
  color: var(--page-text);
  background: rgba(255, 255, 255, 0.08);
}
.back-link:focus-visible {
  outline: 3px solid var(--focus-glow);
  outline-offset: 2px;
}

/* Hidden on screen but still read by screen readers */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* =========================================================
   3. THE SCENE (16:9 container + stacked layers)
   ========================================================= */
.scene {
  position: relative;          /* the layers position themselves against this box */
  aspect-ratio: 16 / 9;        /* always the same shape as the 1920x1080 canvas */

  /* As wide as possible, but never so wide that the 16:9 box gets taller
     than the window (minus room for the hint text underneath). */
  width: min(100%, calc((100svh - 120px) * 16 / 9));

  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);

  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none; /* stops the iOS "save image" menu on long press */
  touch-action: manipulation;  /* removes the double-tap-zoom delay on mobile */
}

/* Wraps the scene. The scene's layers are all absolutely positioned,
   so it has no width of its own: the stage must be full width or the
   scene's percentage width resolves to nothing and the table vanishes. */
.stage {
  width: 100%;
  display: flex;
  justify-content: center;
}

/* Phones held upright: a 16:9 table squeezed into a narrow screen
   leaves the small items (the negi, the chopstick rest) too small to
   tap. So the stage goes edge to edge and the scene is drawn wider
   than the screen. You swipe sideways to look around, and app.js
   starts you in the middle, on the bowl. */
@media (orientation: portrait) and (max-width: 700px) {
  .stage {
    width: 100vw;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;     /* the swipe hint replaces the scrollbar */
  }
  .stage::-webkit-scrollbar {
    display: none;
  }
  .stage {
    justify-content: flex-start; /* centring would clip the left edge out of reach */
  }
  .scene {
    flex: none;
    width: 170vw;              /* about 96vw tall, so roughly double the old size */
    border-radius: 0;
  }
}

/* app.js sets this class while it's working out which item is under the pointer */
.scene.is-pointing {
  cursor: pointer;
}

/* Every image fills the whole scene, so all 1920x1080 exports line up exactly */
.layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  transition: filter 0.25s ease, opacity 0.6s ease;
}

/* Gentle fade-in once everything has loaded */
.scene.is-loading .layer {
  opacity: 0;
}


/* =========================================================
   4. ITEM HIGHLIGHTS (hover, keyboard focus, active)
   A normal outline or box-shadow would draw a 1920x1080 rectangle,
   because each PNG is full-canvas. drop-shadow() is different: it
   follows the transparent PNG's real shape, so it outlines just the
   drawing. Stacking two gives a crisp edge plus a soft glow.
   ========================================================= */

/* .is-hovered is added by app.js (pixel-accurate, see app.js step 6) */
.layer--item.is-hovered {
  filter:
    drop-shadow(0 0 2px var(--hover-glow))
    drop-shadow(0 0 12px var(--hover-glow))
    brightness(1.06);
}

/* Keyboard users: Tab moves between items, this shows which one is selected */
.layer--item:focus {
  outline: none;               /* the default outline would be the full canvas */
}
.layer--item:focus-visible {
  filter:
    drop-shadow(0 0 2px var(--focus-glow))
    drop-shadow(0 0 3px var(--focus-glow))
    drop-shadow(0 0 14px var(--focus-glow));
}

/* The item whose card is currently open keeps glowing behind the backdrop */
.layer--item.is-active {
  filter:
    drop-shadow(0 0 3px var(--hover-glow))
    drop-shadow(0 0 18px var(--hover-glow))
    brightness(1.08);
}


/* =========================================================
   5. HINT / STATUS TEXT under the scene
   ========================================================= */
.hint {
  margin: 0;
  max-width: 60ch;
  text-align: center;
  font-size: clamp(0.85rem, 0.8rem + 0.3vw, 1rem);
  font-weight: 500;
  color: var(--page-text-soft);
}

.hint.is-error {
  color: #ffb4a6;
}


/* =========================================================
   6. WORD CARD (the <dialog> modal)
   ========================================================= */
.word-card {
  width: min(420px, calc(100% - 32px));
  max-height: calc(100svh - 32px);
  padding: 0;                  /* padding lives on .word-card__inner, see index.html */
  border: none;
  border-radius: var(--radius);
  background: var(--card-bg);
  color: var(--card-ink);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
  overflow: auto;
}

/* The dimmed layer behind an open dialog */
.word-card::backdrop {
  background: rgba(20, 14, 10, 0.55);
  backdrop-filter: blur(2px);
}

.word-card__inner {
  position: relative;
  padding: 28px 28px 30px;
  text-align: center;
}

/* --- Open / close animations ---
   [open] is added by the browser on showModal().
   .is-closing is added by app.js, which waits for the animation to finish
   before actually closing the dialog. */
.word-card[open] {
  animation: card-in 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.word-card[open]::backdrop {
  animation: fade-in 0.25s ease;
}
.word-card.is-closing {
  animation: card-out 0.2s ease-in forwards;
}
.word-card.is-closing::backdrop {
  animation: fade-out 0.2s ease-in forwards;
}

@keyframes card-in {
  from { opacity: 0; transform: translateY(24px) scale(0.94); }
  to   { opacity: 1; transform: none; }
}
@keyframes card-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(12px) scale(0.97); }
}
@keyframes fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }

/* --- Card contents --- */
.word-card__close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--card-ink-soft);
  cursor: pointer;
}
.word-card__close:hover {
  background: var(--card-rule);
  color: var(--card-ink);
}
.word-card__close svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
}

.word-card__english {
  margin: 0 0 6px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.word-card__kanji {
  margin: 0;
  font-size: clamp(3rem, 2.4rem + 4vw, 4.5rem);
  font-weight: 900;
  line-height: 1.15;
  overflow-wrap: anywhere;     /* long katakana words wrap instead of overflowing */
}

.word-card__reading {
  margin: 6px 0 18px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 14px;
  font-size: 1.15rem;
  font-weight: 500;
  color: var(--card-ink-soft);
}

/* A small dot between hiragana and romaji, only when both are showing */
#card-hiragana:not([hidden]) + #card-romaji::before {
  content: "·";
  margin-right: 14px;
}

.word-card__play {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  border: none;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.15s ease, filter 0.15s ease;
}
.word-card__play:hover {
  filter: brightness(1.08);
}
.word-card__play:active {
  transform: scale(0.96);
}
.word-card__play svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.word-card__play svg .fill {
  fill: currentColor;
}

/* Pulses while audio is playing (app.js toggles .is-playing) */
.word-card__play.is-playing svg {
  animation: pulse 0.8s ease-in-out infinite alternate;
}
@keyframes pulse {
  to { transform: scale(1.15); }
}

.word-card__explanation {
  margin: 20px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--card-rule);
  font-size: 1rem;
  line-height: 1.7;
  text-align: left;
  color: var(--card-ink);
}

/* Short screens (phones held sideways): tighten the card so it fits
   without scrolling */
@media (max-height: 500px) {
  .word-card__inner {
    padding: 16px 24px 18px;
  }
  .word-card__kanji {
    font-size: 2.6rem;
  }
  .word-card__reading {
    margin: 2px 0 10px;
  }
  .word-card__explanation {
    margin-top: 12px;
    padding-top: 10px;
    line-height: 1.55;
  }
}

/* Visible keyboard focus inside the card */
.word-card button:focus-visible {
  outline: 3px solid var(--focus-glow);
  outline-offset: 2px;
}


/* =========================================================
   7. REDUCED MOTION
   Some people get motion sickness from animations and turn them off
   in their OS settings. We keep durations tiny (not zero) so the
   "animationend" event that app.js waits for still fires.
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}
