/*
 * Styles for the SSR /templates pages (Thymeleaf). Ports the layout of the old React
 * TemplatePage (landing.css + Tailwind) into plain CSS: page-background bands / tinted content
 * sections alternating, ink divider, preview table, HowTo step cards, CTA → /playground.
 * Served at /templates-assets/templates.css (mirrors /blog-assets/blog.css).
 *
 * Colour tokens. Every hex below IS an SPA token from frontend/src/index.css — the `@theme`
 * block for :root, the `.dark` block for html.dark — under the page's own variable names.
 * DesignTokenParityTest pins each pair, so a value changed on one side only fails the build;
 * change the SPA token and copy it here (the test names the variable and both values).
 *
 * The whole page follows the site theme: :root carries the SPA light value of every --tpl-<token>,
 * html.dark the dark one, and every section reads those names. --tpl-light-<token> is the light value
 * once more, never redefined: the relationship chart's downloaded PNG is light in both themes. The site footer is the one
 * surface that stays dark in both themes; it has its own sheet (shared/chrome/site-footer.css).
 *
 * html.dark is set before first paint by the inline <script> at the top of every /templates
 * page: the stored `litmemo-theme` choice wins, then the OS preference, and the fallback is
 * dark — the same order as readStoredTheme() in shared/src/lib/theme.ts, which the SPA boots
 * with.
 */

:root {
  color-scheme: light;
  --tpl-bg: #faf8f5;               /* background */
  --tpl-fg: #1a1a1a;               /* foreground */
  --tpl-card: #ffffff;             /* card */
  --tpl-primary: #7d6340;          /* primary */
  --tpl-primary-fg: #ffffff;       /* primary-foreground */
  --tpl-secondary: #f0ebe4;        /* secondary: first tinted section */
  --tpl-muted-bg: #f5f0ea;         /* muted: second tinted section, table stripes */
  --tpl-muted: #6b6159;            /* muted-foreground */
  --tpl-accent: #e8dfd4;           /* accent: third tinted section, table heads */
  --tpl-border: #9e8e7e;           /* border */
  --tpl-success: #0d7a54;          /* success: the copy button's "copied" state */
  /* The light set again, never redefined under html.dark: the relationship chart's PNG is drawn on paper in
     both themes ([data-rc-light] below points the themed names at these). */
  --tpl-light-bg: #faf8f5;
  --tpl-light-fg: #1a1a1a;
  --tpl-light-card: #ffffff;
  --tpl-light-primary: #7d6340;
  --tpl-light-primary-fg: #ffffff;
  --tpl-light-secondary: #f0ebe4;
  --tpl-light-muted-bg: #f5f0ea;
  --tpl-light-muted: #6b6159;
  --tpl-light-accent: #e8dfd4;
  --tpl-light-border: #9e8e7e;
  --tpl-font: "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, sans-serif;
  --tpl-font-serif: "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, serif;
}

html.dark {
  color-scheme: dark;
  --tpl-bg: #0f0d0a;
  --tpl-fg: #e8e0d4;
  --tpl-card: #1a1610;
  --tpl-primary: #c4a574;
  --tpl-primary-fg: #0f0d0a;
  --tpl-secondary: #241f18;
  --tpl-muted-bg: #241f18;
  --tpl-muted: #978b7b;
  --tpl-accent: #2e271d;
  --tpl-border: #504536;
  --tpl-success: #10b981;
}

/*
 * Per-language brand face. Each locale renders in its OWN Swei Spring Sugar regional variant,
 * so Japanese kana and Simplified glyphs come from the face that actually has them instead of
 * the Traditional face's substitutes.
 *
 * The family NAMES are not interchangeable: the generator emits "Swei Spring Sugar" (tc),
 * "Swei Spring Sugar SC" and "Swei Spring Sugar JP" as three separate families
 * (scripts/app_font_slices.py FAMILIES). A page that loads the SC stylesheet but asks for the
 * tc family name renders in the system fallback and looks merely "plain" — no error, no console
 * warning.
 *
 * KEEP IN SYNC with TemplateViewController.fontFamilyKey, which decides WHICH stylesheet the page
 * links, and with static/blog/blog.css + frontend/src/index.css, which carry the identical stacks.
 * `<html lang>` is emitted by the Thymeleaf templates from the URL prefix (zh-Hant / ja / en /
 * zh-Hans), so these selectors and that decision share one input.
 *
 * zh-Hant uses the :root stack above (tc), matching appFonts.ts; en uses the same tc stack with the
 * Latin punctuation face in front (the html[lang="en"] block below).
 * System faces trail each stack so text still paints while the slices stream in.
 */
html[lang="ja"] {
  --tpl-font: "Swei Spring Sugar JP", "Hiragino Maru Gothic ProN", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", system-ui, sans-serif;
  --tpl-font-serif: "Swei Spring Sugar JP", "Hiragino Mincho ProN", "Noto Serif JP", system-ui, serif;
}

/* English pages: "LM Latin Punctuation" (/fonts/latin-punctuation/latin-punctuation.css, linked only on
   English pages by PublicAppFonts.latinPunctuationStylesheet; U+2018-201F, U+2022, U+2026 only) in front of
   the tc stack, so curly quotes, the bullet and the ellipsis are Latin glyphs. Swei Spring Sugar is a CJK
   face and draws them full-width; CJK pages never name this family, so theirs are unchanged. */
html[lang="en"] {
  --tpl-font: "LM Latin Punctuation", "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, sans-serif;
  --tpl-font-serif: "LM Latin Punctuation", "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, serif;
}

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

/* Arabic pages (slice S5): the Arabic faces come from /fonts/arabic/arabic-fonts.css, linked only on
   Arabic pages (PublicAppFonts.arabicStylesheet) and limited to Arabic code points by unicode-range,
   so they lead the tc stack without touching Latin or digits. Sans (Noto Sans Arabic) for the
   interface, Naskh (Noto Naskh Arabic) for the serif / reading role. Arabic gets no letter-spacing
   (tracking breaks its joining) and no slanted text (docs/ui/ar-localization-guide.md). */
html[lang="ar"] {
  --tpl-font: "LM Noto Sans Arabic", "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, sans-serif;
  --tpl-font-serif: "LM Noto Naskh Arabic", "Swei Spring Sugar", "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", system-ui, serif;
}

html[lang="ar"] body * {
  /* !important: every per-component letter-spacing in this file would otherwise beat it. */
  letter-spacing: normal !important;
}

html[lang="ar"] :is(em, i, cite) {
  font-style: normal;
  font-weight: 700;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--tpl-font);
  color: var(--tpl-fg);
  background: var(--tpl-bg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

img { max-width: 100%; height: auto; }

.tpl-serif {
  font-family: var(--tpl-font-serif);
}

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

/* ===== Generic section helpers ===== */
.tpl-section { position: relative; overflow: hidden; padding: 4rem 1.25rem; }
/* Four surfaces, all themed: the page background (.tpl-section-base: hero, intro, filled example,
   the first mid CTA, how to fill in, related features, final CTA) and three tinted sections that
   step through secondary → muted → accent, so neighbours read as separate bands in both themes. */
.tpl-section-base { background: var(--tpl-bg); color: var(--tpl-fg); }
.tpl-section-light { background: var(--tpl-secondary); color: var(--tpl-fg); }
.tpl-section-light2 { background: var(--tpl-muted-bg); color: var(--tpl-fg); }
.tpl-section-light3 { background: var(--tpl-accent); color: var(--tpl-fg); }
/* Faint primary glow behind the page-background bands. The tint is the primary token at 6% via
   opacity on the pseudo-element, so no second hex is needed for the alpha version. */
.tpl-radial::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, var(--tpl-primary) 0%, transparent 70%);
  opacity: 0.06;
  pointer-events: none;
}
.tpl-inner { position: relative; z-index: 1; max-width: 56rem; margin: 0 auto; }
.tpl-inner-narrow { max-width: 48rem; }
.tpl-inner-wide { max-width: 72rem; }

/* Ink divider (_fragments :: inkDivider). The strokes read currentColor. Brown by default; the gold
   variant (inkDivider(true), on the page-background bands) is gold in the dark theme only: on the light
   page background the faint gold all but disappears, so it takes the brown there too. */
.tpl-divider { display: flex; align-items: center; justify-content: center; }
.tpl-ink { color: rgba(170, 145, 95, 0.4); }
html.dark .tpl-ink-gold { color: rgba(212, 168, 83, 0.45); }

/* Form field edge in the embedded tools (name generator, OC builder, relationship chart, including the chart
   island's Combobox through --color-input). Light theme: the border token, 3.2:1 on the card. Dark theme: the
   border token measures 1.9:1 on the dark card, so fields mix in 60% muted-foreground: 3.7:1 on the card,
   3.3:1 on the secondary band (WCAG 1.4.11 asks 3:1 for a field's edge). Card and table edges keep the token. */
