/*
 * Styles for the SSR creator-challenge pages (Thymeleaf, EventViewController): the /events index,
 * the round page /events/{slug} and the frozen entry page. Served at /events-assets/events.css
 * (mirrors /templates-assets/templates.css).
 *
 * The page is a ledger: a left-aligned hero (kicker, display title, tagline, the two CTAs), the
 * round's day strip — one cell per day of the submission window, the days already spent filled —
 * and then one block per section with its label in a narrow left column and its body on the
 * right (stacked on phones). No alternating bands, no boxed countdown: the strip and the type
 * carry the page.
 *
 * ONE palette, shared with the SPA. Every --ev-* value below equals the matching --color-* token
 * in frontend/src/index.css: `:root` = the light `@theme` block, `html.dark` = the `.dark` block.
 * The names differ (--ev-* vs --color-*), the numbers may not — DesignTokenParityTest reads
 * index.css and compares this file's values against it, so a hand-tuned colour here is a red run.
 * Theme selection is the same as the SPA's: the anti-flash script in <head> reads
 * localStorage["litmemo-theme"] (shared/src/lib/theme.ts THEME_STORAGE_KEY) and adds `dark`
 * to <html>; the visitor's 投稿 click lands them in the SPA on the same theme they saw here.
 */

:root {
  color-scheme: light;
  --ev-background: #faf8f5;
  --ev-foreground: #1a1a1a;
  --ev-card: #ffffff;
  --ev-card-foreground: #1a1a1a;
  --ev-popover: #ffffff;
  --ev-popover-foreground: #1a1a1a;
  --ev-primary: #7d6340;
  --ev-primary-foreground: #ffffff;
  --ev-secondary: #f0ebe4;
  --ev-secondary-foreground: #4a3f35;
  --ev-muted: #f5f0ea;
  --ev-muted-foreground: #6b6159;
  --ev-accent: #e8dfd4;
  --ev-accent-foreground: #4a3f35;
  --ev-destructive: #dc2626;
  --ev-destructive-foreground: #ffffff;
  --ev-border: #9e8e7e;
  --ev-input: #9e8e7e;
  --ev-ring: #7d6340;
  --ev-sidebar: #f5f0ea;
  --ev-sidebar-foreground: #4a3f35;
  --ev-sidebar-border: #9e8e7e;
  --ev-warning: #946300;
  --ev-success: #0d7a54;
  --ev-info: #2563eb;

  /* Same font stacks as templates.css / blog.css / index.css — one brand face per script. */
  --ev-font: "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, sans-serif;
  --ev-font-serif: "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, serif;
}

html.dark {
  color-scheme: dark;
  --ev-background: #0f0d0a;
  --ev-foreground: #e8e0d4;
  --ev-card: #1a1610;
  --ev-card-foreground: #e8e0d4;
  --ev-popover: #1a1610;
  --ev-popover-foreground: #e8e0d4;
  --ev-primary: #c4a574;
  --ev-primary-foreground: #0f0d0a;
  --ev-secondary: #241f18;
  --ev-secondary-foreground: #c8bfb0;
  --ev-muted: #241f18;
  --ev-muted-foreground: #978b7b;
  --ev-accent: #2e271d;
  --ev-accent-foreground: #c8bfb0;
  --ev-destructive: #dc2626;
  --ev-destructive-foreground: #ffffff;
  --ev-border: #504536;
  --ev-input: #504536;
  --ev-ring: #c4a574;
  --ev-sidebar: #13100c;
  --ev-sidebar-foreground: #c8bfb0;
  --ev-sidebar-border: #504536;
  --ev-warning: #f59e0b;
  --ev-success: #10b981;
  --ev-info: #3b82f6;
}

html[lang="ja"] {
  --ev-font: "Swei Spring Sugar JP", "Hiragino Maru Gothic ProN", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", system-ui, sans-serif;
  --ev-font-serif: "Swei Spring Sugar JP", "Hiragino Mincho ProN", "Noto Serif JP", system-ui, serif;
}

html[lang="zh-Hans"] {
  --ev-font: "Swei Spring Sugar SC", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  --ev-font-serif: "Swei Spring Sugar SC", "Noto Serif SC", "PingFang SC", "Microsoft YaHei", system-ui, serif;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--ev-font);
  color: var(--ev-foreground);
  background: var(--ev-background);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; }
.ev-serif { font-family: var(--ev-font-serif); }

/* The top bar is the shared SSR one: /site-assets/site-topbar.css (fragments/site-topbar.html). */

/* ===== Page scaffold ===== */
.ev-page { overflow-x: hidden; }
.ev-inner { max-width: 72rem; margin: 0 auto; padding: 0 1.25rem; }
.ev-muted { color: var(--ev-muted-foreground); }

/* A block: one section, full width, a small heading on top; blocks are separated by one hairline,
   never by a background change. */
.ev-block { border-top: 1px solid var(--ev-border); padding: 2.5rem 0; }
.ev-block:last-of-type { padding-bottom: 4rem; }
.ev-heading { margin: 0 0 1.5rem; font-size: 1.125rem; line-height: 1.4; font-weight: 700; }
/* A heading with a note and a button beside it (the wall's count + 投稿). */
.ev-heading-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.25rem; margin: 0 0 1.5rem; }
.ev-heading-row .ev-heading { margin: 0; }
/* 「全部 / 已投」on the wall's heading row (judging week, signed in): a two-segment pill pushed to the
   row's end on wide screens, wrapping under the heading on phones. [hidden] needs its own rule because
   the class sets display. */
.ev-wall-filter { display: inline-flex; gap: 0.25rem; margin-left: auto; padding: 0.2rem; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--ev-border) 55%, transparent); }
.ev-wall-filter[hidden] { display: none; }
/* The「已投」view hides the wall's load-more control; its class sets display, so [hidden] needs saying. */
.ev-wall-more[hidden] { display: none; }
.ev-chip { font: inherit; font-size: 0.85rem; line-height: 1.2; padding: 0.35rem 0.9rem; border: 0; border-radius: 999px;
  background: transparent; color: var(--ev-muted-foreground); cursor: pointer; }
.ev-chip:hover { color: var(--ev-foreground); }
.ev-chip.is-active { background: var(--ev-primary); color: var(--ev-primary-foreground); }
.ev-chip:focus-visible { outline: 2px solid var(--ev-ring); outline-offset: 2px; }
.ev-chip-count { margin-left: 0.2rem; font-variant-numeric: tabular-nums; opacity: 0.8; }
.ev-heading-note { margin: 0; color: var(--ev-muted-foreground); }
.ev-heading-row .ev-btn { margin-left: auto; }
@media (min-width: 1024px) {
  .ev-block { padding: 3.5rem 0; }
}

/* ===== Hero ===== */
.ev-hero { padding: 3rem 0 2.5rem; }
@media (min-width: 1024px) {
  .ev-hero { padding: 4.5rem 0 3rem; }
}
/* The kicker: phase word, a short hairline, then the day of the round. One line, small. */
.ev-kicker { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin: 0 0 1.25rem; font-size: 0.9rem; color: var(--ev-muted-foreground); }
.ev-kicker .ev-phase { font-weight: 700; color: var(--ev-foreground); }
.ev-kicker .ev-phase[data-phase="OPEN"] { color: var(--ev-primary); }
.ev-kicker-sep { width: 2rem; border-top: 1px solid var(--ev-border); }
.ev-hero h1 {
  margin: 0 0 1.25rem; font-family: var(--ev-font-serif); font-weight: 700;
  font-size: clamp(2.5rem, 6.5vw, 4.25rem); line-height: 1.08; overflow-wrap: anywhere;
}
.ev-tagline { margin: 0 0 2rem; max-width: 34rem; font-size: 1.125rem; line-height: 1.7; color: var(--ev-muted-foreground); }
/* The results line under the intro (results out):「N 件投稿・M 票・K 件得獎」, tight to the sentence above it. */
.ev-results-stats { margin: -1.25rem 0 2rem; font-weight: 700; font-size: 1rem; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; color: var(--ev-foreground); }
/* The index head is a page title, not a hero: the blog list's size (2rem, 1.5rem under 640px), and
   the first block flows straight on from it — no rule, no extra gap (the rule between blocks stays). */
.ev-hero-index { padding: 2.5rem 0 0; }
.ev-hero-index + .ev-block { border-top: none; padding-top: 2rem; }
.ev-hero-index h1 { margin-bottom: 0.5rem; font-size: 2rem; line-height: 1.25; color: var(--ev-primary); }
.ev-hero-index .ev-tagline { margin-bottom: 0; font-size: 1rem; }
@media (max-width: 639px) { .ev-hero-index h1 { font-size: 1.5rem; } .ev-hero-index .ev-tagline { font-size: 0.875rem; } }
@media (min-width: 1024px) { .ev-hero.ev-hero-index { padding: 2.5rem 0 0; } .ev-hero-index + .ev-block { padding-top: 2.5rem; } }

