/* ============================================================================
   InsertMaker — design-system theme ("Boardgamey & Cozy")
   Phase 13.2 (DESIGN.md §19; docs/design/visual-direction.md). The metaphor:
   the app is a game table. Page = green FELT; furniture (nav, frames, buttons)
   = brown WOOD; things you make/browse = CARDBOARD/kraft cards; text you read
   sits on PAPER. Material = role.

   This file establishes the tokens, self-hosted fonts, and base component
   styles that OVERRIDE the stock Bootstrap defaults, plus the themed app shell.
   Per-page restyling is Phase 13.3 — this layer is intentionally broad-but-base.
   Loaded AFTER bootstrap.min.css in App.razor so it wins the cascade.
   ============================================================================ */

/* ── Self-hosted fonts (no runtime CDN — the container is offline) ─────────── */
/* Variable-font subsets; one physical file per family+subset covers the weight
   range, so the distinct @font-face weight declarations reuse the same src. */
@font-face {
  font-family: "Fredoka";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("fonts/fredoka-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fredoka";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("fonts/fredoka-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/nunito-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/nunito-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── Tokens ────────────────────────────────────────────────────────────────
   The approved palette + shape/shadow/type tokens. We ALSO remap the relevant
   Bootstrap CSS variables (--bs-*) onto our tokens so stock components recolour
   automatically without per-element overrides. */
:root {
  /* felt */   --felt: #2E6B4F; --felt-deep: #21513C; --felt-light: #3C8262; --felt-rail: #1A3F2E;
  /* wood */   --wood: #7A4B2B; --wood-dark: #5C3618; --wood-light: #9A6438; --wood-edge: #3F2410;
  /* kraft */  --kraft: #D8B98C; --kraft-dark: #C2A271; --kraft-light: #E7D2AE; --kraft-deep: #A8855A;
  /* paper */  --paper: #F6EFDD; --paper-dim: #EBE0C6; --paper-line: #D8C9A6;
  /* ink */    --ink: #3A2A18; --ink-soft: #6E5A40; --cream: #F4E9D2;
  /* accent */ --accent: #C9772E; --accent-deep: #A85E1E;
  /* wordmark "Maker" gold — >=3:1 large-text AA on the wood nav (#7A4B2B, ~3.5:1); the amber --accent is only ~2.2:1 there and would fail */ --brand-maker: #ECA63C;
  /* semantic*/--success: #3E7D4F; --warn: #B5872A; --danger: #9C3B2E; --info: #3A6E7A;
  /* type */
  --font-display: "Fredoka", "Trebuchet MS", system-ui, sans-serif;
  --font-body: "Nunito Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  /* spacing */
  --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem;
  --space-5: 1.5rem; --space-6: 2rem; --space-7: 3rem;
  /* The WORST-CASE height the sticky wood top nav (.topnav) can reach. The nav uses
     flex-wrap, so a signed-in user with a long display name (e.g. an email) wraps it
     onto a second row — ~104px. Used by html{scroll-padding-top} so any element
     scrolled into view (a `#fragment` jump OR a programmatic/Playwright scroll) clears
     the sticky nav instead of landing under it (which would make the nav intercept a
     click on the revealed control). Generous so CI font metrics that wrap differently
     still clear it. */
  --topnav-height: 7rem;
  /* shape */
  --radius-sm: 8px; --radius: 12px; --radius-lg: 18px; --radius-pill: 999px;
  --shadow-soft: 0 2px 6px rgba(40, 25, 10, .18);
  --shadow-pop: 0 8px 18px rgba(40, 25, 10, .30);
  --shadow-inset: inset 0 2px 4px rgba(40, 25, 10, .12);

  /* Bootstrap variable remap — recolour stock components onto the palette. */
  --bs-body-font-family: var(--font-body);
  --bs-body-color: var(--ink);
  --bs-body-bg: var(--felt);
  --bs-emphasis-color: var(--ink);
  /* Warm, AA-contrast muted text (.text-muted/.text-secondary) — our --ink-soft
     instead of Bootstrap's cold blue-gray, so secondary text stays on the table. */
  --bs-secondary-color: var(--ink-soft);
  --bs-tertiary-color: var(--ink-soft);
  --bs-primary: var(--wood);
  --bs-primary-rgb: 122, 75, 43;
  --bs-secondary: var(--kraft-deep);
  --bs-success: var(--success);
  --bs-success-rgb: 62, 125, 79;
  --bs-danger: var(--danger);
  --bs-danger-rgb: 156, 59, 46;
  --bs-warning: var(--warn);
  --bs-warning-rgb: 181, 135, 42;
  --bs-info: var(--info);
  --bs-info-rgb: 58, 110, 122;
  --bs-link-color: var(--accent);
  --bs-link-color-rgb: 201, 119, 46;
  --bs-link-hover-color: var(--accent-deep);
  --bs-border-color: var(--paper-line);
  --bs-border-radius: var(--radius);
  --bs-border-radius-sm: var(--radius-sm);
  --bs-border-radius-lg: var(--radius-lg);
  --bs-card-bg: var(--kraft);
  --bs-card-color: var(--ink);
  --bs-card-border-color: var(--kraft-dark);
  /* List-group ACTIVE (e.g. the selected mesh-view on design detail): the stock
     #0d6efd Bootstrap blue has no place on the table — recolour the selected
     item onto the wood key (cream on wood = 6.1:1, AA). */
  --bs-list-group-active-bg: var(--wood);
  --bs-list-group-active-border-color: var(--wood-dark);
  --bs-list-group-active-color: var(--cream);
}

/* ── Base typography & surfaces ────────────────────────────────────────────── */
html,
body {
  margin: 0;
  padding: 0;
}

/* The window is the scroll container and the wood top nav is `position: sticky; top: 0`,
   so reserve the nav's height at the top of the scrollport: any element scrolled into
   view — an in-page `#fragment` anchor OR a programmatic scroll (incl. the E2E driver
   revealing a control to click) — comes to rest BELOW the sticky nav, never under it.
   Without this a control scrolled to the top edge sits under the nav, which then
   intercepts the click. */
html {
  scroll-padding-top: var(--topnav-height);
}

body {
  font-family: var(--font-body);
  color: var(--cream);
  line-height: 1.5;
  min-height: 100vh;
  /* FELT: edge vignette + a faint ±45° weave over the base green. */
  background-color: var(--felt);
  background-image:
    radial-gradient(120% 90% at 50% 0%, rgba(60, 130, 98, .35), transparent 55%),
    radial-gradient(140% 120% at 50% 120%, rgba(26, 63, 46, .65), transparent 60%),
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .025) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(-45deg, rgba(0, 0, 0, .06) 0 1px, transparent 1px 4px);
  background-attachment: fixed;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
}

/* Headings + body in the felt content area read as warm ink on a paper canvas
   (see .content below); on felt directly they're cream. */
a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  color: var(--accent-deep);
  text-decoration: underline;
}

/* ── BUTTONS (chunky 3D keys — material = role) ─────────────────────────────── */
.btn {
  font-family: var(--font-body);
  font-weight: 700;
  border: none;
  border-radius: 9px;
  transition: transform .05s ease, box-shadow .05s ease, background-color .15s ease;
}

.btn:active {
  transform: translateY(2px);
}

/* Primary = wood key. */
.btn-primary {
  color: var(--cream);
  background-color: var(--wood);
  box-shadow: inset 0 2px 0 var(--wood-light), inset 0 -3px 0 var(--wood-dark), var(--shadow-soft);
}

.btn-primary:hover,
.btn-primary:focus {
  color: var(--cream);
  background-color: var(--wood-light);
}

.btn-primary:active {
  background-color: var(--wood);
  box-shadow: inset 0 1px 0 var(--wood-light), inset 0 -1px 0 var(--wood-dark);
}

/* The amber CTA — the one button that pops off the wood. */
.btn-cta,
.btn-accent {
  color: #fff;
  background-color: var(--accent);
  box-shadow: inset 0 2px 0 #e0954f, inset 0 -3px 0 var(--accent-deep), var(--shadow-soft);
}

.btn-cta:hover,
.btn-accent:hover,
.btn-cta:focus,
.btn-accent:focus {
  color: #fff;
  background-color: var(--accent-deep);
}

.btn-cta:active,
.btn-accent:active {
  box-shadow: inset 0 1px 0 #e0954f, inset 0 -1px 0 var(--accent-deep);
}

/* Secondary = kraft tile. */
.btn-secondary {
  color: var(--ink);
  background-color: var(--kraft);
  box-shadow: inset 0 2px 0 var(--kraft-light), inset 0 -3px 0 var(--kraft-dark), var(--shadow-soft);
}

.btn-secondary:hover,
.btn-secondary:focus {
  color: var(--ink);
  background-color: var(--kraft-light);
}

/* Destructive = brick that lives with the wood. */
.btn-danger {
  color: var(--cream);
  background-color: var(--danger);
  box-shadow: inset 0 2px 0 #b6543f, inset 0 -3px 0 #6f281d, var(--shadow-soft);
}

.btn-danger:hover,
.btn-danger:focus {
  color: var(--cream);
  background-color: #b6543f;
}

.btn-success {
  color: var(--cream);
  background-color: var(--success);
}

.btn-info {
  color: var(--cream);
  background-color: var(--info);
}

.btn-warning {
  color: #2a200c;
  background-color: var(--warn);
}

/* Wood-outline ghost on paper/felt. */
.btn-outline-primary {
  color: var(--wood);
  border: 2px solid var(--wood);
  background-color: transparent;
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
  color: var(--cream);
  background-color: var(--wood);
  border-color: var(--wood);
}

.btn-outline-secondary {
  color: var(--ink);
  border: 2px solid var(--kraft-dark);
  background-color: transparent;
}

.btn-link {
  color: var(--accent);
  font-weight: 700;
}

/* Kill Bootstrap's stock BLUE button STATES. The resting colours are themed above, but Bootstrap's
   high-specificity active selectors (`.btn:first-child:active`, `:not(.btn-check)+.btn:active` — 0,3,0)
   out-specify our `.btn-x:active` (0,2,0), so a *clicked* button would otherwise repaint to the stock
   blue `--bs-btn-active-bg`/`--bs-btn-active-border-color`. Remap each variant's Bootstrap button
   variables so every state (hover/active/focus/DISABLED) stays on the palette, and swap the blue
   focus-shadow rgb for amber. Disabled is the same trap: Bootstrap's `.btn:disabled` (0,2,0) repaints to
   the per-variant `--bs-btn-disabled-bg`, which still holds stock blue for `.btn-primary`/`.btn-outline-*`
   — so a disabled "Post comment" went blue. Remap the disabled vars too (Bootstrap's 0.65 opacity then
   reads them as muted). Variables (not rules) so they feed Bootstrap's own state selectors at any specificity. */
.btn-primary {
  --bs-btn-active-color: var(--cream);
  --bs-btn-active-bg: var(--wood-dark);
  --bs-btn-active-border-color: var(--wood-edge);
  --bs-btn-disabled-color: var(--cream);
  --bs-btn-disabled-bg: var(--wood);
  --bs-btn-disabled-border-color: var(--wood);
  --bs-btn-focus-shadow-rgb: 201, 119, 46;
}

.btn-secondary {
  --bs-btn-active-color: var(--ink);
  --bs-btn-active-bg: var(--kraft-dark);
  --bs-btn-active-border-color: var(--kraft-deep);
  --bs-btn-disabled-color: var(--ink);
  --bs-btn-disabled-bg: var(--kraft);
  --bs-btn-disabled-border-color: var(--kraft-dark);
  --bs-btn-focus-shadow-rgb: 201, 119, 46;
}

.btn-danger {
  --bs-btn-active-color: var(--cream);
  --bs-btn-active-bg: #6f281d;
  --bs-btn-active-border-color: #6f281d;
  --bs-btn-disabled-color: var(--cream);
  --bs-btn-disabled-bg: var(--danger);
  --bs-btn-disabled-border-color: var(--danger);
  --bs-btn-focus-shadow-rgb: 156, 59, 46;
}

.btn-cta,
.btn-accent {
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--accent-deep);
  --bs-btn-active-border-color: var(--accent-deep);
  --bs-btn-disabled-color: #fff;
  --bs-btn-disabled-bg: var(--accent);
  --bs-btn-disabled-border-color: var(--accent-deep);
  --bs-btn-focus-shadow-rgb: 201, 119, 46;
}

