/* ═══════════════════════════════════════════
   FONT
═══════════════════════════════════════════ */
@font-face {
  font-family: 'YMFont';
  src: url('../fonts/YMFont_3v1-Rg.otf') format('opentype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* ═══════════════════════════════════════════
   RESET & BASE
═══════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
  width: 100%; height: 100%;
  overflow: hidden;
  background: #fff;
  font-family: 'YMFont', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* Buttons / inputs don't inherit font-family by default — force them to. */
button, input, select, textarea { font-family: inherit; }

/* ═══════════════════════════════════════════
   VIEWPORT & CANVAS
═══════════════════════════════════════════ */
#viewport {
  width: 100%; height: 100vh;
  overflow: hidden; position: relative;
  cursor: grab;
  user-select: none; -webkit-user-select: none;
}
#viewport.dragging { cursor: grabbing; }

#world {
  position: absolute; top: 0; left: 0;
  transform-origin: 0 0;
  /* will-change is set DYNAMICALLY (JS bumpWillChange) only during active
     pan/zoom — leaving it on permanently pins the layer texture at a low
     resolution, so zoomed-in tiles stay blurry until something forces a
     repaint. Clearing it lets the browser re-rasterise at the new scale
     once motion settles. */
}
/* Ghost world copies — visual-only side panels for map east-west loop */
.world-ghost {
  position: absolute; top: 0; left: 0;
  transform-origin: 0 0;
  display: none;
}

/* ═══════════════════════════════════════════
   ZONE AREAS
═══════════════════════════════════════════ */
.zone {
  position: absolute;
  border-radius: 4px;
  transition: opacity 0.25s;
}
.zone.hidden { opacity: 0; pointer-events: none; }
.zone-bg {
  position: absolute; inset: 0;
  border-radius: 4px;
}
.zone-label {
  position: absolute;
  top: -26px; left: 0;
  font-size: 13px; font-weight: 700;
  letter-spacing: 0.06em;
  white-space: nowrap; pointer-events: none;
  opacity: 0.92;
}

/* Map view: region dots and photo tiles are BOTH pre-built in the DOM;
   crossing the zoom threshold just toggles which set is shown (no rebuild,
   no load hitch). Scoped to map mode so Field-view tiles are unaffected. */
body.mode-map:not(.mapview-photos) .tile    { display: none !important; }
body.mode-map.mapview-photos      .cmap-dot { display: none !important; }

/* ═══════════════════════════════════════════
   PHOTO TILES  — 3 sizes
═══════════════════════════════════════════ */
.tile {
  position: absolute;
  border-radius: 2px;
  border: none;
  box-shadow: 0 2px 6px rgba(0,0,0,0.22);
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow 0.14s, transform 0.14s, opacity 0.25s;
  /* NO permanent will-change: a persistent compositing hint pins each tile on
     its own GPU layer at a FIXED raster resolution, so when #world is scaled
     up the tile (and the disc behind it) becomes an upscaled bitmap that never
     re-rasterises → blurry on zoom (worst on mobile, smaller texture caps).
     will-change is applied DYNAMICALLY during motion only (bumpWillChange),
     then cleared so the browser repaints crisply at the new scale. */
}
.tile:hover {
  box-shadow: 0 6px 22px rgba(0,0,0,0.38);
  transform: scale(1.07);
  z-index: 9000 !important;
}
.tile.hidden { opacity: 0; pointer-events: none; }

/* Tile interior */
.tile-inner {
  width: 100%; height: 100%;
  position: relative;
  display: flex; align-items: center; justify-content: center;
}
.tile-img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  position: absolute; inset: 0;
}
.tile-placeholder {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; opacity: 0.5;
}
.tile-affil {
  /* Some browsers (commonly Chrome on macOS with a user-set "minimum font
     size") clamp sub-pixel font-sizes, making the caption strip render
     way too tall. We side-step that by using a normal font-size (7px,
     not clamped) and shrinking the whole element 5× with transform —
     the visual size matches the intended ~1.4px on every platform. The
     character count that fits a tile is font-size ÷ (500% box width), so a
     smaller font-size shows MORE of the name (was 10px → only ~1 char on
     narrow tiles). Tight horizontal padding gives the text more room too. */
  position: absolute; bottom: 0; left: 0;
  width: 500%;
  transform: scale(0.20);
  transform-origin: bottom left;
  /* Strip height ≈10px, grown UPWARD only (top padding, bottom padding 0) so
     the text sits flush on the photo's bottom edge. font-size unchanged. */
  padding: 2px 6px 0;
  line-height: 1.15;
  font-size: 7px; color: #fff; font-weight: 400;
  background: rgba(0,0,0,0.62);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  letter-spacing: 0.005em;
  z-index: 4;
  pointer-events: none;
  display: none;                /* hidden until zoomed in (world.affil-visible) */
}
#world.affil-visible .tile-affil { display: block; }

/* ═══════════════════════════════════════════
   HUD — top left: KANDO Snap logo + stats
═══════════════════════════════════════════ */
#hud {
  position: fixed; top: 22px; left: 28px; z-index: 500;
  pointer-events: none;
  display: flex; flex-direction: column; gap: 6px;
}
/* Logo is clickable — replays the opening movie (was the OPENING button). */
#hud-logo { display: block; height: 40px; width: auto; cursor: pointer; pointer-events: auto; }
#hud-logo-fallback {
  font-size: 24px; font-weight: 900; letter-spacing: -0.03em;
  line-height: 1; cursor: pointer; pointer-events: auto;
}
#hud-logo-fallback .kando { color: #1a2f6e; }
#hud-logo-fallback .snap  { color: #29b5e8; }
/* Stats on a single line. */
#hud-stats {
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: baseline;
  column-gap: 8px; row-gap: 0;
}

/* NEW button — same pill design as the old OPENING button. Opens the
   latest-batch photo grid. PC: taken out of the HUD column flow (position:
   absolute) and placed to the RIGHT of the logo+stats block, bottom edge level
   with the Archive line. Out of flow → the logo↔Archive gap stays the original
   6px instead of being stretched by this tall button. */