/* ===== Buttons ===== */
.ev-cta-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.ev-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 3rem; padding: 0.75rem 1.5rem; border-radius: 0.375rem;
  font: inherit; font-weight: 700; font-size: 1rem; line-height: 1.2; cursor: pointer;
  border: 1px solid transparent; transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.ev-btn-primary { background: var(--ev-primary); color: var(--ev-primary-foreground); border-color: var(--ev-primary); }
.ev-btn-primary:hover { background: var(--ev-foreground); border-color: var(--ev-foreground); color: var(--ev-background); }
.ev-btn-outline { background: transparent; color: var(--ev-foreground); border-color: var(--ev-border); }
.ev-btn-outline:hover { border-color: var(--ev-foreground); }
.ev-btn-disabled { background: transparent; color: var(--ev-muted-foreground); border-color: var(--ev-border); cursor: default; }
.ev-btn:focus-visible { outline: 2px solid var(--ev-ring); outline-offset: 2px; }

/* ===== The progress line (fragments/milestone-line.html) + what it counts to =====
   An ink stroke (SVG, stretched to the width; non-scaling stroke keeps the brush weight) from the
   first milestone to the last, drawn as far as --ev-now (0–1); the rest of the way is a dotted
   trail. Marks sit at percentages of the line; Momo sits on now. ===== */
.ev-timeline { margin-top: 2rem; }
.ev-line { position: relative; margin: 0; padding: 3.5rem 0 3.25rem; }
.ev-line-track { position: absolute; left: 0; right: 0; top: calc(3.5rem + 12px); height: 5px; transform: translateY(-50%); }
/* The way still to go: a dotted trail (one dot every 8px), full width. */
.ev-line-rest { position: absolute; inset: 0; background-image: radial-gradient(circle, var(--ev-border) 1.25px, transparent 1.6px); background-size: 8px 5px; background-position: 0 50%; background-repeat: repeat-x; }
/* The way already gone: a bar as wide as --ev-now. No filter — the displacement-map brush edge
   smeared a second, fainter band under the bar (咕's screenshot, 2026-09-22); a clean stroke it is. */
.ev-line-drawn { position: absolute; left: 0; top: 0; bottom: 0; width: calc(var(--ev-now, 0) * 100%); border-radius: 3px; background: var(--ev-primary); }
.ev-line.is-armed .ev-line-drawn { transition: width 1.4s cubic-bezier(0.2, 0.7, 0.2, 1); }
.ev-line.is-armed .ev-line-now { transition: left 1.4s cubic-bezier(0.2, 0.7, 0.2, 1); }
/* Day ticks above the track: one per Taipei day, so a folded past shows as tighter ticks. */
.ev-line-ticks { list-style: none; margin: 0; padding: 0; }
.ev-line-ticks li { position: absolute; top: calc(3.5rem + 12px - 12px); width: 1px; height: 5px; background: var(--ev-border); opacity: 0.8; }
.ev-line-marks { list-style: none; margin: 0; padding: 0; }
.ev-line-marks li { position: absolute; top: calc(3.5rem + 12px); transform: translate(-50%, -50%); text-align: center; }
.ev-line-marks li.is-start { transform: translate(0, -50%); text-align: left; }
.ev-line-marks li.is-end { transform: translate(-100%, -50%); text-align: right; }
.ev-line-dot { display: block; width: 12px; height: 12px; margin: 0 auto; border-radius: 999px; background: var(--ev-background); border: 2px solid var(--ev-border); }
.ev-line-marks li.is-start .ev-line-dot { margin-left: 0; }
.ev-line-marks li.is-end .ev-line-dot { margin-right: 0; }
.is-passed .ev-line-dot { background: var(--ev-primary); border-color: var(--ev-primary); }
.ev-line-date, .ev-line-label { display: block; white-space: nowrap; font-size: 0.8rem; line-height: 1.3; }
.ev-line-marks .ev-line-date { position: absolute; top: calc(100% + 0.3rem); left: 0; right: 0; color: var(--ev-muted-foreground); font-variant-numeric: tabular-nums; }
.ev-line-marks .ev-line-label { position: absolute; top: calc(100% + 1.35rem); left: 0; right: 0; color: var(--ev-foreground); font-weight: 600; }
.ev-line-marks li.is-next .ev-line-label { color: var(--ev-primary); }
.ev-line-marks li.is-start .ev-line-date, .ev-line-marks li.is-start .ev-line-label { right: auto; }
.ev-line-marks li.is-end .ev-line-date, .ev-line-marks li.is-end .ev-line-label { left: auto; }
/* A mark too close to the one before hangs its date + label on the next row (three rows, then dense). */
.ev-line-marks li[data-tier="1"] .ev-line-date { top: calc(100% + 2.5rem); }
.ev-line-marks li[data-tier="1"] .ev-line-label { top: calc(100% + 3.55rem); }
.ev-line-marks li[data-tier="2"] .ev-line-date { top: calc(100% + 4.7rem); }
.ev-line-marks li[data-tier="2"] .ev-line-label { top: calc(100% + 5.75rem); }
.ev-line.has-tier { padding-bottom: 5.5rem; }
.ev-line:has(li[data-tier="2"]) { padding-bottom: 7.75rem; }
/* Momo on「now」: feet on the line, the day pill above the head. */
.ev-line-now { position: absolute; top: calc(3.5rem + 12px); transform: translate(-50%, -100%); pointer-events: none; }
/* Two poses in the markup; the figure's is-sleeping / is-sitting (server, then the script) picks one. */
.ev-line-cat { display: none; fill: var(--ev-primary); }
.ev-line.is-sleeping .ev-line-cat-sleeping { display: block; width: 40px; height: auto; }
.ev-line.is-sitting .ev-line-cat-sitting { display: block; width: 30px; height: auto; }
.ev-line-cat-eye { fill: none; stroke: var(--ev-background); stroke-width: 2; stroke-linecap: round; }
.ev-line-cat-eyeball { fill: var(--ev-background); }
.ev-line-cat-tail { fill: none; stroke: var(--ev-primary); stroke-width: 5; stroke-linecap: round; transform-box: fill-box; animation: evLineTail 3s ease-in-out infinite; }
.ev-line-cat-tail-curl { transform-origin: 74px 64px; animation-duration: 6s; }
.ev-line-cat-tail-sit { transform-origin: 30px 78px; }
@keyframes evLineTail { 0%, 100% { transform: rotate(-8deg); } 50% { transform: rotate(8deg); } }
.ev-line-day {
  position: absolute; left: 50%; bottom: calc(100% + 0.2rem); transform: translateX(-50%); white-space: nowrap;
  padding: 0.15rem 0.6rem; border-radius: 999px; font-size: 0.8rem; font-weight: 700;
  background: var(--ev-primary); color: var(--ev-primary-foreground);
}
.ev-line-day[hidden] { display: none; }
.ev-line-legend { display: none; }
/* Many marks: the marks keep only their dots; dates and labels move to the legend at every width. */
.ev-line.is-dense .ev-line-marks .ev-line-date, .ev-line.is-dense .ev-line-marks .ev-line-label { display: none; }
.ev-line.is-dense { padding-bottom: 0.5rem; }
.ev-line.is-dense .ev-line-legend { display: flex; }
.ev-line-legend { flex-wrap: wrap; gap: 0.35rem 1.25rem; margin: 1.25rem 0 0; font-size: 0.85rem; }
.ev-line-legend > span { display: inline-flex; align-items: center; gap: 0.4rem; }
.ev-line-legend .ev-line-dot { width: 9px; height: 9px; margin: 0; }
.ev-line-legend .ev-line-date { color: var(--ev-muted-foreground); }
.ev-line-legend .ev-line-label { font-weight: 600; }
.ev-line-legend .is-next .ev-line-label { color: var(--ev-primary); }
@media (max-width: 639px) {
  /* Phones: dots only on the line; dates + labels as a legend underneath, in order. */
  .ev-line { padding: 2.75rem 0 0.5rem; }
  .ev-line-track, .ev-line-marks li { top: calc(2.75rem + 12px); }
  .ev-line-ticks li { top: calc(2.75rem + 12px - 12px); }
  .ev-line-now { top: calc(2.75rem + 12px); }
  .ev-line-marks .ev-line-date, .ev-line-marks .ev-line-label { display: none; }
  .ev-line-legend { display: flex; }
  .ev-line.has-tier, .ev-line:has(li[data-tier="2"]) { padding-bottom: 0.5rem; }
}
.ev-timeline-meta { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.5rem 2rem; margin-top: 0.5rem; }
/* The countdown is one sentence: label, then number+unit pairs; the script only rewrites the numbers. */
.ev-countdown { margin: 0; font-size: 0.95rem; color: var(--ev-muted-foreground); white-space: nowrap; }
.ev-countdown strong { margin-left: 0.5rem; margin-right: 0.15rem; font-size: 1.25rem; color: var(--ev-foreground); font-variant-numeric: tabular-nums; }
.ev-dates { display: flex; flex-wrap: wrap; gap: 0.35rem 1.5rem; list-style: none; margin: 0; padding: 0; font-size: 0.9rem; color: var(--ev-muted-foreground); }
.ev-dates strong { margin-right: 0.35rem; font-weight: 600; color: var(--ev-foreground); }
.ev-tz-note { width: 100%; margin: 0.25rem 0 0; font-size: 0.8rem; color: var(--ev-muted-foreground); }