.btn-outline-primary {
  --bs-btn-active-color: var(--cream);
  --bs-btn-active-bg: var(--wood);
  --bs-btn-active-border-color: var(--wood);
  --bs-btn-disabled-color: var(--wood);
  --bs-btn-disabled-border-color: var(--wood);
  --bs-btn-focus-shadow-rgb: 201, 119, 46;
}

.btn-outline-secondary {
  --bs-btn-active-color: var(--ink);
  --bs-btn-active-bg: var(--kraft);
  --bs-btn-active-border-color: var(--kraft-dark);
  --bs-btn-disabled-color: var(--ink);
  --bs-btn-disabled-border-color: var(--kraft-dark);
  --bs-btn-focus-shadow-rgb: 201, 119, 46;
}

.btn-outline-danger {
  --bs-btn-active-color: var(--cream);
  --bs-btn-active-bg: var(--danger);
  --bs-btn-active-border-color: var(--danger);
  --bs-btn-hover-color: var(--cream);
  --bs-btn-hover-bg: var(--danger);
  --bs-btn-hover-border-color: var(--danger);
  --bs-btn-disabled-color: var(--danger);
  --bs-btn-disabled-border-color: var(--danger);
  --bs-btn-focus-shadow-rgb: 156, 59, 46;
}

.btn-link {
  --bs-btn-focus-shadow-rgb: 201, 119, 46;
}