.tpl-tool { --tpl-field-border: var(--tpl-border); }
html.dark .tpl-tool { --tpl-field-border: color-mix(in srgb, var(--tpl-muted) 60%, var(--tpl-border)); }

/* ===== Hero ===== */
.tpl-hero { padding-top: 5rem; padding-bottom: 3.5rem; text-align: center; }
.tpl-hero-annot {
  display: inline-block;
  color: var(--tpl-primary);
  opacity: 0.7;
  font-size: 1rem;
  transform: rotate(-3deg);
  margin: 1.4rem 0 0.6rem;
}
/* Light theme: the full primary. At 0.7 it measures 2.9:1 on the light page background; opaque it is 5.3. */
html:not(.dark) .tpl-hero-annot { opacity: 1; }
/* 墨墨 + one prop (_fragments :: heroMomo). A fixed 240×110 CSS-px figure, centred; max-width keeps it
   inside a 320px phone's column. Inks follow the theme with PetAvatar.tsx's two sets (.pet-ink / -light /
   .pet-eye): the body ink (--tpl-momo-ink) is `color`, so the cat's fills and the props' strokes read currentColor; the
   light ink and the eyes are the two classes below. Not --tpl-* tokens: these are the mascot's own inks,
   and DesignTokenParityTest only admits SPA colour tokens in :root / html.dark. */
.tpl-hero-momo {
  display: block;
  width: 240px;
  max-width: 100%;
  height: auto;
  margin: 0.4rem auto 1.2rem;
  --tpl-momo-ink: #6e5a44;
  --tpl-momo-ink-light: #8a7659;
  --tpl-momo-eye: #fdf6e3;
  color: var(--tpl-momo-ink);
}
html.dark .tpl-hero-momo {
  --tpl-momo-ink: #d4c5a9;
  --tpl-momo-ink-light: #bfb49a;
  --tpl-momo-eye: #1a1a1a;
}
.tpl-hero-momo .tpl-momo-ink-light { fill: var(--tpl-momo-ink-light); }
.tpl-hero-momo .tpl-momo-eye { fill: var(--tpl-momo-eye); }
.tpl-hero h1 {
  font-size: clamp(2rem, 6vw, 3.75rem);
  font-weight: 700;
  line-height: 1.15;
  margin: 0;
  color: var(--tpl-fg);
}
.tpl-hero-sub {
  margin: 1rem auto 0;
  max-width: 38rem;
  color: var(--tpl-muted);
  font-size: 1.05rem;
}

/* CTA button (hero, both mid CTAs, final, the embedded tools). Dark theme: the primary token with a
   shimmer whose highlight stop is primary lightened, not a hex of its own. Light theme: the block after
   this one. */
.tpl-cta-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 2rem;
  margin-top: 2rem;
  background: var(--tpl-primary);
  background: linear-gradient(110deg,
    var(--tpl-primary) 0%, var(--tpl-primary) 35%,
    color-mix(in srgb, var(--tpl-primary) 75%, white) 50%,
    var(--tpl-primary) 65%, var(--tpl-primary) 100%);
  background-size: 200% auto;
  color: var(--tpl-primary-fg);
  font-weight: 700;
  border-radius: 0.5rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  transition: box-shadow 0.3s, transform 0.3s;
  animation: tpl-shimmer 4s ease-in-out infinite;
}
.tpl-cta-btn:hover {
  box-shadow: 0 4px 24px color-mix(in srgb, var(--tpl-primary) 40%, transparent);
  transform: translateY(-2px);
}
.tpl-cta-btn svg { width: 1rem; height: 1rem; }
/* Light theme: the SPA landing's CTA gold (.landing-cta-btn, #d4a853 → #c4943c, ink #0f0d0a) as one solid
   fill: no shimmer, no glow, a card-edge shadow. Gold is the CTA's colour only; the light primary token
   (#7d6340) is the brown every other link and accent on the page uses. Hover darkens to the landing
   gradient's end stop (on paper, hover goes darker). Ink on gold measures 8.8:1 at rest, 7.1:1 on hover. */
html:not(.dark) .tpl-cta-btn {
  background: #d4a853;
  color: #0f0d0a;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
  animation: none;
}
html:not(.dark) .tpl-cta-btn:hover {
  background: #c4943c;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
  transform: translateY(-1px);
}
@keyframes tpl-shimmer {
  0% { background-position: 200% center; }
  100% { background-position: -200% center; }
}

/* ===== Intro / TLDR card ===== */
.tpl-intro { padding-top: 0; padding-bottom: 3.5rem; }
.tpl-intro-card {
  border: 1px solid var(--tpl-border);
  background: var(--tpl-card);
  border-radius: 1rem;
  padding: 2rem 1.75rem;
}
.tpl-intro-card p { margin: 0; color: var(--tpl-fg); font-size: 1.05rem; line-height: 1.9; }

/* ===== Section heading ===== */
.tpl-head { text-align: center; margin-bottom: 2.5rem; }
.tpl-head h2 {
  margin: 1.4rem 0 0;
  font-size: clamp(1.5rem, 4vw, 2.25rem);
  font-weight: 700;
  color: var(--tpl-fg);
}
.tpl-head .tpl-accent { color: var(--tpl-primary); }
.tpl-head p { margin: 0.75rem 0 0; color: var(--tpl-muted); font-size: 0.95rem; }
/* muted-foreground on the accent band measures 4.42 in the dark theme (AA is 4.5 for this
   0.95rem line), so the intro under a heading in the third band uses the full foreground. */
.tpl-section-light3 .tpl-head p { color: var(--tpl-fg); }

/* ===== Preview table ===== */
.tpl-table-wrap {
  overflow-x: auto;
  border-radius: 0.75rem;
  border: 1px solid var(--tpl-border);
  background: var(--tpl-card);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.tpl-table { width: 100%; border-collapse: collapse; text-align: start; font-size: 0.95rem; }
/* Said again on th: the UA centres a th whose inherited alignment is `start`, which a physical
   `left` on the table used to override and the logical value no longer does. */
.tpl-table th { text-align: start; }
.tpl-table thead tr { border-bottom: 1px solid var(--tpl-border); background: var(--tpl-accent); }
.tpl-table th[scope="col"] { padding: 0.75rem 1rem; font-weight: 700; color: var(--tpl-fg); }
.tpl-table th.tpl-col-field { width: 33%; min-width: 7rem; white-space: nowrap; }
.tpl-table tbody tr { border-bottom: 1px solid var(--tpl-border); }
.tpl-table tbody tr:last-child { border-bottom: 0; }
.tpl-table tbody tr.tpl-odd { background: var(--tpl-muted-bg); }
.tpl-table th[scope="row"] {
  padding: 0.75rem 1rem;
  font-weight: 600;
  color: var(--tpl-fg);
  vertical-align: top;
  white-space: nowrap;
}
.tpl-table td { padding: 0.75rem 1rem; color: var(--tpl-fg); }
/* Below desktop the nowrap labels above take whatever they need, and the long ones (beat-sheet,
   dialogue-voice-sheet, ~450px on one line) leave the example column a sliver or push the table
   into a sideways scroll. Here the preview table switches to a fixed split instead — label ~38%,
   example the rest — and the labels wrap. Desktop (≥1024px, where the 56rem column has room)
   keeps the one-line labels. CJK wraps between characters with the browser's kinsoku rules;
   Latin wraps at spaces, and break-word only splits a single word too long for the cell.
   Scoped off the field guide: it has three columns and its own phone layout (cards, below). */
@media (max-width: 1023px) {
  .tpl-table:not(.tpl-table-guide) { table-layout: fixed; }
  .tpl-table:not(.tpl-table-guide) th.tpl-col-field { width: 38%; min-width: 0; white-space: normal; }
  .tpl-table:not(.tpl-table-guide) th[scope="row"],
  .tpl-table:not(.tpl-table-guide) td { white-space: normal; overflow-wrap: break-word; }
}
@media (max-width: 479px) {
  /* 1rem a side eats 64px of a ~290px table at 320; the label column needs that room more. */
  .tpl-table:not(.tpl-table-guide) th,
  .tpl-table:not(.tpl-table-guide) td { padding-inline: 0.75rem; }
}

/* ===== Hero image (optional illustration under the intro) ===== */
.tpl-hero-figure { padding-top: 0; padding-bottom: 3.5rem; }
.tpl-figure { margin: 0; text-align: center; }
.tpl-figure img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 auto;
  border-radius: 1rem;
  border: 1px solid var(--tpl-border);
  background: var(--tpl-card);
}
.tpl-figure figcaption { margin: 0.9rem auto 0; max-width: 36rem; color: var(--tpl-muted); font-size: 0.9rem; }

/* ===== Mid-page CTA bands (after the filled example, after the downloads) =====
   A compact coda of the section above it: same surface, no top padding (that section's bottom padding
   is the gap), one lead line and the page's CTA button. */
.tpl-mid-cta { padding-top: 0; padding-bottom: 3rem; text-align: center; }
/* The section above keeps its own bottom padding as the gap, trimmed so the band reads as its last
   line (restated for desktop in the Responsive block, where .tpl-section grows to 6rem). */