#new-btn {
  display: inline-block;   /* 既定は表示。JS(syncBtn)がnew写真の有無で none/'' に切替 */
  position: absolute; left: calc(100% + 15px); bottom: 0;
  padding: 16px 16px;
  background: rgba(80, 80, 80, 0.55); color: #fff;
  border: none; border-radius: 50px;
  font-family: inherit;
  font-size: 16px; font-weight: 400; letter-spacing: 0.06em;
  cursor: pointer; pointer-events: auto;
  transition: background 0.15s, transform 0.1s;
}
#new-btn:hover { background: rgba(60, 60, 60, 0.75); transform: translateY(-1px); }
/* font-size uses !important to survive the Yamaha shared CSS, which
   sets a larger font-size directly on inline elements like <b>. Without
   the !important the numbers (2026 / snap total / company count) render
   noticeably larger than the surrounding label. */
.hud-archive,
.hud-count {
  font-size: 12px !important; font-weight: 400; color: #555;
  letter-spacing: 0.02em;
  line-height: 1.3 !important;
}
/* Numbers only — bolder + darker. Same !important font-size so the
   shared CSS can't bump them above the label. */
.hud-archive b,
.hud-count b {
  font-size: 12px !important;
  font-weight: 800; color: #111;
}

/* ═══════════════════════════════════════════
   EVENT LOGO — top right: Yamaha Day
═══════════════════════════════════════════ */
#event-logo {
  position: fixed; top: 22px; right: 28px; z-index: 500;
  pointer-events: none;
  display: flex; align-items: center;
}
#event-logo img { height: 36px; width: auto; }
/* Full-width white band across the very top — single "zabuton" behind the
   KANDO Snap logo+Archive (left) and the Yamaha Day logo (right). Spans the
   screen top down to ~the logos' bottom. The 71st badge (#archive-badge,
   z-index 450) and the logos (z-index 500) sit IN FRONT of it (band z 440). */
#top-band {
  position: fixed; top: 0; left: 0; width: 100vw; height: 94px;
  /* solid white, no bottom fade; 透明度を少し下げる=より不透明に(0.4→0.5) */
  background: rgba(255, 255, 255, 0.5);
  z-index: 440; pointer-events: none;
}

/* ═══════════════════════════════════════════
   ARCHIVE BADGE — top centre: "71st" mark
═══════════════════════════════════════════ */
#archive-badge {
  position: fixed; top: 0; left: 50%; transform: translateX(-50%);
  z-index: 450; pointer-events: none;
  width: 244px;
}
#archive-badge img { display: block; width: 100%; height: auto; }
/* PC: show full SVG (text + dome). SP overrides below in @media. */
#archive-badge .badge-sp { display: none; }

/* ═══════════════════════════════════════════
   ZOOM CONTROLS — bottom left
═══════════════════════════════════════════ */
#zoombar {
  position: fixed; bottom: 24px; left: 28px; z-index: 500;
  display: flex; flex-direction: column; gap: 5px;
}
.z-btn {
  position: relative;
  width: 26px; height: 26px;            /* matches the SVG viewBox (25.57) */
  border: none; background: transparent; padding: 0;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.12s;
}
.z-btn img {
  width: 100%; height: 100%; display: block; pointer-events: none;
}
.z-btn:hover { opacity: 0.78; }

/* ── Advertising-guideline notices (small grey footer text) ────────── */
.gl-note { font-size: 6px; line-height: 1.5; color: #8a8a8a; letter-spacing: 0.01em; }
/* PC: a text box filling the gap BETWEEN the zoom +/- buttons (left) and the
   centred View bar (right). left+right anchoring → width shrinks as the window
   narrows, so the text re-wraps to more lines automatically. */
#gl-pc {
  position: fixed; left: 66px; right: calc(50% + 225px); bottom: 24px; z-index: 500;
  text-align: left; font-size: 8px;   /* PC: 8px (small enough to wrap to 3 lines beside the zoom buttons) */
}
#gl-sp { display: none; }   /* the SP copy lives in #layoutbar; hidden on PC */
/* Per-photo modal notice — only shown for flagged photos (JS toggles display);
   centred + small, below the page-nav buttons. */
#mnotice {
  display: none;
  text-align: center; font-size: 10px; line-height: 1.45; color: #9a9a9a;
  max-width: 88%; margin: 10px auto 0; padding: 0 10px;
}
/* Attention ripple — red ring pulse on the zoom controls, played a few
   times when the Map view is opened. */
.z-btn::after {
  content: ''; position: absolute; inset: -3px;
  border-radius: 50%;
  border: 2.5px solid #e50000;
  opacity: 0; pointer-events: none;
}
#zoombar.attention .z-btn::after {
  animation: zBtnRipple 1.2s ease-out 3;
}
@keyframes zBtnRipple {
  0%   { transform: scale(0.82); opacity: 0;    }
  18%  { opacity: 0.9;  }
  100% { transform: scale(2.0);  opacity: 0;    }
}

/* ═══════════════════════════════════════════
   CATEGORY LEGEND — bottom right
═══════════════════════════════════════════ */
/* font-size uses !important to survive the Yamaha shared CSS, which sets
   font-size directly on descendant block/inline elements and otherwise
   overrides the inherited 9px. */
#cat-legend {
  position: fixed; bottom: 22px; right: 10px; z-index: 500;
  pointer-events: none;
  display: grid; grid-template-columns: auto auto; gap: 1px 16px;
  font-size: 9px !important; color: #c8c8c8; line-height: 1.3 !important;
  letter-spacing: 0.01em;
}
#cat-legend .clg-cat {
  font-size: 9px !important; line-height: 1.3 !important;
  color: #c8c8c8; font-weight: 400; white-space: nowrap;
}
#cat-legend .clg-cat b {
  font-size: 9px !important;
  color: #c8c8c8; font-weight: 400; margin-right: 3px;
}

/* ═══════════════════════════════════════════
   POST BUTTON — bottom-right, above the legend. Opens the submission
   form in a new tab.
═══════════════════════════════════════════ */
#post-btn {
  position: fixed; right: 50px; bottom: 110px; z-index: 500;
  width: 163px; height: 163px;   /* 130 × 1.25 */
  display: block; cursor: pointer;
  transition: transform 0.12s, filter 0.12s;
}
#post-btn img { width: 100%; height: 100%; display: block; animation: post-float 2.8s ease-in-out infinite; }
#post-btn .post-sp { display: none; }   /* PC uses post_pc.svg; SP swaps to post.svg below */
#post-btn:hover { transform: translateY(-2px); filter: drop-shadow(0 4px 10px rgba(0,0,0,0.25)); }
/* Gentle up/down bob. Applied to the inner image so the button's own
   hover translate doesn't clash. */