/* PAGINATION (gallery) — stock Bootstrap pages are BLUE (link blue + #0d6efd active). Remap the
   pagination variables onto the palette: paper page tiles, an amber link, the current page on the wood
   key. */
.pagination {
  --bs-pagination-color: var(--accent);
  --bs-pagination-bg: var(--paper);
  --bs-pagination-border-color: var(--paper-line);
  --bs-pagination-hover-color: var(--accent-deep);
  --bs-pagination-hover-bg: var(--paper-dim);
  --bs-pagination-hover-border-color: var(--paper-line);
  --bs-pagination-focus-color: var(--accent-deep);
  --bs-pagination-focus-bg: var(--paper-dim);
  --bs-pagination-focus-box-shadow: 0 0 0 0.2rem rgba(201, 119, 46, 0.35);
  --bs-pagination-active-color: var(--cream);
  --bs-pagination-active-bg: var(--wood);
  --bs-pagination-active-border-color: var(--wood-dark);
  --bs-pagination-disabled-color: var(--ink-soft);
  --bs-pagination-disabled-bg: var(--paper-dim);
  --bs-pagination-disabled-border-color: var(--paper-line);
}

/* ── CARDS = cardboard/kraft ───────────────────────────────────────────────── */
.card {
  background-color: var(--kraft);
  background-image:
    linear-gradient(rgba(255, 255, 255, .10), rgba(0, 0, 0, .05)),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, .03) 0 1px, transparent 1px 7px);
  color: var(--ink);
  border: 1px solid var(--kraft-dark);
  border-bottom: 4px solid var(--kraft-dark); /* the cardboard edge */
  border-radius: var(--radius);
  box-shadow: var(--shadow-soft);
}

.card-header,
.card-footer {
  background-color: var(--kraft-deep);
  color: var(--cream);
  border-color: var(--kraft-dark);
}

.card-title {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
}

/* Card body/caption text rides KRAFT, not paper — ink-soft on kraft is only
   3.51:1 (below AA), so card captions use --ink (7.4:1). ink-soft stays for
   secondary text on PAPER (5.0:1), per the direction's contrast discipline.
   This includes Bootstrap's muted/secondary helpers when used inside a card. */
.card-subtitle,
.card-text,
.card .text-muted,
.card .text-secondary,
.card .form-text,
.card .small {
  color: var(--ink);
}

/* ── PANELS = paper (forms, prose, list groups) ────────────────────────────── */
.panel,
.list-group {
  background-color: var(--paper);
  color: var(--ink);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-soft);
}

.panel {
  padding: 22px 24px;
}

.panel h1,
.panel h2,
.panel h3,
.panel h4,
.list-group {
  color: var(--ink);
}

.list-group-item {
  background-color: transparent;
  color: var(--ink);
  border-color: var(--paper-line);
}

/* The SELECTED mesh-view item — wood key, never stock Bootstrap blue (#0d6efd).
   Belt-and-braces over the --bs-list-group-active-* remap above. */
.list-group-item.active {
  color: var(--cream);
  background-color: var(--wood);
  border-color: var(--wood-dark);
}

/* The active item's muted SUBTITLE (e.g. the mesh-view "All N modules…" line):
   Bootstrap's .text-muted/.text-secondary set color via --bs-secondary-color
   !important (our ink-soft), which on the wood active background is 1.12:1 —
   unreadable. The .active cream only reaches the non-muted title, so recolour the
   muted text to cream too (6.1:1 on wood, AA). !important is required to beat
   Bootstrap's own !important. */
.list-group-item.active .text-muted,
.list-group-item.active .text-secondary {
  color: var(--cream) !important;
}