.tpl-hero-figure:has(+ .tpl-mid-cta) { padding-bottom: 2rem; }
.tpl-downloads:has(+ .tpl-mid-cta) { padding-bottom: 1.25rem; }
.tpl-mid-cta-lead { margin: 0; color: var(--tpl-muted); font-size: 0.95rem; }
.tpl-mid-cta .tpl-cta-btn { margin-top: 0.9rem; }
/* The downloads band sits on a tinted surface; a card-edge shadow there instead of the button's
   default drop shadow, which reads as a smudge on the tinted band. */
.tpl-section-light2.tpl-mid-cta .tpl-cta-btn { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }

/* ===== Downloads (compact row of buttons under the preview table) ===== */
.tpl-downloads { padding-top: 2.5rem; padding-bottom: 2.5rem; }
.tpl-head-compact { margin-bottom: 1.5rem; }
.tpl-head-compact h2 { margin-top: 0; font-size: clamp(1.25rem, 3vw, 1.6rem); }
.tpl-download-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem; }
.tpl-download-btn {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.6rem 1.1rem; border-radius: 0.5rem;
  border: 1px solid var(--tpl-border);
  background: var(--tpl-card);
  color: var(--tpl-primary); font-weight: 600; font-size: 0.9rem;
  transition: background 0.2s, border-color 0.2s;
}
.tpl-download-btn:hover { background: var(--tpl-muted-bg); border-color: var(--tpl-primary); }
.tpl-download-btn svg { width: 0.9rem; height: 0.9rem; }

/* ===== Field-by-field guide (one H3 + one 3-column table per group) ===== */
.tpl-guide-group + .tpl-guide-group { margin-top: 2.5rem; }
.tpl-guide-group-title { margin: 0 0 1rem; font-size: 1.25rem; font-weight: 700; color: var(--tpl-fg); }
/* The preview table gives its row-header column a third of the width; with three columns that
   starves the two text columns, so the guide table hands the space back. Cells keep a floor so
   a phone scrolls the table sideways (the wrap is overflow-x: auto) instead of squeezing three
   columns into one character each. */
.tpl-table-guide th.tpl-col-field { width: 18%; }
.tpl-table-guide td { min-width: 9rem; vertical-align: top; }
.tpl-table-guide td + td { color: var(--tpl-muted); }
/* Phones: three columns at 320px would scroll sideways, and this is the page's main SEO
   section — stack each row into a card instead, captioning the two text cells with their
   column label (the <td data-label> the view emits). The <thead> is hidden, not removed, so
   the table keeps its semantics for assistive tech. */
@media (max-width: 639px) {
  .tpl-table-guide thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .tpl-table-guide, .tpl-table-guide tbody, .tpl-table-guide tr,
  .tpl-table-guide th[scope="row"], .tpl-table-guide td { display: block; }
  .tpl-table-guide tr { padding: 0.9rem 1rem; }
  .tpl-table-guide th[scope="row"] { padding: 0 0 0.35rem; white-space: normal; font-size: 1.02rem; color: var(--tpl-fg); }
  .tpl-table-guide td { padding: 0.35rem 0 0; min-width: 0; }
  .tpl-table-guide td::before {
    content: attr(data-label);
    display: block;
    font-size: 0.75rem;
    color: var(--tpl-muted);
    margin-bottom: 0.1rem;
  }
}

/* ===== Plain-text copy block =====
   Narrow screens: the button sits above the block, right-aligned (a corner button would eat a
   third of a 320px line). From 640px up it moves into the top-right corner and the <pre>
   reserves that corner, so a long first line runs under nothing. */
.tpl-copy-wrap { position: relative; display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem; }
.tpl-copy {
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 1.5rem 1.25rem;
  /* Reads as part of the page: the same card surface as the tables, not a code editor. */
  background: var(--tpl-card);
  border: 1px solid var(--tpl-border);
  border-radius: 0.75rem;
  color: var(--tpl-fg);
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, var(--tpl-font), monospace;
  font-size: 0.9rem;
  line-height: 1.75;
  white-space: pre-wrap;      /* keep the author's line breaks, wrap the long ones */
  overflow-wrap: anywhere;    /* a long URL or CJK run cannot force horizontal scroll */
  max-height: 28rem;
  overflow-y: auto;
}
.tpl-copy-btn {
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--tpl-border);
  background: var(--tpl-card);
  color: var(--tpl-primary);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
/* The button ships `hidden` and only the inline script reveals it; without this rule the
   display value above would override the UA's [hidden] and show a button that cannot work. */
.tpl-copy-btn[hidden] { display: none; }
.tpl-copy-btn:hover { background: var(--tpl-muted-bg); border-color: var(--tpl-primary); }
.tpl-copy-btn-done { color: var(--tpl-success); border-color: var(--tpl-success); }

/* ===== Embedded name generator (templates/tools/name-generator.html) =====
   Controls wrap onto their own lines on phones; the result list is two columns from 640px up.
   The copy buttons reuse .tpl-copy-btn but stay in the row (the copy block's ≥640px rule pins
   .tpl-copy-btn absolutely into a corner — the two-class selector here outranks it). */
.tpl-namegen-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 1rem 1.5rem;
  margin-bottom: 1.5rem;
}
.tpl-namegen-field { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.tpl-namegen-field > label, .tpl-namegen-gender legend { font-size: 0.85rem; font-weight: 600; color: var(--tpl-muted); }
.tpl-namegen-select {
  font: inherit;
  padding: 0.55rem 0.8rem;
  border-radius: 0.5rem;
  border: 1px solid var(--tpl-field-border);
  background: var(--tpl-card);
  color: var(--tpl-fg);
  min-width: 12rem;
}
.tpl-namegen-gender { border: 0; padding: 0; margin: 0; flex-direction: row; flex-wrap: wrap; gap: 0.4rem 1rem; }
.tpl-namegen-gender legend { padding: 0; margin-bottom: 0.4rem; width: 100%; }
.tpl-namegen-gender label { display: inline-flex; align-items: center; gap: 0.35rem; cursor: pointer; }
/* The select and the radio row share one control height: the controls row aligns its groups at the
   bottom (flex-end), so equal-height controls are what put「世界觀」and「性別」on the same line
   (a 22px radio row left 性別 ~16px lower). Radios that wrap on a phone simply grow the row. */
/* No vertical padding inside the fixed height: WebKit keeps the inherited line-height inside a
   <select>, and 2 x 0.55rem of padding left too little room — the label's lower half was cut off. */
.tpl-namegen-select { box-sizing: border-box; height: 2.5rem; padding-block: 0; line-height: normal; }
.tpl-namegen-gender label { min-height: 2.5rem; }
.tpl-namegen-gender input { accent-color: var(--tpl-primary); margin: 0; }
.tpl-namegen-draw { border: 0; cursor: pointer; font: inherit; }
.tpl-namegen-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
}
.tpl-namegen-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.7rem 1rem;
  border: 1px solid var(--tpl-border);
  border-radius: 0.6rem;
  background: var(--tpl-card);
}
.tpl-namegen-name { font-size: 1.2rem; font-weight: 700; color: var(--tpl-fg); overflow-wrap: anywhere; }
.tpl-namegen .tpl-copy-btn { position: static; flex-shrink: 0; }
/* 「用這個名字建角色」— a link into the sandbox, styled as the row's primary action. On a narrow
   row (phones, the two-column grid's half width) the actions wrap under the name instead of
   squeezing it: the item wraps, and the name takes the leftover space. */
.tpl-namegen-item { flex-wrap: wrap; }
/* The name and, for Japanese kanji names, its reading stacked under it: one box takes the row's
   leftover space, so a row with a reading lays out like one without. */
/* The label takes the whole first line, so every row puts its two actions on the line below: with
   names of different lengths (and the longer ja / en button) the rows otherwise wrap differently
   from one row to the next. */