/* ===== Tiles: the wall, the demo, the results ===== */
.ev-tiles { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 640px) { .ev-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .ev-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ev-tile {
  display: flex; flex-direction: column; gap: 0.35rem; min-width: 0; padding: 1.25rem 1.25rem 1.1rem;
  border: 1px solid var(--ev-border); border-radius: 0.5rem; background: var(--ev-card); color: var(--ev-card-foreground);
  transition: border-color 0.2s;
}
a.ev-tile:hover { border-color: var(--ev-primary); }
a.ev-tile:hover h3 { color: var(--ev-primary); }
.ev-tile h3 { margin: 0; font-family: var(--ev-font-serif); font-size: 1.35rem; line-height: 1.3; overflow-wrap: anywhere; transition: color 0.2s; }
.ev-tile-author { font-size: 0.9rem; color: var(--ev-muted-foreground); overflow-wrap: anywhere; }
.ev-tile-stats { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; margin-top: 0.75rem; font-size: 0.85rem; color: var(--ev-muted-foreground); }
.ev-tile-stats strong { margin-right: 0.2rem; font-weight: 700; color: var(--ev-foreground); font-variant-numeric: tabular-nums; }
.ev-tile-link { margin-top: 0.75rem; font-size: 0.9rem; font-weight: 700; color: var(--ev-primary); }
.ev-tile-badge { align-self: flex-start; margin-bottom: 0.25rem; font-size: 0.8rem; font-weight: 700; color: var(--ev-primary); }
.ev-tile-badge-invalid { color: var(--ev-destructive); }
.ev-tile-note { margin: 0.35rem 0 0; font-size: 0.9rem; color: var(--ev-muted-foreground); white-space: pre-wrap; overflow-wrap: anywhere; }
.ev-tile-static { cursor: default; }
.ev-tile-demo { border-style: dashed; }
.ev-empty { padding: 1.5rem 0; color: var(--ev-muted-foreground); }

/* ===== The wall: book covers (events/_wall.html, WallTiles) =====
   咕 picked this from a rendered prototype (2026-09-23): 3:4 covers — ~6 a row at desktop width,
   never fewer than 2 on a phone (the min() keeps two columns where 168px would leave one) — with the
   cast row and the tally underneath. The cover is a physical object, so its colours do not follow the
   theme: the ink is the tile's inline --ev-book-ink (WallTiles.INKS), the type is cream (#f3ece0), the
   seal is vermilion; none of them is an --ev-* token. Every tile has the same height before any
   image arrives (aspect-ratio + a fixed-height row), so appending a page never moves what is above. */
.ev-books { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(168px, calc((100% - 18px) / 2)), 1fr)); gap: 22px 18px; }
.ev-book { display: flex; flex-direction: column; gap: 10px; min-width: 0; color: inherit; text-decoration: none; }
.ev-book:focus-visible { outline: 2px solid var(--ev-ring); outline-offset: 5px; border-radius: 6px; }
.ev-book-cover {
  position: relative; aspect-ratio: 3 / 4; border-radius: 4px 8px 8px 4px; overflow: hidden;
  color: #f3ece0; background: var(--ev-book-ink, #474440);
  /* the spine: a dark band and a one-pixel highlight on the left edge, then the drop shadow */
  box-shadow: inset 7px 0 0 rgba(0, 0, 0, 0.18), inset 8px 0 0 rgba(255, 255, 255, 0.06), 0 10px 22px -14px rgba(0, 0, 0, 0.55);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
/* light from the top right, and a faint paper grain */
.ev-book-cover::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 80% at 80% 0%, rgba(255, 255, 255, 0.12), transparent 60%),
              repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.025) 0 2px, transparent 2px 4px);
}
a.ev-book:hover .ev-book-cover, a.ev-book:focus-visible .ev-book-cover {
  transform: translateY(-4px) rotate(-0.4deg);
  box-shadow: inset 7px 0 0 rgba(0, 0, 0, 0.18), 0 18px 30px -16px rgba(0, 0, 0, 0.6);
}
/* ===== The entry's REAL cover over the generated one (the cover island, /islands/event-covers.js) =====
   The box's shape is the entry's cover kind (inline aspect-ratio: WORLD_COVER 16:9, BOOK_COVER 2:3 —
   WallTiles.Tile.aspect). The island mounts .ev-cover-drawn as the box's FIRST child, draws the app's
   own cover renderer in it, and only when that cover is complete (pictures loaded, type in) marks the
   box .is-drawn: the drawn layer fades in and the generated title / byline go transparent — still in
   the markup for screen readers and crawlers. Before that, and forever if it cannot draw, the reader
   sees the generated cover. Later siblings (seal, ribbon, flag, 18+) paint over the drawn layer. */
.ev-cover-drawn { position: absolute; inset: 0; z-index: 0; opacity: 0; pointer-events: none; transition: opacity 0.22s ease; }
.is-drawn > .ev-cover-drawn { opacity: 1; }
.is-drawn > .ev-book-title, .is-drawn > .ev-book-author, .is-drawn > .ev-mini-title { opacity: 0; }
/* A portrait (book) cover keeps its spine over the drawn picture; no grain or gloss touches the author's cover. */
.ev-book-cover.is-portrait.is-drawn::after { background: linear-gradient(90deg, rgba(0, 0, 0, 0.18) 0 7px, rgba(255, 255, 255, 0.06) 7px 8px, transparent 8px); }

/* A LANDSCAPE cover (a world's) is a card, not a book lying on its side: even corners, no spine, no
   gloss, a soft drop shadow; its generated title runs across the foot like the default design's
   (WORLD_FULL: the world's name bottom-left). No byline inside it — the WORLD designs print none, and
   the tile names the author on its credit line under the box (.ev-book-credit). */
.ev-book-cover.is-landscape { border-radius: 8px; box-shadow: 0 12px 26px -16px rgba(0, 0, 0, 0.6); }
.ev-book-cover.is-landscape::after { content: none; }
a.ev-book:hover .ev-book-cover.is-landscape, a.ev-book:focus-visible .ev-book-cover.is-landscape {
  transform: translateY(-3px); box-shadow: 0 20px 32px -18px rgba(0, 0, 0, 0.65);
}
.ev-book-cover.is-landscape .ev-book-title.is-horizontal {
  top: auto; left: 18px; right: 18px; bottom: 16px; font-size: 1.35rem; line-height: 1.25; -webkit-line-clamp: 2;
}
.ev-book-cover.is-landscape .ev-book-title.is-horizontal.is-m { font-size: 1.15rem; -webkit-line-clamp: 2; }
.ev-book-cover.is-landscape .ev-book-title.is-horizontal.is-s { font-size: 1rem; -webkit-line-clamp: 2; }
.ev-book-cover.is-landscape.has-mark .ev-book-title.is-horizontal { top: auto; }
.ev-book-cover.is-landscape .ev-book-age { top: 12px; bottom: auto; }
.ev-book-cover.is-drawn .ev-book-age { background: rgba(0, 0, 0, 0.55); color: #f3ece0; }
/* The landscape wall: one column on a phone (a 16:9 cover at half a phone's width shrinks its title
   below reading size), two on a tablet, four at desktop width — the default design's title stays
   ~20px or more at every one of them. */
.ev-books.is-landscape { grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr)); gap: 26px 20px; }