/* Wood-framed paper section (a "tray frame"). */
.framed {
  border-radius: var(--radius-lg);
  padding: 6px;
  background-image: linear-gradient(var(--wood-light), var(--wood-dark));
  box-shadow: var(--shadow-soft);
}

.framed > .framed-inner {
  background-color: var(--paper);
  color: var(--ink);
  border-radius: var(--radius);
  padding: 20px 22px;
}

/* ── LINKED GAME CARD (BoardGameGeek, §19.3) ───────────────────────────────────
   A compact paper panel: the cached cover (proxied, never hotlinked) beside the
   title, year, and the MANDATORY "Powered by BGG" attribution link. Degrades to
   a title-only row when no cover was cached (the <img> is simply absent). */
.game-card {
  padding: 14px 16px;
}

.game-card-heading {
  display: block;
  text-transform: uppercase;
  letter-spacing: .06em;
  margin-bottom: 6px;
}

.game-card-body {
  display: flex;
  gap: 14px;
  align-items: center;
}

.game-card-cover {
  width: 96px;
  height: 96px;
  object-fit: contain;
  flex: 0 0 auto;
  background-color: var(--paper-dim);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-inset);
}

/* The text column beside the cover: allow it to shrink (min-width:0) so the title
   wraps and the full-width "Powered by BGG" logo resolves its max-width:100%
   against this flex item instead of overflowing the card. */
.game-card-text {
  min-width: 0;
  flex: 1 1 auto;
}

.game-card-title {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.15rem;
  color: var(--ink);
}

/* The "Powered by BoardGameGeek" attribution link (BGG ToS, §19.4) — accent ink
   on paper (the theme link colour), always visible whenever a game is shown. */
.game-card-bgg-link {
  margin-top: 4px;
  color: var(--accent);
  text-decoration: underline;
}

.game-card-bgg-link:hover,
.game-card-bgg-link:focus {
  color: var(--accent-deep);
}

/* ── BADGES / CHIPS (little tokens) ────────────────────────────────────────── */
.badge {
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: .02em;
  border-radius: var(--radius-pill);
  color: var(--cream);
  box-shadow: var(--shadow-soft);
}

.badge.bg-primary,
.badge.text-bg-primary {
  background-color: var(--wood) !important;
}

/* "Published" badge — cream on the lighter --success was 4.10:1 (just below AA);
   a darker felt-green takes cream to 5.5:1 (AA) while staying in the green family. */
.badge.bg-success,
.badge.text-bg-success {
  background-color: #33683F !important;
  color: var(--cream) !important;
}

.badge.bg-warning,
.badge.text-bg-warning {
  background-color: var(--warn) !important;
  color: #2a200c !important;
}

.badge.bg-danger,
.badge.text-bg-danger {
  background-color: var(--danger) !important;
}

.badge.bg-info,
.badge.text-bg-info {
  background-color: var(--info) !important;
  color: var(--cream) !important;
}

/* Kraft tile chip — ink on kraft (the direction's "kraft chips with ink text",
   §3 Badges). kraft-deep + cream was 2.83:1 (below AA); kraft-dark + ink is
   5.71:1 (AA). Used by the Draft status badge, gallery parts chip, My-designs
   status chips. */
.badge.bg-secondary,
.badge.text-bg-secondary {
  background-color: var(--kraft-dark) !important;
  color: var(--ink) !important;
}

/* ── FORM CONTROLS = inset paper wells ─────────────────────────────────────── */
.form-control,
.form-select {
  font-family: var(--font-body);
  color: var(--ink);
  background-color: var(--paper-dim);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-inset);
}

.form-control:focus,
.form-select:focus,
.form-check-input:focus {
  color: var(--ink);
  background-color: var(--paper);
  border-color: var(--accent);
  box-shadow: 0 0 0 .2rem rgba(201, 119, 46, .35);
}

.form-control::placeholder {
  color: var(--ink-soft);
  opacity: .8;
}

.form-label,
.col-form-label,
.form-check-label {
  color: var(--ink);
  font-weight: 700;
}

.form-text {
  color: var(--ink-soft);
}

.form-check-input:checked {
  background-color: var(--accent);
  border-color: var(--accent);
}

.input-group-text {
  background-color: var(--kraft);
  color: var(--ink);
  border-color: var(--paper-line);
}

/* ── TABLES on paper ───────────────────────────────────────────────────────── */
.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--ink);
  --bs-table-border-color: var(--paper-line);
  --bs-table-striped-bg: var(--paper-dim);
  --bs-table-striped-color: var(--ink);
  color: var(--ink);
}

/* ── ALERTS (warm semantic) ────────────────────────────────────────────────── */
.alert {
  border-radius: var(--radius);
  border-width: 1px;
}

.alert-success {
  color: #1f4a2e;
  background-color: #dcebdf;
  border-color: var(--success);
}

.alert-danger {
  color: #5e231b;
  background-color: #f0dad6;
  border-color: var(--danger);
}

.alert-warning {
  color: #5a430f;
  background-color: #f3e8cc;
  border-color: var(--warn);
}

.alert-info {
  color: #234047;
  background-color: #d8e6e9;
  border-color: var(--info);
}

/* ── Focus visibility (amber ring — the brand focus token, AA-UI) ──────────── */
/* WCAG 1.4.11: the indicator must hit >= 3:1 against the ADJACENT surface. Amber
   alone is only ~1.9:1 on felt / ~3.0:1 on paper, so we wrap the amber outline in
   a TWO-TONE halo: an inner cream ring (>= 5:1 on the dark felt/wood) plus an outer
   ink ring (>= 7:1 on the light paper/kraft). Whatever the surface, at least one
   ring clears 3:1 — so focus is always visible. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow:
    0 0 0 2px var(--cream),
    0 0 0 4px var(--ink);
}

/* Blazor's <FocusOnNavigate Selector="h1"> programmatically focuses the page
   heading after every navigation (a screen-reader context cue), so on keyboard-
   driven navigation the heading turns :focus-visible. A heading is not an
   actionable control — the focus halo would frame the headline in a dark ring
   ("black border"). Suppress it on headings; the halo stays on real controls. */