.tpl-namegen-label { flex: 1 0 100%; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.tpl-namegen-reading { font-size: 0.8rem; color: var(--tpl-muted); overflow-wrap: anywhere; }
.tpl-namegen-use {
  flex-shrink: 0;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  background: var(--tpl-primary);
  color: var(--tpl-primary-fg);
  font-size: 0.8rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
/* When the row wraps (phones), the copy button stays on the end edge (right in LTR, left in RTL) under the link. */
.tpl-namegen-use + .tpl-copy-btn { margin-inline-start: auto; }
.tpl-namegen-use:hover { filter: brightness(1.08); }
.tpl-namegen-use:focus-visible { outline: 2px solid var(--tpl-primary); outline-offset: 2px; }
@media (min-width: 640px) {
  .tpl-namegen-list { grid-template-columns: repeat(2, 1fr); }
}

/* ===== Embedded OC builder (templates/tools/oc-builder.html + the /islands/oc-builder.js island) =====
   Server-rendered: the field list (.tpl-ocb-guide) and the filled-in example. The island replaces
   the guide with .tpl-ocb-app: the side column (buttons, card, picture, Keep), the phone-only mini
   bar, and the form.

   Phones (≤768px): one flex column, card first, then the mini bar, the form and Keep. The mini bar
   sticks below the fixed top bar once the card has scrolled away (the island shows it then).
   A FLEX column, not a grid: a sticky element only travels inside its containing block, and a grid
   item's containing block is its own grid area — one row as tall as the bar, so it would never move.

   Wider: two columns, the side column sticks below the fixed top bar and scrolls on its own when it is
   taller than the window (the island scales the card to fit one window first).

   Why this section is `overflow: clip` and not the `.tpl-section` default `hidden`: `hidden` makes
   the section a scroll container, and a sticky element sticks to its nearest scroll container — the
   section never scrolls, so the column used to leave the screen with the rest of the page. `clip`
   still clips the decorations without being a scroll container. `min-width: 0` on the tracks lets a
   long word wrap instead of widening the page. */
.tpl-section.tpl-ocb { overflow: clip; }
.tpl-ocb-guide h3, .tpl-ocb-example h3 { font-size: 1.35rem; margin: 0 0 0.75rem; color: var(--tpl-fg); }
.tpl-ocb-guide h4 { margin: 1.25rem 0 0.4rem; font-size: 1rem; color: var(--tpl-primary); }
.tpl-ocb-dl { margin: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.tpl-ocb-dl-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.1rem 1rem; }
.tpl-ocb-dl dt { font-weight: 600; color: var(--tpl-fg); }
.tpl-ocb-dl dd { margin: 0; color: var(--tpl-muted); font-size: 0.9rem; }
.tpl-ocb-example { margin-top: 3rem; }
.tpl-ocb-example p { color: var(--tpl-muted); margin: 0 0 1rem; }

.tpl-ocb-app { display: flex; flex-direction: column; gap: 1.5rem; }
.tpl-ocb-form { min-width: 0; display: flex; flex-direction: column; gap: 1.5rem; }
.tpl-ocb-mode, .tpl-ocb-section { border: 0; padding: 0; margin: 0; min-width: 0; }
.tpl-ocb-mode { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tpl-ocb-mode legend { width: 100%; padding: 0; margin-bottom: 0.5rem; font-size: 0.85rem; font-weight: 600; color: var(--tpl-muted); }
.tpl-ocb-mode label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--tpl-border);
  border-radius: 999px;
  background: var(--tpl-card);
  cursor: pointer;
  font-size: 0.9rem;
}
.tpl-ocb-mode label.is-on { border-color: var(--tpl-primary); color: var(--tpl-primary); font-weight: 700; }
.tpl-ocb-mode input { accent-color: var(--tpl-primary); margin: 0; }
.tpl-ocb-section { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.9rem; }
.tpl-ocb-section legend { padding: 0; margin-bottom: 0.25rem; font-size: 1.15rem; font-weight: 700; color: var(--tpl-primary); }
.tpl-ocb-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.tpl-ocb-field label { font-size: 0.9rem; font-weight: 600; color: var(--tpl-fg); }
.tpl-ocb-hint { font-size: 0.8rem; color: var(--tpl-muted); }
.tpl-ocb-field input {
  font: inherit;
  width: 100%;
  box-sizing: border-box;
  padding: 0.55rem 0.75rem;
  border-radius: 0.5rem;
  border: 1px solid var(--tpl-field-border);
  background: var(--tpl-card);
  color: var(--tpl-fg);
}
/* Full muted-foreground: 6.0:1 on the light card, 5.4:1 on the dark one (at 0.75 opacity it was about 4:1). */
.tpl-ocb-field input::placeholder { color: var(--tpl-muted); opacity: 1; }
.tpl-ocb-field input:focus { outline: 2px solid var(--tpl-primary); outline-offset: 1px; }

.tpl-ocb-side { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 0.75rem; }
.tpl-ocb-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; width: 100%; }
.tpl-ocb-btn {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  padding: 0.5rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--tpl-primary);
  background: var(--tpl-card);
  color: var(--tpl-primary);
  cursor: pointer;
}
.tpl-ocb-btn:hover:not(:disabled) { background: var(--tpl-muted-bg); }
.tpl-ocb-btn-quiet { border-color: var(--tpl-border); color: var(--tpl-muted); }
.tpl-ocb-btn:disabled, .tpl-ocb-keep-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.tpl-ocb-status { flex-basis: 100%; margin: 0; min-height: 1.25rem; font-size: 0.85rem; color: var(--tpl-muted); }
/* An empty live region keeps its place in the DOM (screen readers) but takes no height: every px
   above the card is a px the card cannot use (the island fits the card under the buttons). */
.tpl-ocb-actions .tpl-ocb-status:empty { min-height: 0; margin-top: -0.5rem; }
.tpl-ocb-status-error { color: var(--tpl-fg); }
.tpl-ocb-fallback {
  flex-basis: 100%;
  width: 100%;
  box-sizing: border-box;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 0.8rem;
  border: 1px solid var(--tpl-border);
  border-radius: 0.5rem;
  background: var(--tpl-card);
  color: var(--tpl-fg);
}
/* The label row: "Card preview" and, wider than 768px, the「click to enlarge」button beside it. */
.tpl-ocb-preview-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.75rem; width: 100%; margin-top: 0.25rem; }
.tpl-ocb-preview-label { margin: 0; font-size: 0.85rem; font-weight: 600; color: var(--tpl-muted); }
.tpl-ocb-zoom-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--tpl-border);
  border-radius: 999px;
  background: var(--tpl-card);
  color: var(--tpl-primary);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.5;
  cursor: zoom-in;
}
.tpl-ocb-zoom-btn:hover { background: var(--tpl-muted-bg); }
.tpl-ocb-zoom-btn:focus-visible { outline: 2px solid var(--tpl-primary); outline-offset: 2px; }
/* The island sets this box's width (and height) to the card's drawn size; the renderer fills it. */
.tpl-ocb-card { position: relative; width: 100%; max-width: 26rem; flex: none; border-radius: 0.75rem; overflow: hidden; box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12); }
.tpl-ocb-card-zoomable { cursor: zoom-in; }

/* The enlarged card: a native modal <dialog> filling the window (sized in %, which in the top layer is
   the viewport — no vh). The close button sits outside the scroll box so it is always reachable; the
   body scrolls when the card is taller than the window, and a click on it (outside the card) closes. */
.tpl-ocb-zoom {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--tpl-fg);
  overflow: hidden;
}
.tpl-ocb-zoom::backdrop { background: rgba(10, 9, 8, 0.72); }
.tpl-ocb-zoom-body {
  box-sizing: border-box;
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4rem 2rem 2rem;
  cursor: zoom-out;
}
.tpl-ocb-zoom-card { flex: none; border-radius: 0.75rem; overflow: hidden; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35); cursor: default; }
.tpl-ocb-zoom-close {
  position: absolute;
  top: 1rem;
  inset-inline-end: 1rem;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--tpl-border);
  border-radius: 999px;
  background: var(--tpl-card);
  color: var(--tpl-fg);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}
.tpl-ocb-zoom-close:hover { background: var(--tpl-muted-bg); }
.tpl-ocb-zoom-close:focus-visible { outline: 2px solid var(--tpl-primary); outline-offset: 2px; }
/* The portrait doubles as the「pick a picture」button: an invisible hit area over it. */
.tpl-ocb-portrait-hit {
  position: absolute;
  z-index: 2;
  padding: 0;
  border: 0;
  border-radius: 0.4rem;
  background: transparent;
  cursor: pointer;
}
.tpl-ocb-portrait-hit:hover { background: rgba(255, 255, 255, 0.18); }
.tpl-ocb-portrait-hit:focus-visible { outline: 2px solid var(--tpl-primary); outline-offset: 2px; }
.tpl-ocb-avatar { display: flex; flex-direction: column; gap: 0.35rem; width: 100%; }
.tpl-ocb-avatar-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tpl-ocb-avatar-hint { margin: 0; font-size: 0.8rem; color: var(--tpl-muted); }
/* Opened through the buttons / the portrait; kept in the layout (not display:none) so .click() works everywhere. */
.tpl-ocb-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.tpl-ocb-keep { display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem; }
.tpl-ocb-keep-btn { border: 0; cursor: pointer; font: inherit; font-weight: 700; margin-top: 0.5rem; white-space: normal; text-align: center; }
.tpl-ocb-keep-note { margin: 0; font-size: 0.85rem; color: var(--tpl-muted); }