@keyframes post-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
@media (prefers-reduced-motion: reduce) { #post-btn img { animation: none; } }
/* Post position is unified per device: PC = bottom-right (this base rule, all
   layouts); SP = top-right (see the SP media query). */

/* ═══════════════════════════════════════════
   MODAL
═══════════════════════════════════════════ */
#overlay {
  position: fixed; inset: 0; z-index: 2000;
  background: rgba(0,0,0,0.78);
  display: none; align-items: center; justify-content: center;
  padding: 16px;
}
#overlay.open { display: flex; }
#mbox {
  background: #fff; border-radius: 12px;
  /* Width: 740px floor (1366 base), grows with viewport (54vw), 1080px cap.
     Height ceiling rises proportionally on taller windows. */
  width: min(1080px, max(740px, 54vw));
  max-height: min(840px, 92vh);
  position: relative; overflow-y: auto;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 60px rgba(0,0,0,0.4);
  padding-bottom: 22px;
}
#mhead {
  display: flex; align-items: flex-start; justify-content: space-between;
  flex-shrink: 0;
}
#mcat {
  padding: 7px 80px 8px 24px;       /* longer horizontally */
  font-size: 13px; font-weight: 400; color: #fff;
  letter-spacing: 0.02em;
  white-space: nowrap;
  min-width: 240px;                  /* keep the tag wide regardless of label */
  /* Top-right corner clipped at 45° to match the field selector tabs. */
  clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 14px, 100% 100%, 0 100%);
  border-radius: 0;                  /* corners are flat now */
}
#mclose {
  width: 30px; height: 30px; margin: 5px 8px 0 0; flex-shrink: 0;
  border: none; background: transparent; color: #666;
  font-size: 18px; cursor: pointer; line-height: 1;
}
#mclose:hover { color: #000; }
#mimg-area {
  width: 100%; aspect-ratio: 16 / 10;
  max-height: min(640px, 64vh);
  flex-shrink: 0; overflow: hidden;
  background: #ddd;
  display: flex; align-items: center; justify-content: center;
  position: relative;   /* anchor the loading spinner */
}
#mimg-area img {
  width: 100%; height: 100%; object-fit: contain; display: block;
  margin: 0 auto;
}
/* Loading spinner shown over the modal photo until its full-res arrives. */
.mimg-spinner {
  position: absolute; top: 50%; left: 50%;
  width: 46px; height: 46px; margin: -23px 0 0 -23px;
  border: 4px solid rgba(255,255,255,0.55);
  border-top-color: rgba(0,0,0,0.45);
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
  animation: mimg-spin 0.8s linear infinite;
  pointer-events: none; z-index: 2;
}
@keyframes mimg-spin { to { transform: rotate(360deg); } }
#mimg-placeholder {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  font-size: 64px;
}
#mbody { padding: 16px 52px 6px; }
#mdesc {
  font-size: 13px; color: #444; line-height: 1.75;
  margin-bottom: 14px; text-align: left;
  white-space: pre-wrap;
}
#mphotographer {
  font-size: 13px; font-weight: 700; color: #222;
  text-align: center;
}
#maffiliation {
  font-size: 11px; color: #888; text-align: center; margin-top: 2px;
}
/* Grey round nav button — the circular sibling of the View buttons (same
   grey, white glyph, low-shift shadow). Shared size with the Book page-nav. */
.mnav-arrow {
  position: absolute; bottom: 18px;
  width: 44px; height: 44px; padding: 0; border-radius: 50%;
  border: none; background: #9a9a9a; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 4px rgba(0,0,0,0.30);
  transition: background 0.15s, transform 0.1s;
}
.mnav-arrow:hover:not(:disabled) { background: #7c7c7c; }
.mnav-arrow img { width: 12px; height: auto; display: block; filter: brightness(0) invert(1); }
#mPrev { left: 14px; }
#mNext { right: 14px; }
#mNext img { transform: scaleX(-1); }
.mnav-arrow:disabled { opacity: 0.22; cursor: default; }

/* ═══════════════════════════════════════════
   LOADING SCREEN
═══════════════════════════════════════════ */
#loading {
  position: fixed; inset: 0; z-index: 9999;
  background: #fff;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 16px;
}
#loading .ld-title { font-size: 20px; font-weight: 800; color: #222; letter-spacing: -0.02em; }
#loading .ld-sub { font-size: 12px; color: #aaa; letter-spacing: 0.06em; }
#loading.done { display: none; }

/* ═══════════════════════════════════════════
   INTRO — photos-forming-"71st" video (once per session)
═══════════════════════════════════════════ */
#intro {
  position: fixed; inset: 0; z-index: 10000;
  background: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.6s ease;
}
#intro.hide { opacity: 0; pointer-events: none; }
/* Intro clip sits inside the window with a margin — ~1280px wide on a
   1366px window. 16:9, contained within both viewport dimensions. */
#intro-video {
  width: auto; height: auto;
  max-width: 94vw; max-height: 94vh;
  display: block;
}
#intro-fallback { display: none; flex-direction: column; align-items: center; }
#intro-fallback img {
  width: min(78vw, 900px); height: auto;
  opacity: 0;
  animation: introFadeIn 1.4s ease-out 0.15s forwards;
}
#intro.no-video #intro-video { display: none; }
#intro.no-video #intro-fallback { display: flex; }
@keyframes introFadeIn {
  from { opacity: 0; transform: scale(0.985); }
  to   { opacity: 1; transform: scale(1); }
}
/* Intro controls — icon-only, top-right under the Yamaha Day logo. */
#intro-skip,
#intro-sound {
  position: fixed; top: 80px;
  background: transparent; border: none; padding: 0;
  cursor: pointer; transition: opacity 0.15s, transform 0.1s;
  opacity: 0.85;
}
/* Skip is a wide pill (viewBox 106.8 × 43.47), Sound is a square (43.47²). */
#intro-skip  { right: 28px;  width: 80px; height: 32px; }
#intro-sound { right: 114px; width: 32px; height: 32px; }  /* 6px gap before skip */
/* SP: shift both right so the skip pill aligns with the OPENING button
   (which sits at right: 14px on SP). */
@media (max-width: 768px) {
  #intro-skip  { right: 14px; }
  #intro-sound { right: 100px; }   /* 14 + 80 + 6 = 100 */
}
#intro-skip img,
#intro-sound img {
  width: 100%; height: 100%; display: block; pointer-events: none;
}
#intro-skip:hover,
#intro-sound:hover { opacity: 1; transform: translateY(-1px); }
#intro.no-video #intro-sound { display: none; }