:is(h1, h2, h3, h4, h5, h6):focus,
:is(h1, h2, h3, h4, h5, h6):focus-visible {
  outline: none;
  box-shadow: none;
}

/* Buttons get the SAME amber brand halo, not Bootstrap's per-variant blue focus
   ring (.btn:focus-visible carries a hardcoded --bs-btn-focus-shadow-rgb of
   49,132,253 that beats the generic :focus-visible above on specificity). Keep
   stock blue off the table here too. */
.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow:
    0 0 0 2px var(--cream),
    0 0 0 4px var(--ink);
}

/* The validation chrome from app.css recoloured onto the warm palette. */
.valid.modified:not([type=checkbox]) {
  outline: 1px solid var(--success);
}

.invalid {
  outline: 1px solid var(--danger);
}

.validation-message {
  color: var(--danger);
}

/* ════════════════════════════════════════════════════════════════════════════
   Phase 13.3 — per-page application of the design system across every page.
   The shell (top nav/footer/viewer base) is themed in 13.2/13.6; this layer
   styles the page bodies: home hero + feature cards, gallery/My-designs/
   candidate kraft cards, the wood-framed editor sections + score meter, the
   wood-framed viewer hero, the community paper sub-panels, and the auth cards.
   Material = role throughout (visual-direction §3/§5).
   ════════════════════════════════════════════════════════════════════════════ */

/* ── Shared page furniture ─────────────────────────────────────────────────── */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  margin-bottom: 0.75rem;
}

.section-head h1,
.section-head h2 {
  margin: 0;
}

.section-head-note,
.section-head .muted {
  color: var(--ink-soft);
  font-size: 0.95rem;
}

.page-lead {
  color: var(--ink);
  font-size: 1.05rem;
  max-width: 70ch;
}

.page-muted {
  color: var(--ink-soft);
}

/* ── Privacy policy (/privacy, Phase 17.2) ─────────────────────────────────── */
.privacy-section {
  margin-top: 1.75rem;
}

.privacy-section h2 {
  margin-bottom: 0.5rem;
}

.privacy-table {
  font-size: 0.92rem;
}

.privacy-table th {
  white-space: nowrap;
}

.privacy-category {
  font-weight: 600;
  white-space: nowrap;
}

.privacy-third-parties,
.privacy-rights {
  padding-left: 1.25rem;
}

.privacy-third-parties li,
.privacy-rights li {
  margin-bottom: 0.4rem;
}

/* ── Cookie policy (/cookies, Phase 17.3) ──────────────────────────────────── */
.cookies-section {
  margin-top: 1.75rem;
}

.cookies-section h2 {
  margin-bottom: 0.5rem;
}

.cookies-table {
  font-size: 0.92rem;
}

.cookies-name code {
  white-space: nowrap;
  color: var(--ink);
}

/* ── Terms of service (/terms, Phase 17.6) ─────────────────────────────────── */
.terms-section {
  margin-top: 1.75rem;
}

.terms-section h2 {
  margin-bottom: 0.5rem;
}

.terms-list {
  padding-left: 1.25rem;
}

.terms-list li {
  margin-bottom: 0.4rem;
}

.terms-contact a {
  margin-left: 0.35rem;
}

/* ── Site footer (Phase 17.6) ──────────────────────────────────────────────── */
/* A wood plank pinned to the bottom of the felt page — the same material as the
   top nav — carrying the legal links in cream so it reads as part of the chrome.
   The .page flex column + .page-main flex:1 push it to the bottom on short pages. */
.site-footer {
  flex: 0 0 auto;
  background-color: var(--wood-dark);
  color: var(--cream);
  border-top: 2px solid var(--wood-edge);
  box-shadow: inset 0 2px 0 var(--wood-light), 0 -2px 8px rgba(40, 25, 10, .22);
}

.site-footer-links {
  max-width: 70rem;
  margin: 0 auto;
  padding: 0.85rem 1.25rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 1.5rem;
}

.site-footer-links a {
  color: var(--kraft-light);
  font-weight: 600;
  text-decoration: none;
}

.site-footer-links a:hover,
.site-footer-links a:focus-visible {
  color: #fff;
  text-decoration: underline;
}

/* Copyright notice (Phase 21.1) — cream, not a link, so it reads as the chrome's
   own claim sitting beside the legal links rather than another navigable page. */
.site-footer-copyright {
  color: var(--cream);
  font-weight: 600;
}

/* ── Cookie consent banner (Phase 17.3, ePrivacy/GDPR) ─────────────────────── */
/* A wood plank pinned to the bottom of the viewport — the same material as the top
   nav — so it reads as part of the chrome, not the paper content sheet. Shown only
   when a non-essential cookie exists and no choice has been made yet. */
.cookie-consent {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 1080;
  background-color: var(--wood-dark);
  color: var(--cream);
  box-shadow: 0 -4px 14px rgba(40, 25, 10, .34), inset 0 2px 0 var(--wood-light);
  border-top: 2px solid var(--wood-edge);
}

.cookie-consent-inner {
  max-width: 70rem;
  margin: 0 auto;
  padding: 0.85rem 1.25rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
}

.cookie-consent-text {
  margin: 0;
  flex: 1 1 22rem;
  font-size: 0.95rem;
  line-height: 1.45;
}

.cookie-consent-link {
  color: var(--kraft-light);
  text-decoration: underline;
  white-space: nowrap;
}

.cookie-consent-link:hover,
.cookie-consent-link:focus-visible {
  color: #fff;
}

.cookie-consent-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
}

.cookie-consent-accept,
.cookie-consent-decline {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
  border-radius: 0.5rem;
  padding: 0.45rem 1rem;
  cursor: pointer;
  border: 1px solid transparent;
}