/* Phones: the mini bar — a thumbnail of the card's top + the name, below the fixed top bar (56px). */
.tpl-ocb-mini { position: sticky; top: 56px; z-index: 20; margin: 0 -1.25rem; }
.tpl-ocb-mini[hidden] { display: none; }
.tpl-ocb-mini-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 3.5rem;
  padding: 0.4rem 1.25rem;
  border: 0;
  border-bottom: 1px solid var(--tpl-border);
  background: var(--tpl-card);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  font: inherit;
  color: var(--tpl-fg);
  text-align: start;
  cursor: pointer;
}
.tpl-ocb-mini-thumb { flex: none; width: 48px; height: 48px; overflow: hidden; border-radius: 0.4rem; border: 1px solid var(--tpl-border); background: var(--tpl-muted-bg); }
.tpl-ocb-mini-name { flex: 1; min-width: 0; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tpl-ocb-mini-action { flex: none; font-size: 0.85rem; font-weight: 600; color: var(--tpl-primary); }
.tpl-ocb-mini-panel {
  display: flex;
  justify-content: center;
  padding: 0.75rem 1.25rem 1rem;
  max-height: calc(100dvh - 56px - 3.5rem);
  overflow-y: auto;
  background: var(--tpl-muted-bg);
  border-bottom: 1px solid var(--tpl-border);
}

@media (min-width: 640px) {
  .tpl-ocb-dl-row { grid-template-columns: minmax(10rem, 16rem) minmax(0, 1fr); }
}
@media (min-width: 640px) and (max-width: 768px), (min-width: 1100px) {
  .tpl-ocb-section { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tpl-ocb-section legend { grid-column: 1 / -1; }
}
@media (min-width: 769px) {
  .tpl-ocb-app { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 22rem); gap: 2rem; align-items: start; }
  .tpl-ocb-form { grid-column: 1; grid-row: 1; }
  .tpl-ocb-side {
    grid-column: 2;
    grid-row: 1;
    /* Clears the fixed site top bar (56px); the island's STICKY_TOP_PX / BOTTOM_GAP_PX match these. */
    position: sticky;
    top: 4.5rem;
    max-height: calc(100vh - 5.5rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-bottom: 0.25rem;
  }
}

/* ===== Extra prose sections ===== */
.tpl-extra .tpl-divider { margin-bottom: 2rem; }
.tpl-extra-section + .tpl-extra-section { margin-top: 2.5rem; }
.tpl-extra-section h3 { margin: 0 0 0.75rem; font-size: 1.35rem; font-weight: 700; color: var(--tpl-fg); }
.tpl-extra-section p { margin: 0 0 1rem; color: var(--tpl-fg); font-size: 1.02rem; line-height: 1.85; }
.tpl-extra-section ul { margin: 0 0 1rem; padding-inline-start: 1.4rem; color: var(--tpl-fg); font-size: 1.02rem; line-height: 1.85; }
.tpl-extra-section li { margin: 0.2rem 0; }
.tpl-extra-section li::marker { color: var(--tpl-primary); }
/* Section image after the paragraphs: a little air above, none below (the next section's margin
   already separates them). Inherits .tpl-figure's max-width:100% / height:auto, so it never
   overflows the narrow column on a phone. */
.tpl-extra-figure { margin: 1.5rem 0 0; }

/* ===== Usage guide ===== */
.tpl-guide p {
  color: var(--tpl-muted);
  font-size: 1.05rem;
  margin: 0 0 1.25rem;
}

/* ===== HowTo steps ===== */
.tpl-steps-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}
.tpl-step-card {
  position: relative;
  border: 1px solid var(--tpl-border);
  background: var(--tpl-card);
  border-radius: 1rem;
  padding: 1.75rem 1.5rem 1.5rem;
  transition: border-color 0.3s, box-shadow 0.3s;
}
.tpl-step-card:hover { border-color: var(--tpl-primary); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); }
.tpl-step-badge {
  position: absolute;
  top: -0.75rem;
  inset-inline-start: 1.5rem;
  background: var(--tpl-primary);
  color: var(--tpl-primary-fg);
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.15rem 0.75rem;
  border-radius: 999px;
}
.tpl-step-card h3 { margin: 0.5rem 0 0.5rem; font-size: 1.1rem; font-weight: 700; color: var(--tpl-fg); }
.tpl-step-card p { margin: 0; font-size: 0.9rem; color: var(--tpl-muted); }

/* ===== Related templates ===== */
.tpl-related-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
.tpl-related-card {
  display: block;
  background: var(--tpl-card);
  border: 1px solid var(--tpl-border);
  border-radius: 0.75rem;
  padding: 1.75rem;
  transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s;
}
.tpl-related-card:hover {
  transform: translateY(-4px);
  border-color: var(--tpl-primary);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.1);
}
.tpl-related-card h3 { margin: 0 0 0.5rem; font-size: 1.1rem; font-weight: 700; color: var(--tpl-fg); transition: color 0.2s; }
.tpl-related-card:hover h3 { color: var(--tpl-primary); }
.tpl-related-card p { margin: 0; font-size: 0.9rem; color: var(--tpl-muted); }
/* Index card thumbnail (template_data.cardImage): bleeds to the card's edges above the title.
   The fixed aspect-ratio (the 1200×750 the card images are cut to) reserves the box before the
   lazy image arrives, so the grid does not shift. */
.tpl-card-thumb {
  display: block;
  margin: -1.75rem -1.75rem 1.25rem;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: 0.75rem 0.75rem 0 0;
  border-bottom: 1px solid var(--tpl-border);
  background: var(--tpl-muted-bg);
}
.tpl-card-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.tpl-related-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.75rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--tpl-primary);
}
.tpl-related-link svg { width: 0.85rem; height: 0.85rem; }
/* The forward arrow (templates/_fragments :: arrow) points toward the reading direction's end. */
[dir="rtl"] .tpl-arrow { transform: scaleX(-1); }

/* Related BLOG posts reuse the card + grid above, but their count is admin-authored
   and often 1–2 (relatedTemplates is always seeded at 3). This modifier sizes the
   tracks to the content and centres the row so a short list isn't stranded against
   the left edge of a fixed 3-column grid. */
.tpl-related-grid-posts { justify-content: center; }

/* ===== Index page card grid ===== */
.tpl-index-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}

/* ===== Final CTA ===== */
.tpl-final { text-align: center; padding: 5rem 1.25rem; }
.tpl-final .tpl-annot {
  display: block;
  color: var(--tpl-primary);
  /* Dark theme: 0.75 measures 5.1:1 on the page background (0.6 was 3.6, under AA for this 20px line). */
  opacity: 0.75;
  font-size: 1.25rem;
  margin: 2rem 0 0.75rem;
}
/* Light theme: the full primary, as on the hero annotation (0.75 measures 3.2:1 on the light page background). */
html:not(.dark) .tpl-final .tpl-annot { opacity: 1; }
.tpl-final h2 {
  font-size: clamp(1.75rem, 5vw, 3rem);
  font-weight: 700;
  margin: 0;
  color: var(--tpl-fg);
}
.tpl-final h2 .tpl-accent { color: var(--tpl-primary); }
.tpl-final-sub { margin: 1rem auto 0; max-width: 32rem; color: var(--tpl-muted); }
.tpl-final-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 2.5rem;
}
.tpl-link-underline {
  color: var(--tpl-muted);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: var(--tpl-primary);
  font-size: 0.9rem;
  transition: color 0.2s;
}
.tpl-link-underline:hover { color: var(--tpl-fg); }

/* ===== Related features (倒流到 /features/* 功能頁) ===== */
.tpl-feature-intro { text-align: center; color: var(--tpl-muted); margin: 0 auto 1.5rem; max-width: 32rem; font-size: 0.95rem; }
.tpl-feature-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem; }
.tpl-feature-pill {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.6rem 1.1rem; border-radius: 999px;
  border: 1px solid var(--tpl-border);
  color: var(--tpl-primary); font-weight: 600; font-size: 0.9rem;
  transition: background 0.2s, border-color 0.2s;
}
.tpl-feature-pill:hover { background: var(--tpl-card); border-color: var(--tpl-primary); }
.tpl-feature-pill svg { width: 0.9rem; height: 0.9rem; }

/* ===== FAQ ===== */
.tpl-faq-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.tpl-faq-item {
  background: var(--tpl-card);
  border: 1px solid var(--tpl-border);
  border-radius: 0.75rem;
  overflow: hidden;
  transition: border-color 0.3s;
}
.tpl-faq-item[open] { border-color: var(--tpl-primary); }
.tpl-faq-question {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--tpl-fg);
  padding-block: 1.125rem;
  /* Room on the end edge for the +/− marker. */
  padding-inline: 1.5rem 3rem;
  cursor: pointer;
  /* Suppress the native disclosure triangle in both engines so the custom +/- is the only marker */
  list-style: none;
  position: relative;
  transition: color 0.2s;
}
.tpl-faq-question::-webkit-details-marker { display: none; }
.tpl-faq-question:hover { color: var(--tpl-primary); }
.tpl-faq-question::after {
  content: "+";
  position: absolute;
  inset-inline-end: 1.5rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.375rem;
  font-weight: 400;
  color: var(--tpl-primary);
  line-height: 1;
}
.tpl-faq-item[open] .tpl-faq-question::after { content: "\2212"; } /* minus sign */
.tpl-faq-answer {
  padding: 0 1.5rem 1.25rem;
  color: var(--tpl-muted);
  font-size: 0.9375rem;
  line-height: 1.8;
}