/* Click-for-sound prompt: shown ONLY when the browser blocked autoplay
   with sound and the clip fell back to muted. Clicking anywhere on the
   intro unmutes (a user gesture, always permitted). */
#intro {
  cursor: default;
}
#intro.needs-sound {
  cursor: pointer;
}
#intro-tap {
  /* Lower portion of the viewport (top: 82%) so it sits clear of the
     centred intro video. Hidden by default — fades in/out on a class.
     Only the pill itself is clickable (it's the actual unmute control;
     clicks elsewhere on the intro overlay do nothing). */
  display: flex; align-items: center;
  position: fixed; left: 50%; top: 82%;
  transform: translate(-50%, -50%);
  padding: 14px 28px; border-radius: 60px;
  background: rgba(0, 0, 0, 0.72); color: #fff;
  font-size: 18px; font-weight: 400; letter-spacing: 0.04em;
  font-family: inherit;
  border: none; outline: none; cursor: pointer;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s ease;
}
#intro.needs-sound #intro-tap { pointer-events: auto; }
#intro-tap:hover { background: rgba(0, 0, 0, 0.88); }
#intro-tap img {
  width: 22px; height: 22px; vertical-align: middle;
  margin-right: 10px;
}
#intro-tap span { vertical-align: middle; }
/* SP: shrink the pill — PC's 18px font + 14×28 padding is oversized
   on a phone. */
@media (max-width: 768px) {
  #intro-tap {
    padding: 9px 16px;
    font-size: 12px;
    border-radius: 40px;
  }
  #intro-tap img {
    width: 15px; height: 15px; margin-right: 6px;
  }
}
#intro.needs-sound #intro-tap {
  opacity: 1;
  animation: introTapPulse 1.4s ease-in-out infinite;
}
@keyframes introTapPulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1);    }
  50%      { transform: translate(-50%, -50%) scale(1.06); }
}

/* Mouse-wheel operation guide — shown briefly in the centre while the
   Field / Map zoom-out hint plays, fades out after a few seconds. */
#wheel-guide {
  position: fixed; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 600;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s ease;
}
#wheel-guide img {
  width: auto; height: 200px; display: block;
}
#wheel-guide.show { opacity: 1; }

/* While the intro overlay is showing, lift the two top-corner logos above
   it so the login screen matches the reference (logos + mosaic, no stats
   and no centre 71st badge — the badge is part of the video itself). */
body.intro-active #hud         { z-index: 10100; }
body.intro-active #event-logo  { z-index: 10100; }
body.intro-active #hud-stats,
body.intro-active #archive-badge,
body.intro-active #new-btn,
body.intro-active #post-btn { display: none; }

/* ═══════════════════════════════════════════
   NEW GRID — latest-batch photos over a dark backdrop
═══════════════════════════════════════════ */
#new-grid {
  position: fixed; inset: 0; z-index: 1500;
  background: rgba(0, 0, 0, 0.82);
  display: flex;
  align-items: center; justify-content: center;
  /* Fade in/out at the same speed as the view-switch fade (0.27s). */
  opacity: 0; visibility: hidden;
  transition: opacity 0.27s ease, visibility 0s linear 0.27s;
}
#new-grid.open { opacity: 1; visibility: visible; transition: opacity 0.27s ease; }
/* Scroll wrapper: lets the grid scroll when it's taller than the screen,
   while staying vertically centred when it fits. */
#new-grid-scroll {
  max-height: 100%; width: 100%;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  display: flex;
  padding: 56px 16px;
  box-sizing: border-box;
}
/* margin:auto centres the block when it fits and stays scrollable (no top
   clipping) when it's taller than the viewport. */
#new-grid-inner {
  display: flex; flex-direction: column;
  gap: 30px;
  width: 100%; max-width: 1200px; margin: auto;
}
/* One date group: a date header + its photo row. */
.ng-group { display: flex; flex-direction: column; gap: 8px; }
.ng-date {
  color: #fff; font-weight: 700; font-size: 15px; letter-spacing: 0.02em;
}
.ng-row { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-start; }
.ng-cell {
  width: 116px; height: 116px;
  border-radius: 4px; overflow: hidden;
  cursor: pointer; background: #222;
  flex: 0 0 auto;
  transition: transform 0.12s;
}
.ng-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ng-cell:hover { transform: scale(1.05); }
#new-grid-close {
  /* right = 16px gap + ~15px scrollbar so the visual gap to the scrolled
     content matches the 16px top gap (the grid scrollbar sits at the edge). */
  position: fixed; top: 16px; right: 31px; z-index: 1; /* above the grid scroll */
  width: 40px; height: 40px;
  background: rgba(110,110,110,0.95); color: #fff;
  border: none; border-radius: 50%;
  font-size: 20px; line-height: 1; cursor: pointer;
  transition: background 0.15s;
}
#new-grid-close:hover { background: rgba(140,140,140,0.95); }