/* The title: vertical (right to left, top down) for a CJK title, horizontal for any other. The size
   steps (is-l / is-m / is-s, WallTiles.titleSize) shrink a long title before it can reach the byline;
   what still does not fit is clipped, never drawn over the byline. */
.ev-book-title { position: absolute; margin: 0; overflow: hidden; font-family: var(--ev-font-serif); font-weight: 700; color: inherit; }
.ev-book-title.is-vertical {
  top: 16px; right: 16px; max-height: 78%; max-width: calc(100% - 3.5rem);
  writing-mode: vertical-rl; font-size: 1.45rem; letter-spacing: 0.12em; line-height: 1.25;
}
.ev-book-title.is-vertical.is-m { font-size: 1.2rem; }
.ev-book-title.is-vertical.is-s { font-size: 1rem; letter-spacing: 0.08em; }
.ev-book-title.is-horizontal {
  top: 18px; left: 18px; right: 16px; font-size: 1.3rem; line-height: 1.22; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5;
}
.ev-book-title.is-horizontal.is-m { font-size: 1.1rem; -webkit-line-clamp: 6; }
.ev-book-title.is-horizontal.is-s { font-size: 0.95rem; -webkit-line-clamp: 7; }
/* A corner mark top-left pushes a title that would reach it down instead of sitting on it: every
   horizontal title, and a vertical one whose extra columns run leftwards along the top (is-wrap). */
.ev-book-cover.has-mark .ev-book-title.is-horizontal { top: 3.6rem; }
.ev-book-cover.has-mark .ev-book-title.is-vertical.is-wrap { top: 3.9rem; max-height: calc(78% - 2.9rem); }
.ev-book-author { position: absolute; left: 18px; bottom: 14px; overflow: hidden; font-size: 0.78rem; opacity: 0.85; }
.ev-book-author.is-vertical { max-height: 45%; writing-mode: vertical-rl; letter-spacing: 0.15em; }
/* 縱中橫: a one- or two-digit run stands upright in one cell of a vertical line (WallTiles.Run).
   The line's letter-spacing would otherwise widen the pair past the column. */
.ev-tcy { text-combine-upright: all; -webkit-text-combine: horizontal; letter-spacing: 0; }
.ev-book-author.is-horizontal { right: 16px; white-space: nowrap; text-overflow: ellipsis; }
.ev-book-cover.is-mature .ev-book-author.is-horizontal { right: 3.6rem; }

/* The award seal: a square vermilion stamp, set a little askew, for a label of up to three CJK
   characters; any longer label (every English one) takes the ribbon, which grows with its text. */
.ev-book-seal {
  position: absolute; left: 14px; top: 14px; display: grid; place-items: center; width: 2.6rem; height: 2.6rem;
  border: 2px solid #f3d9c9; border-radius: 6px; background: rgba(184, 53, 43, 0.55); color: #f3d9c9;
  font-family: var(--ev-font-serif); font-weight: 700; font-size: 0.78rem; line-height: 1.05; letter-spacing: 0.02em;
  text-align: center; transform: rotate(-6deg);
}
.ev-book-seal.is-three { font-size: 0.68rem; letter-spacing: 0; }
/* Width: clear of a vertical title's first column (right 16px + one column); a horizontal title has
   moved below the corner, so the ribbon may take the full width. */
.ev-book-ribbon {
  position: absolute; left: 12px; top: 12px; max-width: calc(100% - 4.25rem); padding: 3px 9px; border-radius: 999px;
  background: #b8352b; color: #f3ece0; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
  font-size: 0.7rem; font-weight: 700; line-height: 1.3; letter-spacing: 0.02em; overflow-wrap: anywhere;
}
.ev-book-cover.has-htitle .ev-book-ribbon, .ev-book-cover.has-htitle .ev-book-flag { max-width: calc(100% - 24px); }
/* The demo's and the invalid tile's label, in the same corner (neither ever holds an award). */
.ev-book-flag {
  position: absolute; left: 12px; top: 12px; max-width: calc(100% - 4.25rem); padding: 2px 8px; border-radius: 4px;
  background: rgba(243, 236, 224, 0.92); color: #4a3f35; font-size: 0.72rem; font-weight: 700; line-height: 1.4; letter-spacing: 0.04em;
}
.ev-book-age { position: absolute; right: 14px; bottom: 14px; padding: 1px 6px; border: 1px solid currentColor; border-radius: 4px; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; }

/* The demo: the same book, a dashed outline around it. */
.ev-book.is-demo .ev-book-cover { outline: 1.5px dashed var(--ev-primary); outline-offset: 4px; }
/* 未達標: unlinked, the ink drained to its own grey (relative colour; a flat grey where unsupported), the
   type dimmed, the label kept at full strength. */