/* ===== Relationship-chart tool (templates/tools/relationship-chart.html + the /islands/relationship-chart.js island) =====
   Server-rendered: a preview (.tpl-rc-preview: three steps beside a drawn sample chart and「Start drawing」), sized
   like the tool so nothing below it moves when the island swaps it for .tpl-rc-app.

   Wider than 768px: toolbar, then the panel (characters, relationships) beside the canvas, then the save band.
   768px and narrower: the canvas first, the two panes behind tabs, and a bar of the three actions that sticks
   to the bottom of the window while the tool is on screen — sticky, not fixed, so it never covers the rest of
   the page. That is why this section is `overflow: clip` (see the OC builder above: `hidden` would make the
   section a scroll container and nothing inside could stick).

   The --color-* tokens are the ones the shared canvas reads in inline styles (RelationGraphCanvas, graph.css);
   the island's own sheet builds the Tailwind utilities it uses against the same --tpl-* values.
   Arabic: the chrome follows the page's dir="rtl"; the canvas pins itself LTR (coordinates are not reading order). */
.tpl-section.tpl-rc { overflow: clip; }
/* In-page jumps (the hero's「就在這頁免費畫關係圖」and #tpl-final-cta → #relationship-chart) glide down to the
   tool instead of snapping, so the visitor sees where it sits on the page, and land just under the sticky 57px
   .st-topbar (58px: 1px for sub-pixel rounding; more would leave a sliver of the hero showing). A reader who
   asked the system for less motion keeps the instant jump.
   Only on the page that holds the tool (`:has(#relationship-chart)`): every /templates page loads this sheet, and on
   the others a smooth `html` turns every window.scrollTo into an animation that callers (the OC builder's tests)
   measure mid-flight. A selector rather than a class from detail.html, so the rule and the element it serves cannot
   drift apart; an engine without :has gets the instant jump, the same thing reduced motion gets. */
@media (prefers-reduced-motion: no-preference) { html:has(#relationship-chart) { scroll-behavior: smooth; } }
#relationship-chart { scroll-margin-top: 3.625rem; }
.tpl-rc, [data-rc-light] {
  --color-background: var(--tpl-bg);
  --color-foreground: var(--tpl-fg);
  --color-card: var(--tpl-card);
  --color-card-foreground: var(--tpl-fg);
  --color-primary: var(--tpl-primary);
  --color-muted: var(--tpl-muted-bg);
  --color-muted-foreground: var(--tpl-muted);
  --color-accent: var(--tpl-accent);
  --color-border: var(--tpl-border);
  --color-ring: var(--tpl-primary);
}
/* Dark theme: the canvas draws its relationship lines in --color-border (an inline stroke on each edge path),
   which measures 2.2:1 on the dark canvas; inside an edge on this page it is the field edge instead (4.0:1).
   The light lines are 3.1:1 as they are. */
html.dark .tpl-rc .react-flow__edge { --color-border: var(--tpl-field-border); }
.tpl-rc-mount { min-height: 44rem; }
.tpl-rc-mount[data-rc-ready] { min-height: 0; }

/* -- the preview -- */
.tpl-rc-preview { display: grid; grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); gap: 1.25rem; align-items: stretch; }
.tpl-rc-preview-steps {
  margin: 0; padding: 1.25rem 1.25rem 1.25rem 2.5rem; padding-inline: 2.5rem 1.25rem;
  background: var(--tpl-card); border: 1px solid var(--tpl-accent); border-radius: 1rem;
  display: flex; flex-direction: column; gap: 0.9rem; color: var(--tpl-fg); line-height: 1.6;
}
.tpl-rc-preview-canvas {
  position: relative; min-height: 35rem; border: 1px solid var(--tpl-accent); border-radius: 1rem;
  background-color: var(--tpl-card);
  background-image: radial-gradient(color-mix(in srgb, var(--tpl-border) 45%, transparent) 1px, transparent 1px);
  background-size: 20px 20px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1rem; padding: 1.5rem;
}
.tpl-rc-preview-art { width: min(100%, 26rem); height: auto; }
.tpl-rc-preview-lines line { stroke: var(--tpl-border); stroke-width: 1.5; }
.tpl-rc-preview-nodes rect { fill: var(--tpl-card); stroke: var(--tpl-border); }
.tpl-rc-start { margin-top: 0; border: 0; cursor: pointer; font: inherit; font-weight: 700; }
.tpl-rc-noscript { margin: 0; color: var(--tpl-muted); font-size: 0.9rem; text-align: center; }
.tpl-rc-mount[data-rc-loading] .tpl-rc-start { opacity: 0.6; }

/* -- the tool -- */
.tpl-rc-app { display: flex; flex-direction: column; gap: 1rem; font-family: var(--tpl-font); }
.tpl-rc-app h3 { margin: 0; font-size: 1.1rem; font-weight: 700; color: var(--tpl-primary); }
.tpl-rc-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.tpl-rc-toolbar { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: space-between; align-items: center; }
.tpl-rc-toolbar-group { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tpl-rc-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  min-height: 2.5rem; padding: 0.45rem 1rem; border-radius: 999px;
  border: 1px solid var(--tpl-border); background: var(--tpl-card); color: var(--tpl-fg);
  font: inherit; font-size: 0.9rem; line-height: 1.3; cursor: pointer;
}
.tpl-rc-btn:hover { border-color: var(--tpl-primary); }
.tpl-rc-btn:focus-visible { outline: 2px solid var(--tpl-primary); outline-offset: 2px; }
.tpl-rc-btn:disabled { opacity: 0.55; cursor: default; }
.tpl-rc-btn-accent, .tpl-rc-btn-outline { border-color: var(--tpl-primary); color: var(--tpl-primary); }
.tpl-rc-btn-primary { border-color: var(--tpl-primary); background: var(--tpl-primary); color: var(--tpl-primary-fg); font-weight: 700; }
.tpl-rc-btn-lg { min-height: 2.875rem; padding: 0.6rem 1.4rem; font-size: 0.95rem; }
.tpl-rc-btn svg { flex-shrink: 0; }

.tpl-rc-body { display: grid; grid-template-columns: 20.5rem minmax(0, 1fr); grid-template-areas: "panel stage"; gap: 1.25rem; align-items: start; }
/* The canvas stays in view beside a long panel (sticky under the fixed 56px top bar; the section is overflow: clip). */
.tpl-rc-stage { grid-area: stage; min-width: 0; display: flex; flex-direction: column; gap: 0.6rem; position: sticky; top: 4.5rem; }
.tpl-rc-panel {
  grid-area: panel; min-width: 0; display: flex; flex-direction: column; gap: 1.1rem;
  background: var(--tpl-card); border: 1px solid var(--tpl-accent); border-radius: 1rem; padding: 1.1rem;
}
.tpl-rc-pane { display: flex; flex-direction: column; gap: 0.75rem; min-width: 0; }
.tpl-rc-pane + .tpl-rc-pane { border-top: 1px solid var(--tpl-accent); padding-top: 1.1rem; }
.tpl-rc-pane-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.tpl-rc-count { font-size: 0.85rem; color: var(--tpl-muted); white-space: nowrap; }

.tpl-rc-chips, .tpl-rc-links { list-style: none; margin: 0; padding: 0; }
.tpl-rc-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.tpl-rc-chip {
  display: inline-flex; align-items: center; border-radius: 999px; min-width: 0; max-width: 100%;
  background: var(--tpl-muted-bg); border: 1px solid var(--tpl-accent);
}
.tpl-rc-chip[data-selected] { border-color: var(--tpl-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--tpl-primary) 25%, transparent); }
.tpl-rc-chip-pick {
  display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0; min-height: 2.25rem;
  padding: 0.2rem 0.25rem 0.2rem 0.7rem; padding-inline: 0.7rem 0.25rem;
  border: 0; background: none; color: var(--tpl-fg); font: inherit; font-size: 0.85rem; cursor: pointer; text-align: start;
}
.tpl-rc-chip-pick > span:last-child { overflow-wrap: anywhere; }
.tpl-rc-dot { width: 0.65rem; height: 0.65rem; border-radius: 50%; flex-shrink: 0; }
.tpl-rc-chip-x {
  display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; flex-shrink: 0;
  border: 0; border-radius: 999px; background: none; color: var(--tpl-muted); font-size: 1.05rem; cursor: pointer;
}
.tpl-rc-chip-x:hover { color: var(--tpl-fg); background: var(--tpl-accent); }
.tpl-rc-add { display: flex; gap: 0.5rem; }
.tpl-rc-add input, .tpl-rc-field input[type="text"], .tpl-rc-hex {
  min-width: 0; width: 100%; box-sizing: border-box; min-height: 2.5rem; padding: 0.45rem 0.75rem;
  border: 1px solid var(--tpl-field-border); border-radius: 0.6rem; background: var(--tpl-card); color: var(--tpl-fg);
  font: inherit; font-size: 0.95rem;
}
/* The browser's default placeholder grey measures 3.9:1 on the dark card; muted-foreground is 5.4 (6.0 light). */
.tpl-rc-add input::placeholder, .tpl-rc-field input[type="text"]::placeholder { color: var(--tpl-muted); opacity: 1; }
.tpl-rc-add input { flex: 1; }
.tpl-rc-color { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; font-size: 0.85rem; color: var(--tpl-muted); }
.tpl-rc-color input[type="color"] {
  width: 2.75rem; height: 2.25rem; padding: 2px; border: 1px solid var(--tpl-field-border); border-radius: 0.5rem;
  background: var(--tpl-card); cursor: pointer;
}
.tpl-rc-color .tpl-rc-hex { width: 6.5rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.85rem; }
.tpl-rc-hint { margin: 0; font-size: 0.8rem; color: var(--tpl-muted); }