/* ═══════════════════════════════════════════
   LAYOUT SWITCHER — bottom center
═══════════════════════════════════════════ */
#layoutbar {
  position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%);
  z-index: 500;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
}
#layoutbar-label {
  font-size: 16px; font-weight: 400; color: #333;
  letter-spacing: 0.02em;
  position: relative; top: 2px; margin-top: 4px;   /* PC: nudge View down 2px + 4px breathing room above */
}
.layoutbar-btns { display: flex; align-items: center; gap: 12px; }
.layout-btn {
  /* Fixed width so labels of different lengths (Field / Company / Book)
     all render at the same size. */
  width: 130px; padding: 16px 0; border-radius: 50px; border: none;
  background: #9a9a9a; color: #fff;
  font-size: 16px; font-weight: 400; cursor: pointer;
  transition: background 0.15s, transform 0.1s;
  white-space: nowrap; letter-spacing: 0.01em;
  text-align: center;
  /* Low-shift drop shadow so the pill edge stays defined against light/photo
     backdrops (it was melting into the page). */
  box-shadow: 0 1px 4px rgba(0,0,0,0.30);
}
.layout-btn:hover { background: #7c7c7c; transform: translateY(-1px); }
.layout-btn.active { background: #29b5e8; color: #fff; }  /* Sky blue from AI design */

/* View-switch fade — white overlay flashed during a view change.
   ~8 frames in + 8 frames out at 30fps (≈0.27s each).
   z-index 100: above the content (world / book-view) but BELOW the
   persistent UI chrome (z-index 450-500) so the HUD, logos, 71st badge,
   zoom bar and View bar stay visible through the fade. */
#view-fade {
  position: fixed; inset: 0; z-index: 100;
  background: #fff; opacity: 0;
  pointer-events: none;
  transition: opacity 0.27s ease;
}
#view-fade.show { opacity: 1; }

/* ── Field view circles ── */
.field-circle {
  position: absolute;
  border-radius: 50%;
  overflow: visible;   /* NO circle mask — photos inscribe inside with a small margin */
  cursor: default;
  box-shadow: 0 4px 24px rgba(0,0,0,0.18);
  transition: opacity 0.28s ease;
}
/* Focus mode: only the focused circle builds live tiles (workload bounded to
   one circle); the others just keep their bake at full opacity — no dimming
   (the JS marks non-focused circles via `_fieldDimmed`, no visual change). */
/* Map tiles form a SEAMLESS mosaic that matches the bake — no per-tile drop
   shadow / rounding. */
body.mode-map .tile { box-shadow: none; border-radius: 0; }
/* Map tile hover cue: a slight enlarge of the tile itself (the photo tiling is
   light now, so the pop is cheap). No frame overlay — a separate frame can't be
   kept pixel-aligned with the tile across the world transform. transform-origin
   centre, so it grows in place. */
body.mode-map .tile:hover { z-index: 9000 !important; box-shadow: none !important; transform: scale(1.12) !important; }
/* Per-country bake image (shown pulled-back; hidden once the country tiles). */
.map-bake {
  position: absolute;
  background-size: 100% 100%;
  background-repeat: no-repeat;
  z-index: 9;                 /* under live tiles (z 10) */
  pointer-events: auto;       /* clickable → zoom into the country */
  cursor: pointer;
}
/* (No hover shadow change — the disc shadow stays constant on mouseover.) */
.field-photo-tile {
  position: absolute;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  cursor: pointer;
  overflow: hidden;
  transition: transform 0.14s !important;
}
.field-photo-tile:hover {
  /* Slight enlarge of the tile itself (same cue as the map), transform-origin
     centre. No frame overlay (a separate frame can't stay pixel-aligned across
     the world transform) and no drop-shadow (its blur radius × zoom scale would
     be a huge halo at deep zoom). */
  transform: scale(1.12) !important;
  z-index: 9000 !important;
}

/* NEW corner badge — top-left of any photo tile (Field / Map / Book) whose
   photo carries the new flag. FIXED size (not a % of the tile) so every badge
   is the same size regardless of the photo it sits on; it still scales with
   the canvas zoom in Field / Map. */
.new-badge {
  position: absolute; top: 0; left: 0; z-index: 3;
  /* Cap at 5px AND at 50% of the tile width, so the badge never grows bigger
     than half the photo on small (deep-zoom / map) tiles. */
  width: min(5px, 50%); height: auto;
  /* Force the box ratio so the badge isn't mis-sized on iOS Safari, which
     doesn't derive an SVG <img>'s intrinsic ratio from viewBox alone. */
  aspect-ratio: 13.19 / 7.52;
  object-fit: contain;
  pointer-events: none;
}
/* In Field / Map the badge appears only once zoomed in (same timing as the
   affiliation caption); in Book (outside #world) it always shows. */
#world .new-badge { display: none; }
#world.affil-visible .new-badge { display: block; }
/* Company (Map) view: badge sized independently of Field. Map photo tiles are
   now about the same size as Field's, so the badge matches Field's 5px (a
   smaller value made it look too small relative to the photos). */
body.mode-map #world .new-badge { width: min(5px, 50%); }
/* Book view: the generic ".book-photo img" rule (100%/object-fit) would
   stretch the badge to fill the cell — pin it back to a top-left mark.
   2× the old 30px, but capped at 50% of the photo width so it never exceeds
   half the photo on narrow SP tiles (% resolves against the positioned .book-photo). */
.book-photo .new-badge { width: min(60px, 50%); height: auto; object-fit: contain; }
.field-cat-label {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  pointer-events: none;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 400;
  border-radius: 20px;
  padding: 1px 8px;          /* 座布団を文字ギリギリに(縦詰め)→ 円下部に収め写真と被らない */
  line-height: 1;            /* 行間の余白を除去して座布団の高さを文字ピッタリに */
  letter-spacing: -0.02em;
}

/* ═══════════════════════════════════════════
   BOOK VIEWER
═══════════════════════════════════════════ */
#book-view {
  display: none;
  position: fixed; inset: 0; z-index: 80;
  background: #ffffff;
}
#book-view.active { display: block; }

/* Left field selector — one coloured arrow-tab per category.
   Top-aligned with the book by positionBookFields() (JS); the default
   here is the upper cap that keeps it clear of the top-left logo. */
#book-fields {
  position: absolute; left: 14px; top: 96px;
  z-index: 6; display: flex; flex-direction: column; gap: 4px;
}
.book-field-btn {
  /* PC: no fixed height — the 10 buttons flex to share #book-fields' height,
     which JS sets to the book's height (positionBookFields). So they line up
     with the book and never overflow past it. SP overrides height below. */
  width: 105px; flex: 1 1 0; min-height: 0; border: none; padding: 0 0 0 5px;
  display: flex; align-items: center; justify-content: flex-start;
  cursor: pointer; outline: none;
  /* Uniform text label for every field — sized so the longest label
     ("Racetracks") just fits the 105px button; other UI chrome matches. */
  font-size: 16px; font-weight: 400; letter-spacing: 0.01em;
  white-space: nowrap;
  /* Top-right corner clipped at 45° (square tag with notched corner). */
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 11px, 100% 100%, 0 100%);
  transition: width 0.14s, filter 0.14s;
}
.book-field-btn img { height: 10px; width: auto; display: block; pointer-events: none; }
.book-field-btn:hover { filter: brightness(1.1); }
.book-field-btn.active { width: 125px; }

/* Match the reference image colours for the field-name buttons. The
   inline cat.color is overridden for Town (was olive green), Water (was
   pale blue) and Office (was #e61f19 → pure red) — every other field matches. */