.ev-book.is-invalid .ev-book-cover { background: #55524e; background: oklch(from var(--ev-book-ink, #474440) l 0 h); }
.ev-book.is-invalid .ev-book-title, .ev-book.is-invalid .ev-book-author { opacity: 0.62; }
.ev-book.is-invalid .is-drawn > .ev-book-title, .ev-book.is-invalid .is-drawn > .ev-book-author { opacity: 0; }
.ev-book.is-invalid .is-drawn > .ev-cover-drawn { filter: grayscale(1); opacity: 0.7; }
.ev-book.is-invalid .ev-book-flag { color: #b8352b; }
.ev-book-static { cursor: default; }

/* Directly under the cover: the credit line (WallTiles.Tile.creditLine) — the quill, then the author's
   own 署名 as stored, one line, ellipsized. A line of its own, pulled up close to the cover so it reads as
   the cover's byline: never on the row of faces, where a name would read as one more character and a
   long one would run into the tally. */
.ev-book-credit { display: flex; align-items: center; gap: 6px; min-width: 0; margin: -3px 0 0; font-size: 0.85rem; font-weight: 500; line-height: 1.4; color: var(--ev-foreground); }
.ev-credit-icon { flex-shrink: 0; width: 1em; height: 1em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ev-book-credit .ev-credit-icon { color: var(--ev-muted-foreground); }
.ev-credit-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ev-book.is-invalid .ev-book-credit { opacity: 0.62; }

/* Under the credit: the cast (overlapping faces, then「+N」) on the left, the tally on the right. */
.ev-book-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 26px; font-size: 0.78rem; }
.ev-book-cast { display: flex; min-width: 0; }
.ev-face {
  position: relative; display: inline-grid; place-items: center; flex-shrink: 0; width: 26px; height: 26px;
  overflow: hidden; border: 2px solid var(--ev-background); border-radius: 50%;
  background: var(--ev-accent); color: var(--ev-primary);
  font-family: var(--ev-font-serif); font-weight: 700; font-size: 0.72rem; line-height: 1;
}
.ev-face + .ev-face { margin-left: -8px; }
.ev-face img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The author's frame: the img is scaled past the circle and offset (inline style); the circle clips it. */
.ev-face img.ev-face-cropped { position: absolute; max-width: none; max-height: none; object-fit: fill; }
.ev-face-more { background: var(--ev-secondary); color: var(--ev-muted-foreground); font-family: var(--ev-font); }
.ev-book-votes { color: var(--ev-muted-foreground); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* 「✓ 已投」: the judging week's mark on a cover the signed-in visitor voted for (added by the round
   page's script from my-votes), where the tally sits once the results are out. */
.ev-book-voted { flex-shrink: 0; padding: 1px 8px; border-radius: 999px; background: var(--ev-primary); color: var(--ev-primary-foreground); font-weight: 700; white-space: nowrap; }

/* ===== The wall: character cards (wall_style = characters; events/_wall.html :: character) =====
   A round built around characters (share on + N public characters, no chapter) shows each entry as
   its lead character: a square portrait — the author's own frame applied, the same arithmetic as the
   entry page, which is why the box is square — with a hairline inner frame so it reads as a card, the
   name in the serif, then the world (a diamond in the entry's ink ties the card to its colour) and the
   byline. The portrait is artwork like the book cover: ink and cream do not follow the theme; the card
   body does (--ev-card / --ev-border). The cast row and the tally stay under the card in .ev-book-meta,
   where the round page's script appends「✓ 已投」. Every card has the same height before any image
   loads (aspect-ratio + a fixed body), so a load-more page never moves what is above it. */
.ev-books.is-characters { grid-template-columns: repeat(auto-fill, minmax(min(176px, calc((100% - 18px) / 2)), 1fr)); gap: 26px 18px; }
.ev-char {
  position: relative; display: flex; flex-direction: column; overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--ev-border) 45%, transparent); border-radius: 14px;
  background: var(--ev-card); color: var(--ev-card-foreground);
  box-shadow: 0 14px 26px -20px rgba(0, 0, 0, 0.5);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
a.ev-book:hover .ev-char, a.ev-book:focus-visible .ev-char {
  transform: translateY(-4px); border-color: var(--ev-primary); box-shadow: 0 22px 34px -20px rgba(0, 0, 0, 0.55);
}
.ev-char-portrait {
  position: relative; aspect-ratio: 1 / 1; overflow: hidden; color: #f3ece0;
  background: radial-gradient(120% 90% at 28% 12%, rgba(255, 255, 255, 0.16), transparent 62%), var(--ev-book-ink, #474440);
}
/* the card's frame, drawn over the picture: the portrait reads as a card, not as a cropped photo */
.ev-char-portrait::after {
  content: ""; position: absolute; inset: 8px; border: 1px solid rgba(243, 236, 224, 0.3); border-radius: 9px; pointer-events: none;
}
.ev-char-img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }
/* The author's frame: scaled past the square and offset (inline style); the portrait clips it. */
.ev-char-img.is-cropped { max-width: none; max-height: none; object-fit: fill; }
.ev-char-mono {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--ev-font-serif); font-weight: 700; font-size: 3.4rem; line-height: 1;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.2);
}
/* The corner marks are the book cover's own classes; on a portrait the「18+」sits top-right. */
.ev-char-portrait .ev-book-age { top: 14px; bottom: auto; background: rgba(0, 0, 0, 0.45); color: #f3ece0; }
.ev-char-portrait .ev-book-ribbon, .ev-char-portrait .ev-book-flag { max-width: calc(100% - 4.5rem); }
.ev-char-body { display: flex; flex-direction: column; gap: 2px; min-height: 5rem; padding: 11px 13px 13px; }
.ev-char-name {
  margin: 0; overflow: hidden; font-family: var(--ev-font-serif); font-weight: 700; font-size: 1.05rem; line-height: 1.35;
  white-space: nowrap; text-overflow: ellipsis;
}
.ev-char-world {
  margin: 3px 0 0; overflow: hidden; font-size: 0.8rem; line-height: 1.4; color: var(--ev-foreground);
  white-space: nowrap; text-overflow: ellipsis;
}
.ev-char-world::before {
  content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 7px 1px 1px; border-radius: 1.5px;
  background: var(--ev-book-ink, #474440); transform: rotate(45deg);
  /* a hairline in the text colour keeps a deep ink visible on the dark card */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--ev-foreground) 22%, transparent);
}
.ev-char-author { margin: 0; overflow: hidden; font-size: 0.76rem; line-height: 1.4; color: var(--ev-muted-foreground); white-space: nowrap; text-overflow: ellipsis; }
.ev-book.is-char .ev-book-meta { padding: 0 2px; }
/* The demo: the same card, a dashed outline around it. */
.ev-book.is-char.is-demo .ev-char { outline: 1.5px dashed var(--ev-primary); outline-offset: 4px; }
/* 未達標: unlinked, the portrait drained to grey, the text dimmed, the flag kept at full strength. */
.ev-book.is-char.is-invalid .ev-char-portrait { background: #55524e; background: oklch(from var(--ev-book-ink, #474440) l 0 h); }
.ev-book.is-char.is-invalid .ev-char-img { filter: grayscale(1); opacity: 0.7; }
.ev-book.is-char.is-invalid .ev-char-mono, .ev-book.is-char.is-invalid .ev-char-body { opacity: 0.62; }

/* The admin's draft preview (?preview=): a strip under the topbar, so the page is never mistaken for the live one. */
.ev-preview-banner { padding: 0.6rem 0; background: var(--ev-warning); color: var(--ev-primary-foreground); font-size: 0.9rem; font-weight: 700; }
html.dark .ev-preview-banner { color: var(--ev-background); }

/* Visually hidden, still read aloud (the image cover's byline). */
.ev-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* 「怎麼投票」above the wall in the judging week: three short rules in a quiet box. */
.ev-howto { max-width: 40rem; margin: 0 0 2rem; padding: 1rem 1.25rem; border: 1px solid var(--ev-border); border-radius: 0.5rem; background: var(--ev-muted); }
.ev-howto-heading { margin: 0 0 0.5rem; font-family: var(--ev-font-serif); font-size: 1.05rem; line-height: 1.4; }
.ev-howto-list { margin: 0; padding-left: 1.2rem; font-size: 0.925rem; line-height: 1.7; }
.ev-howto-list li + li { margin-top: 0.15rem; }

/* 「載入更多」under the wall: one outline button, centred; dimmed while its page is on the way. */
.ev-wall-more { display: flex; justify-content: center; margin-top: 2rem; }
.ev-wall-more .ev-btn { min-width: 12rem; }
.ev-wall-more .ev-btn[aria-busy="true"] { opacity: 0.6; cursor: progress; }

/* ===== The results: a podium (events/detail.html #awards, from results_at on) =====
   An awards ceremony rather than a list of cards: a warm spotlight from the top of the block, the
   heading centred between two gilt rules, then the placements on steps — FIRST in the middle, largest
   and highest; SECOND to its left and THIRD to its right, each set lower — and under them a gilt rule
   and the other awards as a centred row of medium covers. Every cover is the wall's own tile; a plaque
   under it carries the medal (placements), the award, the world, the byline and the judges' note.
   Medal gold / silver / bronze, the gilt and the award red are ornament colours, like the covers'
   inks: literal values, never --ev-* tokens (those must each equal an SPA token). Phones: FIRST across
   the whole row, SECOND and THIRD side by side under it. */
.ev-awards { position: relative; background: radial-gradient(56rem 24rem at 50% 0%, rgba(201, 162, 74, 0.17), transparent 72%); }
html.dark .ev-awards { background: radial-gradient(56rem 24rem at 50% 0%, rgba(214, 178, 94, 0.13), transparent 72%); }
.ev-awards-head { max-width: 42rem; margin: 0 auto 2.75rem; text-align: center; }
.ev-awards-heading {
  display: flex; align-items: center; justify-content: center; gap: 1rem; margin: 0;
  font-family: var(--ev-font-serif); font-weight: 700; font-size: clamp(1.6rem, 3.4vw, 2.3rem); line-height: 1.25;
}
.ev-awards-heading::before, .ev-awards-heading::after {
  content: ""; flex: 0 1 4rem; height: 1px; background: linear-gradient(90deg, transparent, #c9a24a);
}
.ev-awards-heading::after { background: linear-gradient(270deg, transparent, #c9a24a); }
.ev-awards-intro { margin: 1rem auto 0; }

.ev-podium { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; gap: 2.25rem 1rem; margin: 0 auto; padding: 0; list-style: none; }
.ev-podium-step { display: flex; flex-direction: column; align-items: center; flex: 0 1 calc(50% - 0.5rem); min-width: 0; }
.ev-podium-step.is-place-1 { flex-basis: 100%; }
.ev-podium-cover { width: 100%; max-width: 10.5rem; }
.ev-podium-step.is-place-1 .ev-podium-cover { max-width: 13.5rem; }
@media (min-width: 768px) {
  .ev-podium { flex-wrap: nowrap; gap: 0 2.75rem; }
  .ev-podium-step { flex: 0 1 13.5rem; }
  .ev-podium-step.is-place-1 { flex: 0 1 17rem; order: 2; }
  .ev-podium-step.is-place-2 { order: 1; padding-top: 3.25rem; }
  .ev-podium-step.is-place-3 { order: 3; padding-top: 5rem; }
  .ev-podium-cover { max-width: 12.5rem; }
  .ev-podium-step.is-place-1 .ev-podium-cover { max-width: 16rem; }
}
/* Landscape covers (a world's 16:9) need more width than a book to say the same thing: FIRST 26rem,
   SECOND / THIRD 20rem at desktop width; on a phone FIRST takes the row and the other two share one. */
.ev-podium.is-landscape .ev-podium-cover { max-width: 100%; }
.ev-podium.is-landscape .ev-podium-step.is-place-1 .ev-podium-cover { max-width: 100%; }
@media (min-width: 768px) {
  .ev-podium.is-landscape { gap: 0 2rem; }
  .ev-podium.is-landscape .ev-podium-step { flex: 0 1 20rem; }
  .ev-podium.is-landscape .ev-podium-step.is-place-1 { flex: 0 1 26rem; }
  .ev-podium.is-landscape .ev-podium-step.is-place-2 { padding-top: 2.5rem; }
  .ev-podium.is-landscape .ev-podium-step.is-place-3 { padding-top: 3.75rem; }
}
.ev-podium-step.is-place-1 .ev-book-cover.is-landscape {
  box-shadow: 0 0 0 1px rgba(201, 162, 74, 0.75), 0 26px 44px -22px rgba(0, 0, 0, 0.65);
}
.ev-honours.is-landscape { grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 18rem)); }
.ev-honours.is-landscape .ev-honour .ev-podium-cover { max-width: 18rem; }
/* The winner's cover: a gilt edge and a longer shadow (a book keeps its spine band; a character card
   has none — the band would sit on its white body); its title set larger for the larger book. */
.ev-podium-step.is-place-1 .ev-book-cover {
  box-shadow: inset 7px 0 0 rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(201, 162, 74, 0.75), 0 26px 44px -22px rgba(0, 0, 0, 0.65);
}
.ev-podium-step.is-place-1 .ev-char { border-color: rgba(201, 162, 74, 0.8); box-shadow: 0 26px 44px -22px rgba(0, 0, 0, 0.6); }
.ev-podium-step.is-place-1 .ev-book-title.is-vertical { font-size: 1.85rem; }
.ev-podium-step.is-place-1 .ev-book-title.is-vertical.is-m { font-size: 1.5rem; }
.ev-podium-step.is-place-1 .ev-book-title.is-vertical.is-s { font-size: 1.2rem; }
.ev-podium-step.is-place-1 .ev-book-title.is-horizontal { font-size: 1.6rem; }
.ev-podium-step.is-place-1 .ev-book-author { font-size: 0.9rem; }

/* The plaque under a cover. */
.ev-plaque { display: flex; flex-direction: column; align-items: center; gap: 0.1rem; width: 100%; margin-top: 1rem; text-align: center; }
.ev-medal {
  display: inline-grid; place-items: center; width: 2.1rem; height: 2.1rem; margin-bottom: 0.45rem; border-radius: 50%;
  font-family: var(--ev-font-serif); font-weight: 700; font-size: 1.05rem; line-height: 1;
  color: #3b2a07; background: radial-gradient(circle at 35% 30%, #f6e3a6, #c9a24a 58%, #9c7a2e);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.35), 0 3px 8px -3px rgba(0, 0, 0, 0.45);
}
.ev-podium-step.is-place-1 .ev-medal { width: 2.6rem; height: 2.6rem; font-size: 1.3rem; }
.ev-podium-step.is-place-2 .ev-medal { color: #2f3338; background: radial-gradient(circle at 35% 30%, #f4f6f8, #b9bfc6 58%, #8d949c); }
.ev-podium-step.is-place-3 .ev-medal { color: #3a1f0c; background: radial-gradient(circle at 35% 30%, #f1c9a3, #c07f4c 58%, #8f5a31); }
.ev-plaque-tier { margin: 0; font-family: var(--ev-font-serif); font-weight: 700; font-size: 1.15rem; line-height: 1.3; letter-spacing: 0.04em; color: #9a2b22; overflow-wrap: anywhere; }
html.dark .ev-plaque-tier { color: #e8836f; }
.ev-podium-step.is-place-1 .ev-plaque-tier { font-size: 1.5rem; }
.ev-plaque-title { margin: 0.3rem 0 0; font-weight: 700; font-size: 1rem; line-height: 1.35; overflow-wrap: anywhere; }
.ev-plaque-author { margin: 0; font-size: 0.85rem; line-height: 1.5; color: var(--ev-muted-foreground); overflow-wrap: anywhere; }
.ev-plaque-note {
  max-width: 17rem; margin: 0.7rem 0 0; padding: 0;
  font-family: var(--ev-font-serif); font-size: 0.92rem; line-height: 1.75; color: var(--ev-foreground);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
/* A gilt rule over the note, so it reads as the judges' words rather than more of the caption. */
.ev-plaque-note::before { content: ""; display: block; width: 1.75rem; height: 2px; margin: 0 auto 0.55rem; border-radius: 2px; background: #c9a24a; }

/* The other awards: medium covers, centred however many there are (auto-fit tracks capped at 12rem). */
.ev-honours {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(10rem, calc((100% - 1rem) / 2)), 12rem));
  justify-content: center; gap: 2.25rem 1rem; margin: 0 auto; padding: 0; list-style: none;
}
.ev-podium + .ev-honours { margin-top: 3.25rem; padding-top: 2.75rem; border-top: 1px solid rgba(201, 162, 74, 0.45); }
.ev-honour { display: flex; flex-direction: column; align-items: center; min-width: 0; }
.ev-honour .ev-podium-cover { max-width: 10rem; }
.ev-honour .ev-plaque-tier { font-size: 1rem; }
/* Phones: two per row. An auto-fit track sized by its 12rem cap fits only one on a 393px screen, so the
   columns are fixed here; an odd last award takes the whole row, centred like the rest. */
@media (max-width: 639px) {
  .ev-honours { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ev-honour:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (min-width: 768px) { .ev-honours { gap: 2.5rem 1.75rem; } }

/* ===== Prizes: rows, not a boxed table ===== */
.ev-prizes { width: 100%; max-width: 48rem; border-collapse: collapse; font-size: 1rem; }
.ev-prizes th, .ev-prizes td { padding: 0.9rem 0; text-align: left; vertical-align: top; border-bottom: 1px solid var(--ev-border); }
.ev-prizes th { font-size: 0.85rem; font-weight: 400; color: var(--ev-muted-foreground); padding-top: 0; }
.ev-prizes tr:last-child td { border-bottom: none; }
.ev-prizes td.ev-prize-label { font-weight: 700; padding-right: 1.5rem; }
.ev-prizes td.ev-num { white-space: nowrap; font-variant-numeric: tabular-nums; padding-right: 1.5rem; }
.ev-prizes td:last-child { padding-right: 0; }
.ev-prize-note { display: block; font-size: 0.85rem; font-weight: 400; color: var(--ev-muted-foreground); }
/* Narrow screens: one stacked row per prize, each numeric cell prefixed by its column name (data-label). */
@media (max-width: 639px) {
  .ev-prizes thead { display: none; }
  .ev-prizes, .ev-prizes tbody, .ev-prizes tr, .ev-prizes td { display: block; width: 100%; }
  .ev-prizes tr { padding: 0.9rem 0; border-bottom: 1px solid var(--ev-border); }
  .ev-prizes tr:last-child { border-bottom: none; }
  .ev-prizes td { padding: 0.1rem 0; border-bottom: none; }
  .ev-prizes td.ev-prize-label { margin-bottom: 0.25rem; }
  .ev-prizes td.ev-num { white-space: normal; }
  .ev-prizes td[data-label]::before { content: attr(data-label) "　"; color: var(--ev-muted-foreground); font-size: 0.85rem; }
  .ev-prize-note { display: block; margin-left: 0; }
}

/* ===== Rules / FAQ (admin markdown) ===== */
.ev-prose { max-width: 40rem; font-size: 1rem; line-height: 1.8; }
.ev-prose h2 { margin: 2rem 0 0.6rem; font-family: var(--ev-font-serif); font-size: 1.25rem; line-height: 1.35; }
.ev-prose h2:first-child { margin-top: 0; }
.ev-prose p { margin: 0 0 0.9em; }
/* The round's judging limit, stated from its setting above the admin's rules copy. */
.ev-judging-limit { max-width: 40rem; margin: 0 0 1.25rem; padding: 0.6rem 0.9rem; border-left: 3px solid var(--ev-warning); background: var(--ev-muted); font-size: 0.95rem; line-height: 1.6; }
.ev-prose ol, .ev-prose ul { margin: 0 0 1em; padding-left: 1.4rem; }
.ev-prose li { margin: 0.3rem 0; }
.ev-prose a { color: var(--ev-primary); text-decoration: underline; }

/* ===== The /events index: one full-width block per running round, a row per ended one ===== */
.ev-round { display: block; padding: 0 0 2.5rem; margin-bottom: 2.5rem; border-bottom: 1px solid var(--ev-border); color: inherit; }
.ev-round:last-child { padding-bottom: 0; margin-bottom: 0; border-bottom: none; }
.ev-round:hover h3, .ev-round:focus-visible h3 { color: var(--ev-primary); }
.ev-round:focus-visible { outline: 2px solid var(--ev-ring); outline-offset: 6px; border-radius: 0.25rem; }
.ev-round-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.5rem 1.5rem; margin-bottom: 0.5rem; }
.ev-round h3 { margin: 0 0 0.5rem; font-family: var(--ev-font-serif); font-size: clamp(1.75rem, 3.5vw, 2.5rem); line-height: 1.2; overflow-wrap: anywhere; }
.ev-round h3 { transition: color 0.2s; }
.ev-round-tagline { margin: 0; max-width: 40rem; color: var(--ev-muted-foreground); line-height: 1.7; }
.ev-round .ev-line { margin-top: 0.5rem; }
.ev-round-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.75rem 1.5rem; margin-top: 0.75rem; }
.ev-round-count { margin: 0; color: var(--ev-muted-foreground); }
.ev-row {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.75rem 2rem;
  padding: 1.5rem 0; border-top: 1px solid var(--ev-border);
}
.ev-row:first-child { border-top: none; padding-top: 0; }
.ev-row h3 { margin: 0 0 0.35rem; font-family: var(--ev-font-serif); font-size: 1.35rem; line-height: 1.3; overflow-wrap: anywhere; transition: color 0.2s; color: var(--ev-muted-foreground); }
a.ev-row:hover h3 { color: var(--ev-primary); }
.ev-row .ev-kicker { margin-bottom: 0.5rem; }
.ev-row-side { display: flex; flex-direction: column; align-items: flex-start; gap: 0.35rem; }
.ev-row-count { margin: 0; color: var(--ev-muted-foreground); }
.ev-row-cta { margin-top: 0.25rem; font-weight: 700; color: var(--ev-primary); }
@media (min-width: 768px) {
  .ev-row { grid-template-columns: minmax(0, 1fr) auto 14rem; }
  .ev-row-winners { grid-column: 2; align-self: center; }
  .ev-row-side { grid-column: 3; align-items: flex-end; text-align: right; }
}
/* An ended row's top three winners: small covers (events/_wall.html :: mini), the award under each. */
.ev-row-winners { display: flex; gap: 0.85rem; margin: 0; padding: 0; list-style: none; }
/* min-width 0: the three share a phone's row evenly — a long credit ellipsizes instead of widening its slot. */
.ev-row-winner { display: flex; flex-direction: column; align-items: center; gap: 0.4rem; width: 4.5rem; min-width: 0; }
.ev-row-winner-tier { max-width: 100%; font-size: 0.72rem; font-weight: 700; line-height: 1.3; text-align: center; color: #9a2b22; overflow-wrap: anywhere; }
html.dark .ev-row-winner-tier { color: #e8836f; }
/* The winner's credit, under its award: the same quill and as-stored name as the wall's credit line. */
.ev-row-winner-credit { display: flex; align-items: center; justify-content: center; gap: 3px; max-width: 100%; margin-top: -0.25rem; font-size: 0.7rem; line-height: 1.3; color: var(--ev-muted-foreground); }
.ev-mini {
  position: relative; display: block; width: 100%; aspect-ratio: 3 / 4; overflow: hidden; border-radius: 2px 5px 5px 2px;
  color: #f3ece0; background: var(--ev-book-ink, #474440);
  box-shadow: inset 4px 0 0 rgba(0, 0, 0, 0.18), 0 7px 14px -9px rgba(0, 0, 0, 0.6);
  transition: transform 0.18s ease;
}
a.ev-row:hover .ev-mini, a.ev-row:focus-visible .ev-mini { transform: translateY(-2px); }
.ev-mini.is-char { aspect-ratio: 1 / 1; border-radius: 10px; }
.ev-mini-title { position: absolute; overflow: hidden; font-family: var(--ev-font-serif); font-weight: 700; line-height: 1.2; }
.ev-mini-title.is-vertical { top: 7px; right: 7px; max-height: calc(100% - 14px); writing-mode: vertical-rl; font-size: 0.78rem; letter-spacing: 0.08em; }
.ev-mini-title.is-horizontal {
  top: 8px; left: 9px; right: 6px; font-size: 0.66rem; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5;
}
.ev-mini-art { position: absolute; inset: 0; display: block; width: 100%; height: 100%; max-width: none; object-fit: cover; }
.ev-mini-art.is-cropped { max-height: none; object-fit: fill; }
/* A landscape winner (a world's cover): wider than a book so the drawn cover still reads as one. */
.ev-row-winner.is-landscape { width: 7.5rem; }
.ev-mini.is-landscape { border-radius: 4px; box-shadow: 0 7px 14px -9px rgba(0, 0, 0, 0.6); }
.ev-mini.is-landscape .ev-mini-title.is-horizontal { top: auto; bottom: 6px; left: 8px; right: 6px; -webkit-line-clamp: 2; }
.ev-mini-mono { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--ev-font-serif); font-weight: 700; font-size: 1.6rem; line-height: 1; }

/* ===== The frozen entry page ===== */
.ev-entry-hero { padding: 2.5rem 0 2rem; }
/* The way back up: an arrow and the destination's name, above the title. */
.ev-back { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.9rem; color: var(--ev-muted-foreground); }
.ev-back:hover { color: var(--ev-primary); }
.ev-hero-head .ev-back, .ev-back-row { margin-bottom: 1.25rem; }
.ev-back-row { display: flex; flex-wrap: wrap; gap: 0.35rem 1.25rem; }
/* The world's real cover at the top of an entry page (the wall tile's box, unlinked). */
.ev-entry-cover { width: 100%; max-width: 40rem; margin: 0 0 1.5rem; }
.ev-entry-hero h1 { margin: 0 0 0.5rem; font-family: var(--ev-font-serif); font-size: clamp(2rem, 5vw, 3.25rem); line-height: 1.12; overflow-wrap: anywhere; }
.ev-entry-author { margin: 0 0 0.75rem; font-size: 1.05rem; color: var(--ev-muted-foreground); }
/* A winner's hero: per award, the wall's seal — solid here, the page is no ink cover — then the award
   and the judges' note. The stamp is the cover seal's shape (square, askew, a cream inner line). */
.ev-entry-prizes { display: flex; flex-direction: column; gap: 1.1rem; margin: 0.75rem 0 1.25rem; }
.ev-entry-prize { display: flex; align-items: flex-start; gap: 1.1rem; max-width: 40rem; }
.ev-seal {
  flex-shrink: 0; display: grid; place-items: center; width: 3.4rem; height: 3.4rem; margin-top: 0.15rem; border-radius: 7px;
  background: #b8352b; color: #f3ece0; transform: rotate(-6deg);
  box-shadow: inset 0 0 0 3px #b8352b, inset 0 0 0 4.5px rgba(243, 217, 201, 0.85), 0 7px 16px -9px rgba(0, 0, 0, 0.55);
  font-family: var(--ev-font-serif); font-weight: 700; font-size: 1rem; line-height: 1.05; letter-spacing: 0.02em; text-align: center;
}
.ev-seal.is-three { font-size: 0.84rem; letter-spacing: 0; }
.ev-ribbon {
  display: inline-block; padding: 3px 12px; border-radius: 999px; background: #b8352b; color: #f3ece0;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); font-family: var(--ev-font); font-size: 0.9rem; font-weight: 700; line-height: 1.4;
}
.ev-entry-prize-body { min-width: 0; }
.ev-entry-prize-label { margin: 0; font-family: var(--ev-font-serif); font-weight: 700; font-size: 1.4rem; line-height: 1.3; color: #9a2b22; }
html.dark .ev-entry-prize-label { color: #e8836f; }
.ev-entry-prize-note {
  margin: 0.4rem 0 0; padding-left: 0.9rem; border-left: 2px solid #c9a24a;
  font-family: var(--ev-font-serif); font-size: 0.98rem; line-height: 1.75; color: var(--ev-foreground);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
/* The participation prize on the author's own page (filled by the page's script). */
.ev-entry-participation { margin: 0 0 0.75rem; font-weight: 700; color: var(--ev-success); }
.ev-entry-participation[hidden] { display: none; }
.ev-entry-note { max-width: 34rem; margin: 0; font-size: 0.85rem; color: var(--ev-muted-foreground); }
.ev-vote { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1rem; margin: 1.25rem 0; }
.ev-vote-count { font-weight: 700; font-variant-numeric: tabular-nums; }
.ev-vote-state { font-size: 0.9rem; }
.ev-vote-error { width: 100%; font-size: 0.85rem; color: var(--ev-destructive); min-height: 1em; }
.ev-vote-error:empty { display: none; }
/* The same line also carries the one message that is not a refusal (the verification mail went out). */
.ev-vote-error[data-tone="info"] { color: var(--ev-foreground); }
/* Who may vote, stated before anyone presses; a full row under the button, quiet like the page's notes. */
.ev-vote-hint { width: 100%; max-width: 34rem; margin: 0; font-size: 0.85rem; line-height: 1.6; color: var(--ev-muted-foreground); }
/* A request on its way: dimmed, the wait cursor. The used-up state is disabled too, but it is an answer,
   not a wait — it reads as a plain outlined, muted button (.ev-btn-disabled) at full strength. */
.ev-vote-btn[aria-busy="true"], .ev-vote-resend[disabled] { opacity: 0.6; cursor: wait; }
.ev-vote-btn.ev-btn-disabled { cursor: not-allowed; }
/* Voted: the filled button is a state, not a control (「取消」next to it takes the vote back), so it
   keeps its fill under the pointer instead of the primary button's hover swap. */
/* The voted check is drawn, not typed: this face sets「✓」as a √-like radical. A mask keeps it in the
   text colour, and a pseudo-element survives the vote-box script resetting the label's textContent. */
.ev-book-voted::before, .ev-vote-btn.is-voted::before {
  content: ""; display: inline-block; width: 0.95em; height: 0.95em; margin-right: 0.3em; vertical-align: -0.12em;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%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 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / contain no-repeat;
}
.ev-vote-btn.is-voted, .ev-vote-btn.is-voted:hover { background: var(--ev-primary); border-color: var(--ev-primary); color: var(--ev-primary-foreground); cursor: default; }
/* 「取消」: a small text link beside the filled button. */
.ev-vote-cancel { padding: 0.25rem 0; border: 0; background: none; font: inherit; font-size: 0.9rem; color: var(--ev-muted-foreground); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.ev-vote-cancel:hover { color: var(--ev-foreground); }
.ev-vote-cancel:focus-visible { outline: 2px solid var(--ev-ring); outline-offset: 2px; border-radius: 2px; }
.ev-vote-cancel[disabled] { opacity: 0.6; cursor: wait; }
/* 「還剩 N 票（共 M 票）」beside the button. */
.ev-vote-left { font-size: 0.9rem; color: var(--ev-muted-foreground); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The participation prize's voting condition, met: a full row, the success ink. */
.ev-vote-participation { width: 100%; max-width: 34rem; margin: 0; font-size: 0.85rem; font-weight: 700; line-height: 1.6; color: var(--ev-success); }
/* .ev-btn's display:inline-flex would otherwise beat the UA's [hidden] rule. */
.ev-vote-resend[hidden], .ev-vote-cancel[hidden], .ev-vote-left[hidden], .ev-vote-participation[hidden] { display: none; }
.ev-entry-foot .ev-inner { display: flex; flex-direction: column; align-items: flex-start; gap: 1rem; }

/* 「← 上一件」「下一件 →」: two halves of one row, each the direction over the neighbour's title
   (cut to one line); an end of the list leaves its half empty, so「下一件」stays on the right. */
.ev-entry-nav { display: flex; gap: 1rem; width: 100%; max-width: 48rem; padding: 1rem 0; border-top: 1px solid var(--ev-border); border-bottom: 1px solid var(--ev-border); }
.ev-entry-nav-link { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; flex: 1 1 0; }
.ev-entry-nav-link.is-next { align-items: flex-end; text-align: right; margin-left: auto; }
.ev-entry-nav-dir { font-weight: 700; color: var(--ev-primary); }
.ev-entry-nav-title { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.875rem; color: var(--ev-muted-foreground); }
.ev-entry-nav-link:hover .ev-entry-nav-title { color: var(--ev-foreground); }
.ev-entry-nav-link:focus-visible { outline: 2px solid var(--ev-ring); outline-offset: 4px; border-radius: 2px; }

/* Character cards: avatar (the event's copy, cropped inline) or a monogram, notes, then the fields. */
.ev-char-head { display: flex; align-items: center; gap: 0.9rem; margin-bottom: 0.5rem; }
.ev-avatar { position: relative; display: block; flex-shrink: 0; width: 3.5rem; height: 3.5rem; border-radius: 999px; overflow: hidden; border: 1px solid var(--ev-border); background: var(--ev-muted); }
.ev-avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The author's frame: the img is scaled past the box and offset (inline style); the box clips it. */
.ev-avatar img.ev-avatar-cropped { position: absolute; max-width: none; max-height: none; object-fit: fill; }
.ev-avatar-monogram { display: flex; align-items: center; justify-content: center; font-family: var(--ev-font-serif); font-weight: 700; font-size: 1.35rem; color: var(--ev-primary); background: var(--ev-accent); }
.ev-char-title { min-width: 0; }
.ev-char-title h3 { margin: 0; }
.ev-entry-text { margin: 0; font-size: 0.95rem; line-height: 1.7; white-space: pre-wrap; overflow-wrap: anywhere; }
.ev-fields { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 0.3rem 0.9rem; margin: 0.75rem 0 0; font-size: 0.875rem; }
.ev-fields dt { color: var(--ev-muted-foreground); }
.ev-fields dd { margin: 0; overflow-wrap: anywhere; white-space: pre-wrap; }

/* The reader: a table of contents (only with more than one chapter), then each chapter at reading width. */
.ev-toc { list-style: none; max-width: 40rem; margin: 0 0 2.5rem; padding: 0; border-top: 1px solid var(--ev-border); }
.ev-toc li a { display: flex; justify-content: space-between; gap: 1rem; padding: 0.6rem 0; border-bottom: 1px solid var(--ev-border); }
.ev-toc li a:hover { color: var(--ev-primary); }
.ev-toc small { color: var(--ev-muted-foreground); white-space: nowrap; }
.ev-chapter { margin-bottom: 3.5rem; scroll-margin-top: 5.5rem; }
/* In-page jumps (去投票 / 看投稿牆 → #wall, 看得獎名單 → #awards, the entry page's chapter list) glide
   instead of snapping, and land clear of the sticky 3.5rem top bar. A reader who asked the system for
   less motion keeps the instant jump. Only the event pages load this sheet. */
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
#wall, #awards { scroll-margin-top: 4.5rem; }
.ev-chapter:last-child { margin-bottom: 0; }
.ev-chapter-head h3 { margin: 0 0 0.25rem; font-family: var(--ev-font-serif); font-size: 1.5rem; line-height: 1.3; }
.ev-chapter-head p { margin: 0 0 1.25rem; font-size: 0.875rem; }
.ev-chapter-text { max-width: 40rem; margin: 0; font-size: 1.05rem; line-height: 1.95; }
.ev-chapter-text p { margin: 0 0 1em; }
.ev-chapter-text img { max-width: 100%; height: auto; }
/* 章節插圖 (EntryFigures): its own line, centred — the editor's and the public reader's rule
   (frontend/src/index.css .chapter-figure). 滿版 = the column, 半寬 = half of it (the column on a
   phone), but never wider than the picture itself: the figure shrinks to its picture and the cap is a
   max-width, the img only scales down. The caption wraps under the picture (`width: 0; min-width:
   100%` keeps a long caption from widening the figure). A placeholder has no picture, so `100vw`
   pushes the figure to its cap and `max-width` brings the box back inside it. */
.ev-chapter-text figure { width: fit-content; max-width: 100%; margin: 1.5em auto; text-align: center; }
.ev-chapter-text figure[data-width="half"] { max-width: 50%; }
@media (max-width: 767px) { .ev-chapter-text figure[data-width="half"] { max-width: 100%; } }
.ev-chapter-text figure img { display: block; width: auto; max-width: 100%; height: auto; margin: 0 auto; border-radius: 0.5em; }
.ev-chapter-text figcaption { width: 0; min-width: 100%; margin-top: 0.4em; font-size: 0.875em; line-height: 1.5; color: var(--ev-muted-foreground); }
.ev-figure-placeholder {
  width: 100vw; max-width: 100%; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center; min-height: 9rem; padding: 1.25em 1em;
  border: 1px dashed var(--ev-border); border-radius: 0.5em; background: var(--ev-muted);
  color: var(--ev-muted-foreground); font-size: 0.875rem; line-height: 1.5;
}
.ev-cut-line { display: flex; align-items: center; gap: 0.75rem; max-width: 40rem; margin: 0.6rem 0; font-size: 0.9rem; font-weight: 700; line-height: 1.4; color: var(--ev-warning); }
/* A split chapter: the line sits between the two halves. The half before it drops its last bottom
   margin so the line hugs the text it follows — at a mid-paragraph cut the paragraph then carries on
   right under the line instead of reading as a new paragraph. */
.ev-chapter-text.is-split .ev-cut-before > :last-child { margin-bottom: 0; }
.ev-cut-line::before, .ev-cut-line::after { content: ""; flex: 1; border-top: 1px dashed var(--ev-warning); }

@media (prefers-reduced-motion: reduce) {
  .ev-btn, .ev-tile, .ev-tile h3, .ev-row h3, .ev-round h3, .ev-book-cover, .ev-mini { transition: none; }
  .ev-line-cat-tail { animation: none; }
}