.tpl-rc-rel-form { display: flex; flex-direction: column; gap: 0.6rem; }
.tpl-rc-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.tpl-rc-label { font-size: 0.82rem; color: var(--tpl-muted); }
.tpl-rc-optional { font-size: 0.75rem; color: var(--tpl-muted); font-weight: 400; }
.tpl-rc-tags { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
.tpl-rc-check { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; min-height: 2rem; cursor: pointer; }
.tpl-rc-check input { width: 1.05rem; height: 1.05rem; accent-color: var(--tpl-primary); margin: 0; }
.tpl-rc-links { display: flex; flex-direction: column; gap: 0.25rem; }
.tpl-rc-links li { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; font-size: 0.85rem; }
.tpl-rc-link-text { min-width: 0; overflow-wrap: anywhere; }
.tpl-rc-link-type { color: var(--tpl-primary); }
.tpl-rc-note {
  margin: 0; padding: 0.6rem 0.75rem; border-radius: 0.6rem; background: var(--tpl-muted-bg);
  font-size: 0.82rem; line-height: 1.55; color: var(--tpl-fg);
}
.tpl-rc-status { margin: 0; font-size: 0.85rem; line-height: 1.5; color: var(--tpl-muted); }
.tpl-rc-status.is-error { color: #a2361f; }
html.dark .tpl-rc-status.is-error { color: #f0907a; }

.tpl-rc-tabs { align-self: flex-start; display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 999px; background: var(--tpl-accent); max-width: 100%; }
.tpl-rc-tabs button {
  min-height: 2.25rem; padding: 0.3rem 1rem; border: 0; border-radius: 999px; background: transparent;
  color: var(--tpl-muted); font: inherit; font-size: 0.88rem; cursor: pointer; white-space: nowrap;
}
.tpl-rc-tabs button[aria-selected="true"] { background: var(--tpl-card); color: var(--tpl-fg); font-weight: 700; }
/* muted-foreground on the accent pill measures 4.42 in the dark theme (same as .tpl-section-light3 .tpl-head p);
   the idle tab takes the foreground there, and the selected one keeps its card fill and weight. */
html.dark .tpl-rc-tabs button { color: var(--tpl-fg); }
.tpl-rc-canvas[hidden] { display: none; }
.tpl-rc-frame, .tpl-rc-matrix-frame {
  position: relative; background-color: var(--tpl-card); border: 1px solid var(--tpl-accent); border-radius: 1rem;
  color: var(--tpl-fg);
}
.tpl-rc-frame { height: 35rem; overflow: hidden; }
/* The chart's footer has a strip of its own: the canvas ends 1.75rem above the frame's bottom edge
   (.tpl-rc-canvas-box), so neither a card nor React Flow's own credit (.react-flow__attribution, bottom-right of
   the canvas, kept visible as its licence asks; the PNG leaves it out) can sit under「LitMemo 角色關係圖」.
   Physical right, not inset-inline-end: the canvas is pinned LTR, so its zoom buttons sit bottom-left on every page. */
.tpl-rc-app .tpl-rc-frame .tpl-rc-canvas-box { bottom: 1.75rem; }
.tpl-rc-made {
  position: absolute; bottom: 0.4rem; right: 0.9rem; margin: 0; z-index: 5; pointer-events: none;
  font-size: 0.72rem; line-height: 1.3; color: var(--tpl-muted);
}
/* The empty tool: the page language's example, faded, behind two buttons and three steps (RelationshipChartIsland
   `showsEmptyState`). The faded picture lies beside the frame, over its inside (1px in, the frame's border), so the
   PNG, which is taken from the frame, can never hold it; it stops above the frame's footer strip like the real
   canvas. Faint and greyed so it reads as a picture of what the tool makes, not as cards to press. */
.tpl-rc-canvas { position: relative; }
.tpl-rc-ghost {
  position: absolute; inset: 1px; border-radius: calc(1rem - 1px); overflow: hidden; pointer-events: none;
  opacity: 0.32; filter: saturate(0.35);
}
.tpl-rc-app .tpl-rc-ghost .tpl-rc-canvas-box { bottom: 1.75rem; }
html.dark .tpl-rc-ghost { opacity: 0.26; }
.tpl-rc-intro-layer {
  position: absolute; inset: 1px 1px 1.75rem; display: flex; align-items: center; justify-content: center;
  padding: 1rem; box-sizing: border-box; overflow: auto; z-index: 6;
  /* A light veil in the middle, so the steps and buttons sit on calm paper whatever card is behind them. */
  background: radial-gradient(closest-side, color-mix(in srgb, var(--tpl-card) 82%, transparent), transparent);
}
.tpl-rc-intro {
  display: flex; flex-direction: column; align-items: center; gap: 1.1rem; max-width: 100%;
  padding: 1.25rem 1.5rem; box-sizing: border-box; border-radius: 1rem; text-align: center;
  background: color-mix(in srgb, var(--tpl-card) 92%, transparent); border: 1px solid var(--tpl-accent);
  box-shadow: 0 10px 30px -12px rgb(0 0 0 / 0.25);
}
.tpl-rc-intro-steps {
  list-style: none; counter-reset: rc-step; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem 1.25rem; color: var(--tpl-fg); font-size: 0.95rem;
}
.tpl-rc-intro-steps li { counter-increment: rc-step; display: flex; align-items: center; gap: 0.45rem; line-height: 1.4; }
.tpl-rc-intro-steps li::before {
  content: counter(rc-step); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; border-radius: 50%; background: var(--tpl-accent); color: var(--tpl-primary);
  font-weight: 700; font-size: 0.8rem;
}
.tpl-rc-intro-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem; }
/* On the addressing tab the same introduction stands in for the table, in the card's flow. */
.tpl-rc-matrix-frame .tpl-rc-intro { align-self: center; margin: auto 0; border: 0; box-shadow: none; background: none; }
.tpl-rc-empty {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; margin: 0; padding: 2rem;
  text-align: center; color: var(--tpl-muted); font-size: 0.95rem; line-height: 1.6;
}
/* The addressing card keeps the stage's width, so its border, the type's caption and the footer stay in view; only
   the table scrolls sideways inside it (.tpl-rc-matrix-box). The footer is in normal flow under the table (pushed
   to the bottom of the card when the card shows the empty note), so a table that grows can only push it down. */
.tpl-rc-matrix-frame {
  display: flex; flex-direction: column; box-sizing: border-box; padding: 1rem 1rem 0.55rem; min-height: 12rem;
}
.tpl-rc-matrix-box { max-width: 100%; overflow-x: auto; }
.tpl-rc-matrix-frame .tpl-rc-made { position: static; margin-top: auto; padding-top: 0.75rem; text-align: end; }
/* The PNG's copy (RelationshipChartIsland `exportCopy`): off screen; the table's copy is as wide as the whole table,
   nothing clipped. Visible, not visibility:hidden — the capture copies computed styles and would draw an invisible card. */
/* Physical left: an inline-start offset would park the copy past the RIGHT edge on an Arabic page. */
.tpl-rc-export-host { position: fixed; top: 0; left: -100000px; pointer-events: none; }
/* The PNG is light whatever the page theme: the export host (data-rc-light) points every themed name the copy reads
   at the pinned light set, and re-derives on itself the variables that ancestors computed from the dark values
   (--color-* on .tpl-rc above, --tpl-field-border on .tpl-tool). Custom properties resolve where they are declared,
   so redefining only --tpl-* here would leave those two still dark. The island's `dark:` variant skips this subtree
   too (relationshipChartIsland.css). The live page never changes theme, so nothing on screen flashes. */
[data-rc-light] {
  color-scheme: light;
  --tpl-bg: var(--tpl-light-bg);
  --tpl-fg: var(--tpl-light-fg);
  --tpl-card: var(--tpl-light-card);
  --tpl-primary: var(--tpl-light-primary);
  --tpl-primary-fg: var(--tpl-light-primary-fg);
  --tpl-secondary: var(--tpl-light-secondary);
  --tpl-muted-bg: var(--tpl-light-muted-bg);
  --tpl-muted: var(--tpl-light-muted);
  --tpl-accent: var(--tpl-light-accent);
  --tpl-border: var(--tpl-light-border);
  --tpl-field-border: var(--tpl-light-border);
}
.tpl-rc-matrix-frame[data-rc-export] { width: max-content; }
.tpl-rc-matrix-frame[data-rc-export] .tpl-rc-matrix-box { overflow: visible; max-width: none; }
/* The speaker column and the header row stay put while the table scrolls sideways in .tpl-rc-matrix-box (a phone
   shows two or three columns of ten), as in the app's relation matrix and the public page's table. `separate` with
   zero spacing, borders on the cells: a collapsed table hands its borders to the TABLE, and a sticky cell then
   slides out from under its own border. Opaque backgrounds and z-index keep the scrolled cells underneath;
   `inset-inline-start` pins the column on the right in Arabic. */
.tpl-rc-matrix { border-collapse: separate; border-spacing: 0; font-size: 0.85rem; }
.tpl-rc-matrix th, .tpl-rc-matrix td {
  border-inline-end: 1px solid var(--tpl-accent); border-bottom: 1px solid var(--tpl-accent);
  padding: 0.45rem 0.6rem; min-width: 5.5rem; text-align: start; vertical-align: top;
}
.tpl-rc-matrix thead th { border-top: 1px solid var(--tpl-accent); }
.tpl-rc-matrix tr > :first-child { border-inline-start: 1px solid var(--tpl-accent); }
.tpl-rc-matrix thead th { position: sticky; top: 0; z-index: 2; background: var(--tpl-muted-bg); font-weight: 700; }
.tpl-rc-matrix tbody th {
  position: sticky; inset-inline-start: 0; z-index: 1; background: var(--tpl-muted-bg); font-weight: 700; white-space: nowrap;
}
.tpl-rc-matrix thead th:first-child { inset-inline-start: 0; z-index: 3; }
.tpl-rc-matrix td.is-self { background: color-mix(in srgb, var(--tpl-accent) 50%, transparent); }
/* One table per relation type (D12): the type buttons above the frame wrap to more rows rather than scroll, and
   the type's name is the table's caption, inside the frame, so the PNG says which type it is. The same pill strip
   as the view tabs, with 0.5rem inside each end rather than 0.25rem: six short types (ja) fill a phone's row edge to
   edge, and at 0.25rem the last one read as flush with the strip's end. Logical padding, so Arabic mirrors it. */
.tpl-rc-types { flex-wrap: wrap; border-radius: 1.25rem; padding-inline: 0.5rem; }
.tpl-rc-matrix-caption { margin: 0; text-align: start; padding: 0 0 0.6rem; font-weight: 700; font-size: 0.95rem; }
.tpl-rc-matrix .tpl-rc-corner { font-weight: 400; color: var(--tpl-muted); font-size: 0.78rem; }

.tpl-rc-save {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap;
  background: var(--tpl-card); border: 1px solid var(--tpl-accent); border-radius: 1rem; padding: 1.1rem 1.4rem;
}
.tpl-rc-save-copy { min-width: 0; flex: 1 1 18rem; }
.tpl-rc-save-copy h3 { color: var(--tpl-fg); font-size: 1.15rem; }
.tpl-rc-save-copy p { margin: 0.3rem 0 0; color: var(--tpl-muted); font-size: 0.92rem; }
.tpl-rc-save-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.tpl-rc-stays { margin: -0.4rem 0 0; text-align: center; font-size: 0.82rem; color: var(--tpl-muted); }

.tpl-rc-app .tpl-rc-phone-only { display: none; }
.tpl-rc-mbar { gap: 0.5rem; }

@media (max-width: 768px) {
  .tpl-rc-mount { min-height: 50rem; }
  .tpl-rc-preview { grid-template-columns: minmax(0, 1fr); }
  .tpl-rc-preview-canvas { min-height: 21rem; order: -1; }
  .tpl-rc-toolbar { justify-content: center; }
  .tpl-rc-toolbar-group { justify-content: center; }
  .tpl-rc-btn { min-height: 2.75rem; }
  .tpl-rc-body { grid-template-columns: minmax(0, 1fr); grid-template-areas: "stage" "panel"; }
  .tpl-rc-stage { position: static; }
  /* As tall as a phone allows beside the sticky action bar: the chart is fitted to this box, so height is legibility. */
  .tpl-rc-frame { height: 24rem; }
  /* Phone: the steps stack, the two buttons take the card's width (each ≥44px tall). */
  .tpl-rc-intro-layer { padding: 0.75rem; }
  .tpl-rc-intro { width: 100%; padding: 1rem; gap: 0.9rem; }
  .tpl-rc-intro-steps { flex-direction: column; align-items: flex-start; gap: 0.4rem; text-align: start; }
  .tpl-rc-intro-actions { flex-direction: column; align-self: stretch; }
  .tpl-rc-intro-actions .tpl-rc-btn { width: 100%; min-height: 2.75rem; }
  .tpl-rc-tabs { align-self: stretch; }
  .tpl-rc-app .tpl-rc-tabs.tpl-rc-phone-only { display: flex; }
  /* The two tabs share the row by their own length (a long label such as "What they call each other" takes the
     room a short one leaves), with the padding giving way before the text does. */
  .tpl-rc-tabs button { flex: 1 1 auto; min-width: 0; min-height: 2.75rem; padding-inline: 0.5rem; }
  .tpl-rc-panel { padding: 0.9rem; }
  .tpl-rc-pane:not([data-active]) { display: none; }
  .tpl-rc-pane + .tpl-rc-pane { border-top: 0; padding-top: 0; }
  .tpl-rc-chip-pick { min-height: 2.75rem; }
  .tpl-rc-chip-x { width: 2.75rem; height: 2.75rem; }
  .tpl-rc-add input, .tpl-rc-field input[type="text"] { min-height: 2.75rem; font-size: 1rem; }
  .tpl-rc-check { min-height: 2.75rem; }
  .tpl-rc-color input[type="color"] { width: 2.75rem; height: 2.75rem; }
  .tpl-rc-tags { grid-template-columns: minmax(0, 1fr); }
  .tpl-rc-app .tpl-rc-desktop-only { display: none; }
  .tpl-rc-save-actions { display: none; }
  .tpl-rc-app .tpl-rc-mbar.tpl-rc-phone-only {
    display: flex; position: sticky; bottom: 0; z-index: 20; margin: 0 -1rem; padding: 0.75rem 1rem;
    background: var(--tpl-card); border-top: 1px solid var(--tpl-accent);
  }
  .tpl-rc-mbar .tpl-rc-btn { min-height: 3rem; flex: 1 1 0; min-width: 0; padding-inline: 0.75rem; }
  .tpl-rc-mbar .tpl-rc-icon { flex: 0 0 3rem; width: 3rem; padding: 0; }
  .tpl-rc-mbar .tpl-rc-grow { flex-grow: 1.4; }
}
/* Tab and action-bar labels stay on one line from 360px up (at 390px "الشخصيات · 9/10" and "الحفظ في LitMemo"
   broke in two); narrower than that they may wrap rather than run out of their pill. */
@media (min-width: 360px) {
  .tpl-rc-tabs button, .tpl-rc-mbar .tpl-rc-btn { white-space: nowrap; }
}
@media (max-width: 359px) {
  .tpl-rc-tabs button { white-space: normal; }
}

/* ===== Responsive ===== */
@media (min-width: 640px) {
  .tpl-copy-wrap { display: block; }
  .tpl-copy { padding-inline-end: 6.5rem; }
  .tpl-copy-btn { position: absolute; top: 0.75rem; inset-inline-end: 0.75rem; }
  .tpl-steps-grid { grid-template-columns: repeat(2, 1fr); }
  .tpl-related-grid { grid-template-columns: repeat(3, 1fr); }
  /* auto-fit collapses the empty tracks, so 1–2 cards centre instead of stranding;
     minmax caps a lone card at the same width it would have in the 3-up row. */
  .tpl-related-grid-posts { grid-template-columns: repeat(auto-fit, minmax(0, 17rem)); }
  .tpl-index-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .tpl-section { padding: 6rem 1.5rem; }
  /* Restated here because the shorthand above (same specificity, later in the cascade) would
     otherwise hand these two sections the full 6rem again on desktop. */
  .tpl-hero-figure { padding-top: 0; }
  .tpl-downloads { padding-top: 2.5rem; padding-bottom: 2.5rem; }
  .tpl-mid-cta { padding-top: 0; padding-bottom: 3.5rem; }
  .tpl-hero-figure:has(+ .tpl-mid-cta) { padding-bottom: 2.5rem; }
  .tpl-downloads:has(+ .tpl-mid-cta) { padding-bottom: 1.5rem; }
  .tpl-steps-grid { grid-template-columns: repeat(4, 1fr); }
  .tpl-index-grid { grid-template-columns: repeat(3, 1fr); }
}