.book-field-btn[data-cat-id="cityride"] { background: #3a3a3a !important; }
.book-field-btn[data-cat-id="ocean"]    { background: #1ea3d8 !important; }
.book-field-btn[data-cat-id="office"]   { background: #ff0000 !important; }

/* Main book area — full width so the book centres on the viewport
   (the field selector sits over the left margin). */
#book-main {
  position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 16px;
  /* Book width — defined here (not on #book-container) so the page-nav, a
     sibling, can size itself to a fraction of it. */
  --bw: min(1800px, max(1070px, 82vw), calc((100vh - 263px) * 1070 / 480));
}

/* Book (photo) area — reference 1070×480 at 1366 base; grows with the
   viewport (82vw, also height-capped) up to 1800px wide.
   The height cap reserves 275px of vertical space (top HUD ≈106 + page
   nav ≈52 + bottom footer ≈103, incl. the ~5px page-nav↔View margin) so on
   short windows the book shrinks instead of pushing the page-nav down into
   the View bar / legend. Keep in sync with BOTTOM_RESERVE in positionBookFields. */
#book-container {
  display: flex; align-items: stretch;
  position: relative;
  width: var(--bw);
  height: calc(var(--bw) * 480 / 1070);
  border-radius: 3px;
  /* Narrower drop shadow — tighter blur + negative spread pulls the shadow in
     so it doesn't fan out as wide around the book. */
  box-shadow: 0 12px 28px -8px rgba(0,0,0,0.22), 0 3px 10px -3px rgba(0,0,0,0.12);
  overflow: hidden;
  cursor: grab;
}
#book-container.grabbing { cursor: grabbing; }

.book-page {
  flex: 1; position: relative; overflow: hidden;
  background: transparent;          /* container gradient shows through */
  padding: 38px;
}
.book-spine {
  width: 6px; flex-shrink: 0;
  background: #9a9a9a;              /* grey centre line */
}

/* Fixed field name + photo count — top-left of the book container.
   Lives outside the flipping pages so it never moves on page turns.
   line-height: 1 removes the leading above the glyphs so the label
   sits flush against the corner. PC sits 10px in from the corner;
   the SP media query pulls it tight to (top:0 / left:5). */
#book-fieldname {
  position: absolute; top: 10px; left: 15px; z-index: 6;
  pointer-events: none;
  white-space: nowrap;
  line-height: 1;
}
/* Matches the .hud-archive size — 12px on PC, 9px on SP (see media
   query). !important guards against the Yamaha shared CSS bumping
   inline text. */
#bfn-name,
#bfn-count {
  color: #fff; font-weight: 400;
  font-size: 12px !important;
  line-height: 1 !important;
  letter-spacing: 0.01em;
  text-shadow: 0 1px 2px rgba(0,0,0,0.22);
}

/* Photo layouts — up to 4 photos per page, no rotation.
   The wrap centres its rows (vertically); each row centres its photos
   (horizontally). Photos have explicit width/height (% of row / wrap)
   so they don't stretch to fill — the cluster is anchored to the wrap
   centre with a fixed 10px gap and no overlap. */
.book-photos-wrap {
  display: flex; flex-direction: column;
  justify-content: center; align-items: center;
  gap: 10px; height: 100%; width: 100%;
}
.book-photos-wrap.layout-1 { /* single photo — already centred */ }
.book-photo-row {
  display: flex; gap: 10px;
  justify-content: center; align-items: center;
  width: 100%; flex: none;
}

/* L+stack2: left tall photo + right column of two stacked photos. */
.book-photos-wrap.kind-lstack {
  flex-direction: row; align-items: center;
  gap: 10px; height: 100%;
}
.book-photo-col {
  display: flex; flex-direction: column;
  justify-content: center; align-items: center;
  gap: 10px; height: 100%; flex: none;
}

.book-photo {
  position: relative; border-radius: 2px;
  overflow: hidden;
  flex: none; min-width: 0;
  /* Cell sizes itself to the photo's natural aspect ratio (set as
     --ratio on image load). Default is 4/3 to avoid layout flash. */
  width: auto; height: auto;
  aspect-ratio: var(--ratio, 4 / 3);
  transition: transform 0.18s;
  cursor: pointer;
}
/* Filename caption for NG-photo review — selectable text, sits over the bottom
   of each Book photo. pointer/select overrides so dragging selects the name
   instead of panning / opening the modal. */
.book-photo-fname {
  /* Hidden for public release — was a reviewer aid for NG-photo flagging.
     Kept in the DOM (selectable) but not displayed. */
  display: none;
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  font: 600 11px/1.35 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  color: #fff; background: rgba(0,0,0,0.62);
  padding: 2px 5px; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  user-select: text; -webkit-user-select: text; cursor: text;
}
/* In a row: cell may grow to row height; width derived from aspect ratio,
   capped at --max-w to share space with siblings (set in JS). */
.book-photo-row > .book-photo {
  /* --max-h is set in pixels by applyBookCellMaxH so portraits never tower
     beyond a square bounded by the cell's max-w. */
  max-height: var(--max-h, 100%);
  max-width:  var(--max-w, 100%);
}
/* In a column: cell may grow to col width; height derived from aspect
   ratio, capped at --max-h. */
.book-photo-col > .book-photo {
  max-width: 100%;
  max-height: var(--max-h, 100%);
}
/* Single-photo page: the cell's width AND height are computed in JS
   (preserving the photo's aspect) so we just apply them here verbatim.
   Avoids the aspect-break that happens when only one dimension is set. */
.book-photos-wrap.layout-1 > .book-photo {
  width:  var(--max-w, 100%);
  height: var(--max-h, 100%);
  aspect-ratio: auto;
}
/* No hover enlarge on Book photos (user request) — keeps the page static while
   reviewing filenames. */
.book-photo:hover { z-index: 2; }
.book-photo img {
  width: 100%; height: 100%; object-fit: contain; display: block;
}
.book-photo-placeholder {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  font-size: 32px;
}
/* book-photo-single removed — 1-photo case now uses explicit width/height
   from BOOK_LAYOUTS[1] like the multi-photo layouts. */

.book-caption {
  position: absolute; bottom: 0; left: 0; right: 0;
  padding: 3px 6px 4px;
  font-size: 8.5px; color: #fff; font-weight: 600;
  /* Lighter band, fades out toward the right edge. */
  background: linear-gradient(to right,
    rgba(0,0,0,0.42) 0%,
    rgba(0,0,0,0.32) 55%,
    rgba(0,0,0,0.00) 100%);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  letter-spacing: 0.01em;
}
/* (.book-flag retired — affiliation caption replaces it) */

/* Page turn animation */
@keyframes slideFromRight { from { opacity: 0; transform: translateX(30px); } to { opacity: 1; transform: translateX(0); } }
@keyframes slideFromLeft  { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } }
.spread-enter-right { animation: slideFromRight 0.28s ease; }
.spread-enter-left  { animation: slideFromLeft 0.28s ease; }