.cookie-consent-accept {
  color: var(--ink);
  background-color: var(--kraft);
  box-shadow: inset 0 2px 0 var(--kraft-light), inset 0 -3px 0 var(--kraft-dark);
}

.cookie-consent-accept:hover,
.cookie-consent-accept:focus-visible {
  background-color: var(--kraft-light);
}

.cookie-consent-decline {
  color: var(--cream);
  background-color: transparent;
  border-color: var(--kraft-light);
}

.cookie-consent-decline:hover,
.cookie-consent-decline:focus-visible {
  background-color: var(--wood);
}

/* Themed loading state — an amber spinner on warm paper, replacing bare "Loading…"
   text. Used by the page-level loaders (gallery, design detail, My-designs). */
.loading-state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 2.5rem 1.5rem;
  color: var(--ink-soft);
  font-family: var(--font-display);
  font-size: 1.05rem;
}

.loading-spinner {
  width: 1.5rem;
  height: 1.5rem;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 3px solid var(--paper-line);
  border-top-color: var(--accent);
  animation: loading-spin 0.8s linear infinite;
}

/* Inline variant — sits next to a button label (e.g. the "Optimizing…" CTA);
   tinted to the cream label so it reads on the amber/wood key. */
.loading-spinner--inline {
  width: 1rem;
  height: 1rem;
  margin-right: 0.5rem;
  vertical-align: -0.15em;
  border-color: rgba(244, 233, 210, 0.4);
  border-top-color: var(--cream);
}

@keyframes loading-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Respect reduced-motion: stop the spin, keep the amber arc as a static cue. */
@media (prefers-reduced-motion: reduce) {
  .loading-spinner {
    animation: none;
  }
}

/* Friendly empty states with the amber brand meeple / box glyph + a CTA. */
.empty-state {
  background-color: var(--paper);
  border: 1px dashed var(--paper-line);
  border-radius: var(--radius);
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--ink-soft);
}

.empty-state-art {
  color: var(--accent);
  margin-bottom: 0.5rem;
}

.empty-state-text {
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 1.15rem;
  margin: 0 0 1rem;
}

/* Card sub-parts the cozy cards share (gallery, My-designs, candidates). */
.card-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10px 10px 0;
  padding: 6px;
  border-radius: var(--radius-sm);
  /* Transparent: the thumbnail PNG is keyed to transparency (its OpenSCAD background is removed), so
     the model sits directly on the kraft card with no inset box. */
  background-color: transparent;
  overflow: hidden;
}

.card-thumb img {
  border-radius: var(--radius-sm);
}

.card-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.card-by {
  color: var(--ink); /* on kraft — AA (ink-soft on kraft is 3.51:1) */
  font-size: 0.82rem;
  margin: 0 0 0.5rem;
}

/* A neutral kraft chip — the "tile" for visibility/license/revision tokens.
   Ink on kraft (the direction's "kraft chips with ink text"): kraft-dark + ink
   is 5.71:1 (AA), replacing the 2.83:1 kraft-deep + cream. */
.badge.badge-chip {
  background-color: var(--kraft-dark);
  color: var(--ink);
}

/* ── HOME hero + feature cards ─────────────────────────────────────────────── */
.home-hero {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 28px;
  align-items: center;
  padding: 0.5rem 0 1.5rem;
}

.home-hero h1 {
  font-size: 2.4rem;
  color: var(--ink);
  margin-bottom: 0.3em;
}

.home-hero-lead {
  font-size: 1.15rem;
  color: var(--ink-soft);
  max-width: 44ch;
  margin-bottom: 1.25rem;
}

.home-hero-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.home-hero-art {
  display: flex;
  justify-content: center;
}

.home-hero-frame {
  transform: rotate(-2deg);
  max-width: 100%;
}

.home-hero-tray svg {
  width: 100%;
  height: auto;
}

.home-features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin-top: 0.5rem;
}

.home-feature .card-body {
  padding: 1.1rem 1.25rem 1.25rem;
}

.home-feature-step {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.2rem;
  color: var(--ink);
  margin: 0 0 0.35rem;
}

.home-feature-text {
  color: var(--ink); /* feature cards are kraft — AA (ink-soft on kraft is 3.51:1) */
  font-size: 0.92rem;
  margin: 0;
}

/* The "Sign in" hero link sits beside the two button CTAs as a quieter third option (anonymous only). */
.home-signin {
  align-self: center;
}

/* ── HOME headline-counts strip ───────────────────────────────────────────── */
/* Three wood-framed paper tiles — big Fredoka numbers over a quiet label, the
   counts that "sell the community" (designs · makers · prints). */
.home-stats {
  margin: 1.75rem 0 0.5rem;
}

.home-stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.home-stat-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 1.1rem 0.75rem;
  border: 3px solid var(--wood);
  border-radius: var(--radius-lg);
  background-color: var(--paper);
  box-shadow: var(--shadow-soft), inset 0 1px 0 var(--wood-light);
}

.home-stat-number {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 2.4rem;
  line-height: 1.05;
  color: var(--wood-dark);
}

.home-stat-label {
  margin-top: 0.2rem;
  color: var(--ink); /* ink on paper — AA */
  font-size: 0.95rem;
}

/* ── HOME showcase (Popular + Recent public designs) ──────────────────────── */
.home-showcase {
  margin-top: 2rem;
}

.home-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  margin-bottom: 0.85rem;
}

.home-section-head h2 {
  margin: 0;
  font-family: var(--font-display);
  color: var(--ink);
}

.home-section-note {
  color: var(--ink); /* ink on paper (these sections sit on the .content paper sheet) — AA */
  font-size: 0.95rem;
}

.home-showcase-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}

/* A showcase card mirrors the gallery card: kraft body, warm paper thumbnail inset. */
.home-showcase-card .card-body {
  display: flex;
  flex-direction: column;
}