/* Book nav — prev arrow · current-field dots · next arrow */
#book-nav {
  display: flex; align-items: center; gap: 16px;
  /* 70% of the book width, centred under the book. Dots wrap. */
  width: calc(var(--bw) * 0.7);
}
.book-nav-btn {
  background: #9a9a9a; border: none; padding: 0; border-radius: 50%;
  width: 44px; height: 44px; cursor: pointer; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 4px rgba(0,0,0,0.30);
  transition: background 0.15s, transform 0.1s;
}
.book-nav-btn img { width: 12px; height: auto; display: block; filter: brightness(0) invert(1); }
#bNext img { transform: scaleX(-1); }
.book-nav-btn:hover:not(:disabled) { background: #7c7c7c; }
.book-nav-btn:disabled { opacity: 0.25; cursor: default; }

#book-dots {
  flex: 1; display: flex; gap: 6px; align-items: center;
  flex-wrap: wrap; justify-content: center;
}
.book-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(0,0,0,0.16); cursor: pointer;
  transition: transform 0.15s, background 0.15s;
}
.book-dot:hover { transform: scale(1.25); }
.book-dot.active { transform: scale(1.4); }

/* Editable "current / total" page indicator (replaces the per-spread dots). */
.book-pager {
  display: flex; align-items: baseline; gap: 5px;
  font-size: 14px; line-height: 1; user-select: none;
}
.book-page-input {
  width: 2.6em; min-width: 2.6em; text-align: center;
  font: inherit; font-size: 15px; font-weight: 700;
  color: inherit; background: transparent;
  border: none; border-bottom: 2px solid currentColor;
  padding: 1px 2px 2px; border-radius: 2px 2px 0 0;
  outline: none; -moz-appearance: textfield; cursor: text;
}
.book-page-input::-webkit-outer-spin-button,
.book-page-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.book-page-input:hover  { background: rgba(0,0,0,0.05); }
.book-page-input:focus  { background: rgba(0,0,0,0.07); }
.book-page-total { color: #777; font-weight: 600; font-size: 14px; }

/* SP touch-gesture guides — hidden on PC. The SP media query below
   reveals them on small screens, sized and positioned for tap. */
#pinch-guide, #flick-guide { display: none; }

/* ═══════════════════════════════════════════
   SP RESPONSIVE — max-width: 768px
   Reference: 260601_KS_web_本サイト_snz-05/06.jpg
   Breakpoint covers narrow phones & small tablets.
═══════════════════════════════════════════ */
@media (max-width: 768px) {

  /* ── SP operation guides ─────────────────────────────────────── */
  /* Pinch (Field/Map) and flick (Book) guides — styled like #wheel-guide */
  #pinch-guide,
  #flick-guide {
    display: block;
    position: fixed; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    z-index: 600;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.6s ease;
  }
  #pinch-guide img,
  #flick-guide img {
    width: auto; height: 160px; display: block;
  }
  #pinch-guide.show,
  #flick-guide.show { opacity: 1; }

  /* Desktop wheel guide hidden on SP */
  #wheel-guide { display: none; }

  /* Hide the PC field-category legend on SP — there's no room for it. */
  #cat-legend { display: none !important; }

  /* SP: zoombar (+/-) is dropped to make room for a larger book/photo
     area. Zoom is handled by pinch-gesture. */
  #zoombar { display: none !important; }

  /* #book-fieldname stays visible on SP, pulled tight to the corner. */
  #book-fieldname { top: 0; left: 5px; }
  #bfn-name,
  #bfn-count { font-size: 9px !important; }

  /* ── SP performance: Map view used to OOM-crash on real phones when
     all photo tiles materialised at once. The biggest costs were
     per-tile GPU layers (will-change) and per-tile hover transitions —
     with ~700 tiles that's ~700 layers / repaints. Strip those on SP. */
  body.mode-map .tile {
    will-change: auto !important;
    transition: none !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  }
  body.mode-map .tile:hover { transform: none; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18); }

  /* SP modal: the page-nav arrows overlapped the centred caption. Push them to
     the very left/right edges, shrink them, and tighten the bottom margin so the
     text clears them. */
  .mnav-arrow { width: 36px; height: 36px; bottom: 8px; }
  .mnav-arrow img { width: 10px; }
  #mPrev { left: 3px; }
  #mNext { right: 3px; }
  #mbody { padding: 12px 44px 8px; }

  /* ── HUD: KANDO logo (top-left), all three blocks at ~80% of the
         original size and pulled tight to the top. Stats are pulled
         out of #hud's flow so they sit AFTER the Yamaha Day logo. */
  #hud { top: 12px; left: 16px; gap: 0; }
  #hud-logo { height: 35px; display: block; }     /* 44 → 35 (~80%) */
  #hud-logo-fallback { font-size: 19px; }
  #hud-stats {
    position: fixed;
    top: 79px;        /* yamaha-day bottom (75) + 4px gap */
    left: 16px;
    z-index: 500;
    pointer-events: none;
    max-width: calc(100vw - 140px);   /* keep clear of the 71st badge */
  }
  /* NEW button: fixed just below the stats line (hud-stats is taken out of
     the HUD flow on SP, so position the button explicitly). */
  #new-btn {
    position: fixed; top: 99px; bottom: auto; left: 16px; z-index: 500;  /* nudged +4px down */
    margin-top: 0; padding: 8px 12px; font-size: 14px;   /* ~80% height (vert pad 12→8) */
  }
  .hud-archive,
  .hud-count   { font-size: 9px !important; }                /* unified, ~80% of PC's 12px */
  .hud-archive b,
  .hud-count b { font-size: 9px !important; }

  /* ── Yamaha Day logo: 4px below KANDO logo ─────────────────── */
  #event-logo {
    top: 49px;        /* tightened the gap above (2px) and opened the gap below */
    left: 16px; right: auto;
  }
  #event-logo img { height: 26px; }               /* 32 → 26 (~80%) */

  /* ── 71st badge: SP uses a dedicated SVG that includes the background
         circle. Pin to the top-right corner of the viewport. */
  #archive-badge {
    left: auto; right: 0;
    top: 0; transform: none;
    width: 132px;     /* 165 → 132 (~80%) */
    overflow: visible;
  }
  #archive-badge .badge-pc { display: none; }
  #archive-badge .badge-sp {
    display: block; width: 100%; height: auto;
  }

  /* ── OPENING button: bottom edge aligned with Archive 2026 stats
         (stats bottom ≈ 102; button height 26 → top: 102 − 26 = 76). */
  /* NEW grid: smaller cells on SP, less padding. */
  #new-grid-scroll { padding: 52px 10px; }
  #new-grid-inner { gap: 20px; }
  .ng-row { gap: 4px; }
  .ng-date { font-size: 12px; }
  .ng-cell { width: 88px; height: 88px; }
  /* SP scrollbars are overlay (no layout width), so no scrollbar offset. */
  #new-grid-close { right: 16px; }
  /* Post button: smaller, bottom-right above the View bar (legend hidden on SP). */
  /* SP: unified top-right (the position formerly set for Book). */
  #post-btn { right: 12px; top: 58px; bottom: auto; width: 95px; height: 95px; }   /* 76 × 1.25 */
  #post-btn .post-pc { display: none; }
  #post-btn .post-sp { display: block; }

  /* ── Footer: Layoutbar (View label + 3 buttons), pinned to the bottom.
         No field-legend on SP — see #cat-legend hidden above. */

  /* Layoutbar: pinned 5px above the viewport bottom. */
  #layoutbar {
    bottom: 5px;
    left: 50%; right: auto;
    transform: translateX(-50%);
    flex-direction: column;
    align-items: center;
    padding: 0;
    background: transparent;
    border-top: none;
    gap: 5px;
    width: auto;
  }
  #layoutbar-label { text-align: center; font-size: 14px; position: relative; top: 3px; margin-top: 0; }   /* View row: roomy → larger than category; nudged down 3px (SP only; PC's 4px margin reset here) */
  /* Guideline notice: PC copy hidden; SP copy shown below View, centred, ~2 lines. */
  #gl-pc { display: none; }
  #gl-sp { display: block; text-align: center; max-width: 92vw; margin: 4px auto 0; }
  /* SP: shrink the per-photo modal notice so it fits in 2 lines on narrow phones. */
  #mnotice { font-size: 6.5px; }
  .layoutbar-btns {
    display: flex; gap: 8px;
    justify-content: center;
    width: 92vw; max-width: 460px;
  }
  .layout-btn {
    flex: 1 1 0; width: auto; max-width: none;
    padding: 8px 0;        /* ~70% of the doubled height */
    font-size: 14px;       /* View buttons have room — larger than category cells */
  }

  /* (zoombar is hidden on SP — see #zoombar display:none above.) */

  /* ── BOOK VIEW: flex-column layout on SP ─────────────────────── */
  /* book-view becomes a scrollable flex column so the book stage,
     nav, and field selector stack vertically */
  #book-view.active {
    display: flex !important;
    flex-direction: column;
    align-items: center;
    overflow-y: auto;
    overflow-x: hidden;
    /* top clears the shrunken HUD stack (≈108); bottom reserves the category
       grid (raised to clear the View label + guideline notice) + a gap. */
    padding: 120px 0 152px;
  }

  /* book-main: vertically centered in the bookView content area. The
     page-nav stays 5px below the book stage; the whole block centers
     so tall viewports balance whitespace above and below. */
  #book-main {
    position: static;
    width: 100%;
    flex: 1 1 auto;
    min-height: 0;
    display: flex; flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 0;
  }

  /* Square single-page stage. The 262px reservation = top padding (120)
     + page-nav row + the bottom UI stack (View bar + field selector) +
     a little breathing room; tuned by eye on a 400×800 viewport. */
  #book-container {
    --bsp: min(88vw, calc(100svh - 290px));
    width: var(--bsp) !important;
    height: var(--bsp) !important;
    min-width: unset !important; max-width: unset !important;
    border-radius: 4px;
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.14), 0 1px 3px rgba(0, 0, 0, 0.08);
  }
  /* Hide right page and spine — single-page mode on SP */
  .book-spine,
  #book-right-page { display: none !important; }
  /* Left page fills the whole stage */
  #book-left-page { flex: 1 !important; padding: 20px; }

  /* Page nav on SP: arrows are dropped (a flick-gesture hint already tells
     users to swipe), and the dot strip spans nearly the full window width.
     Extra top margin keeps the dots clear of the book page when they wrap
     to multiple rows. */
  #book-nav {
    width: 96vw;
    max-width: none;
    gap: 0;
    margin-top: 8px;      /* tightened (was 14) */
    margin-bottom: 2px;   /* tightened (was 4) */
  }
  #book-nav .book-nav-btn { display: none !important; }
  /* Page indicator ~80% of PC size on SP, tighter. */
  .book-pager      { font-size: 11px; }
  .book-page-input { font-size: 12px; }
  .book-page-total { font-size: 11px; }

  /* Field selector: pinned ABOVE the View label (5px gap), so it stays
     at a constant position regardless of book size. 3-column grid using
     PC's arrow-tab shape but at roughly half height. Order matches the
     reference (col1: Road / Off-Road / Racetracks, col2: Water /
     Turf-Sky / Town / Factory, col3: Office / Daily Life / Sports). */
  #book-fields {
    position: fixed !important;
    top: auto !important;  /* unset PC base top:96 so height collapses to content */
    left: 50%; right: auto;
    transform: translateX(-50%);
    bottom: 90px;          /* sits ~5px above the "View" label (which now has the guideline notice below it); was 62 before the notice was added */
    display: grid !important;
    grid-template-columns: repeat(5, 1fr) !important;
    grid-template-rows: repeat(2, auto) !important;
    grid-auto-flow: row !important;
    gap: 5px 5px;
    width: 92vw;
    margin-top: 0;
    z-index: 500;
    pointer-events: auto;
  }
  .book-field-btn {
    /* Smaller notch + tighter padding so the longest labels (Racetracks,
       Daily Life, Turf / Sky) fit in the narrower 5-col cells. */
    clip-path: polygon(0 0, calc(100% - 6px) 0, 100% 6px, 100% 100%, 0 100%) !important;
    border-radius: 0 !important;
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    height: 25px;          /* ~70% of the doubled 36px */
    padding: 0 2px 0 4px !important;
    font-size: 10px;       /* unified SP UI font ("Racetracks" still fits the cell) */
    justify-content: flex-start;
  }
  .book-field-btn.active { width: 100% !important; }
  /* 5×2 row-flow grid — 10 items, no gaps:
       row 1: Road / Off-Road / Racetracks / Water / Turf-Sky
       row 2: Town / Factory / Office / Daily Life / Sports
     so no explicit grid-area overrides needed. */
}