.home-showcase-card-name {
  margin: 0.15rem 0 0.1rem;
}

.home-showcase-card-name a {
  color: var(--ink);
  text-decoration: none;
}

.home-showcase-card-name a:hover,
.home-showcase-card-name a:focus-visible {
  text-decoration: underline;
}

.home-showcase-card-owner {
  color: var(--ink); /* ink on kraft for AA */
  margin: 0 0 0.5rem;
}

/* Engagement chips: heart + likes, star + average, make + prints. Icon-only marks
   are aria-hidden and each <li> carries an aria-label, so meaning never relies on
   the glyph alone (WCAG, §19). */
.home-card-stats {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.9rem;
  margin: auto 0 0;
  padding: 0.55rem 0 0;
  border-top: 1px solid var(--kraft-deep);
}

.home-card-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--ink); /* ink on kraft — AA */
  font-size: 0.9rem;
}

.home-card-stat-icon {
  color: var(--accent-deep);
  font-size: 0.95rem;
  line-height: 1;
}

.home-card-stat-value {
  font-variant-numeric: tabular-nums;
}

.home-showcase-more {
  margin-top: 1rem;
  display: flex;
  justify-content: center;
}

/* ── HOME empty-state (no public designs yet) ─────────────────────────────── */
.home-empty {
  margin-top: 1.75rem;
}

.home-empty-heading {
  font-family: var(--font-display);
  color: var(--ink);
  margin: 0.4rem 0 0.25rem;
}

/* ── HOME "how it works" + closing CTA band ───────────────────────────────── */
.home-how {
  margin-top: 2.25rem;
}

.home-how .home-section-head {
  justify-content: center;
}

.home-closing {
  margin-top: 2.5rem;
  padding: 1.75rem 1.5rem;
  text-align: center;
  border-radius: var(--radius-lg);
  background-color: var(--felt);
  box-shadow: var(--shadow-inset);
}

.home-closing h2 {
  font-family: var(--font-display);
  color: var(--cream);
  margin: 0 0 0.35rem;
}

.home-closing-lead {
  color: var(--cream);
  margin: 0 auto 1.1rem;
  max-width: 52ch;
}

.home-closing-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

/* Responsive: collapse the stat + showcase + feature grids to one column on phones. */
@media (max-width: 720px) {
  .home-stats-grid,
  .home-showcase-grid,
  .home-features {
    grid-template-columns: 1fr;
  }
}

/* ── EDITOR (wood-framed paper sections + amber CTA + score meter) ─────────── */
/* Each fieldset is a "tray frame": a paper sheet with a chunky wood border (the
   frame) and the legend riding the wood as a cream tab (visual-direction §5). */
.editor-section {
  border: 4px solid var(--wood);
  border-radius: var(--radius-lg);
  padding: 0.4rem 1.1rem 1.1rem;
  margin-bottom: 1.25rem;
  background-color: var(--paper);
  color: var(--ink);
  box-shadow: var(--shadow-soft), inset 0 1px 0 var(--wood-light);
}

.editor-section-legend {
  float: none;
  width: auto;
  margin: 0;
  padding: 0.15rem 0.85rem;
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--cream);
  background-color: var(--wood);
  box-shadow: inset 0 2px 0 var(--wood-light), inset 0 -2px 0 var(--wood-dark);
}

.editor-section .form-label,
.editor-section .form-check-label,
.editor-section .col-form-label {
  color: var(--ink);
}

/* Tray-colour swatches (Phase 14.2): compact, wood-framed colour wells so they read as deliberate
   "paint chips" on the paper editor section rather than full-width inset text wells. */
.tray-colors .form-control-color {
  width: 3.25rem;
  height: 2.4rem;
  padding: 0.2rem;
  background-color: var(--paper-dim);
  border: 1px solid var(--kraft-dark);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

/* The candidate picker — choosable kraft cards, not a spreadsheet. */
.candidate-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
  margin-top: 1rem;
}

.candidate-card {
  display: flex;
  flex-direction: column;
}

.candidate-thumb {
  aspect-ratio: 1 / 1; /* square, matching the square thumbnail render + viewport */
}

.candidate-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.candidate-preview-missing {
  color: var(--ink-soft);
}

/* Live per-element preview (Phase 26.1): a small thumbnail in each deck/token/mini row that updates
   (debounced) as the element's fields change, or a "doesn't fit" cue when it overflows the bed. */
.element-preview {
  display: flex;
  align-items: center;
  justify-content: center;
}

.element-preview-img {
  border: 1px solid var(--line, rgba(0, 0, 0, 0.1));
  border-radius: 4px;
  object-fit: contain;
}

.element-preview-missing {
  display: inline-block;
  max-width: 6rem;
  line-height: 1.1;
  text-align: center;
}

.candidate-strategy {
  font-size: 1.1rem;
  margin: 0 0 0.15rem;
}

.candidate-modules {
  margin: 0.5rem 0 0.75rem;
  color: var(--ink-soft);
  font-size: 0.85rem;
}

.candidate-modules summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--ink);
}

/* A friendly amber score meter (relative quality across the candidate set). */
.score-meter {
  height: 8px;
  border-radius: 4px;
  background: var(--paper-dim);
  overflow: hidden;
  margin: 0.25rem 0 0.5rem;
  box-shadow: inset 0 1px 2px rgba(40, 25, 10, 0.2);
}

.score-meter > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-deep));
}

/* ── DESIGN DETAIL (wood-framed viewer hero + community paper sub-panels) ──── */

/* TOP HEADER BAND: the design's identity (left) beside the linked BGG game card
   (right). The columns mirror the content grid below (.detail-content) — the SAME
   minmax(0,2fr)/minmax(0,1fr) split — so the BGG card's right column lines up with
   and matches the width of the Assembly/Download/Manage sidebar panels, forming one
   consistent right rail. Collapses to one column on narrow screens, so the game
   card stacks below the identity instead of overflowing. */
.detail-header {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  margin-bottom: var(--space-5);
}

.detail-header-main {
  min-width: 0; /* let the title/description wrap instead of forcing overflow */
}

.detail-title {
  margin-bottom: var(--space-3);
}

.detail-header .design-description {
  margin-bottom: var(--space-3);
}

/* The identity meta row: status, licence, rating + likes as wrapping chips on
   one tidy line (each item baseline-aligned). */
.detail-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-3);
}

.detail-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* The licence chip uses the kraft chip styling (.badge-chip); keep it readable
   inline with the surrounding meta text. */
.detail-meta .license-label {
  font-weight: 700;
}

/* The rating aggregate + star widget sit together in the meta; keep the stars
   inline (not a block) so they ride the meta row. */
.detail-meta .rating-widget {
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
}

.detail-meta .rating-average {
  font-size: 1.05rem;
}

/* The BGG game card in the header: it fills the FULL WIDTH of the header's right
   column — which now matches the content grid's right (sidebar) track — so the card
   lines up with and is the same width as the Assembly/Download/Manage panels below
   it, with the cover + title + attribution logo reading cleanly without overflow. */
.detail-header-game {
  width: 100%;
  max-width: 100%;
  margin: 0;
}

/* The official "Powered by BoardGameGeek" logo (BGG ToS §19.4): max-width:100% +
   height:auto keep the asset's 342×76 (4.5:1) aspect ratio while scaling it DOWN to
   fit the now-narrower card (matching the sidebar width), never exceeding its
   container — so it stays crisp and never forces horizontal overflow. */
.game-card-bgg-logo {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  margin-top: 6px;
}

/* The text fallback shown only if the logo image fails to load — the attribution
   is never lost (BGG ToS). Styled like the former text link. */
.game-card-bgg-fallback {
  display: inline-block;
  margin-top: 4px;
  color: var(--accent);
  text-decoration: underline;
}

/* Stack the header to one column on narrow screens: the game card drops below the
   identity and spans the full width, so nothing overflows horizontally. */
@media (max-width: 768px) {
  .detail-header {
    grid-template-columns: 1fr;
  }

  .detail-header-game {
    width: 100%;
  }
}

/* The grouped owner/fork controls cluster beside the viewer (replaces the former
   stack of separate full-width panels). A subtle divider separates the owner's
   lifecycle/sharing block from the always-present fork action. */
.detail-controls-divider {
  border: 0;
  border-top: 1px solid var(--kraft-dark);
  opacity: 0.6;
  margin: var(--space-3) 0;
}

.detail-spec-summary {
  margin-bottom: var(--space-3);
}

/* CONTENT AREA: a two-column grid — the 3D viewer (col 1) beside the Download +
   Manage sidebar (col 2). The Comments + Community-prints sections live INSIDE the
   left (viewer) column, stacked directly below the viewer at the SAME WIDTH — a
   standard content+sidebar layout, with the right rail (Assembly/Download/Manage)
   naturally shorter than the left content column. On a narrow screen it collapses to
   one column so everything stacks (viewer, its community sections, then the sidebar)
   with no horizontal overflow. */
.detail-content {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
}

/* Both content columns clamp to their track (min-width:0) so a wide viewer canvas
   or a long share URL never forces the page to scroll horizontally. */
.detail-viewer-col,
.detail-sidebar-col {
  min-width: 0;
}

/* The "not optimized yet" placeholder occupies the whole grid (its own row); the
   community sections trail it within this same single column. */
.detail-no-spec {
  grid-column: 1 / -1;
}

/* The community sections sit in the LEFT (viewer) column beneath the viewer (and,
   in the no-spec branch, beneath the notice) — they are NOT grid items, so they
   simply flow at the column's width. The .community-section base margin (below)
   gives the first one its spacing under the viewer. */

@media (max-width: 992px) {
  .detail-content {
    grid-template-columns: 1fr;
  }
}

.viewer-frame {
  margin-bottom: 0.5rem;
}

/* The owner share-link row: the read-only URL field beside its Copy button as a
   single input-group, so the button sits flush against the field. */
.share-link-group {
  flex-wrap: nowrap;
}

.share-link-group .share-link {
  min-width: 0; /* let the URL field shrink within the group instead of overflowing */
}

/* Community sections (comments + prints): they live in the LEFT (viewer) column of
   .detail-content, stacked beneath the viewer at the viewer's width (no grid span).
   The top margin separates them from the viewer (and from each other). */
.community-section {
  margin-top: 1.5rem;
}

.community-section h2 {
  margin-top: 0;
}

.rating-star {
  color: var(--accent);
  font-size: 1.4rem;
  line-height: 1;
}

.rating-star.unrated {
  color: var(--paper-line);
}

.rating-average {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.3rem;
  color: var(--ink);
}

/* ── AUTH (centered paper card on felt with the logo on top) ───────────────── */
.auth-wrap {
  display: flex;
  justify-content: center;
  padding: 1rem 0 2rem;
}

.auth-card {
  width: 100%;
  max-width: 26rem;
  padding: 2rem 1.75rem;
}

.auth-brand {
  text-align: center;
  margin-bottom: 1.25rem;
}

.auth-logo {
  filter: drop-shadow(0 1px 2px rgba(40, 25, 10, 0.35));
}

.auth-brand h1 {
  font-size: 1.7rem;
  color: var(--ink);
  margin: 0.5rem 0 0.25rem;
}

.auth-sub {
  color: var(--ink-soft);
  margin: 0;
}

.auth-alt {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--paper-line);
  text-align: center;
  color: var(--ink-soft);
}

/* ── Responsive: stack the multi-column page bodies on narrow screens ──────── */
@media (max-width: 860px) {
  .home-hero {
    grid-template-columns: 1fr;
  }

  .home-features {
    grid-template-columns: 1fr;
  }
}
