/* ============================================================
   SUPPORT CENTRE by Theodore HQ - production stylesheet.
   Lifted near-verbatim from the approved design mockup at
   prototypes/support-dashboard-2026-07-02/refined.html.
   Product accent variables (--c-<product>) and the
   body[data-product] accent bindings are generated per page
   from products.json at build time, so adding a product needs
   no CSS change. Static-site additions (stretched card links,
   the submission modal, form confirmations) live at the end.
   ============================================================
   Original mockup design notes:
   Cool neutral canvas (layered shadows + ambient glow field)
   + deeper per-product accent immersion. Kanban boards share
   the overview panels' design language, full multi-bullet
   release notes on the changelog timeline, section-level add
   buttons, item detail views with reply threads and a comment
   form, FAQ subtitles, delight pass. v8: equal-height home
   card stat strips and overview panels, concentric square "+"
   buttons, quiet "Search /" keyboard-hint chips instead of
   visible search bars, testimonial country flags, and a
   redesigned detail top bar (bordered back button + context).
   v9: glassy landing-page wordmark, subgrid stat strips that
   grow together, FAQ overview rows that fill their panel, and
   section toolbars merged into the header row.
   v10: home card bodies hug their content at every width (the
   tagline-to-strip gap stays constant), ink wordmark on home
   with product-tinted gradient fills inside a product, 4-row
   FAQ overview preview, accent highlight rings on search
   matches, testimonials newest-first everywhere, and section
   intent carrying from consolidated views into products.
   v11: framed layout - the whole window is one continuous
   accent-breathing frame surface, the sidebar sits glassily on
   it (transparent, subtle vertical tint, backdrop blur), and
   the content lives in a rounded panel inset from the top,
   right, and bottom edges, scrolling inside while the frame
   stays put. Slightly larger wordmark, contextual add buttons
   only (no generic New Post, no add on Roadmap or Changelog),
   and the home proof line retired.
   ============================================================ */

/* Registered so accent changes interpolate smoothly everywhere,
   including inside color-mix() and gradients (the atmosphere wash). */
@property --accent {
  syntax: "<color>";
  inherits: true;
  initial-value: #62676f;
}

/* Registered so the sidebar's glassy tint strength cross-fades
   smoothly when stepping into and out of a product. */
@property --side-tint {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 5%;
}

:root {
  --font: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --accent-ms: 400ms;
  /* Product brand colours (--c-<product>) are injected per page
     from products.json - see the generated style block in <head>. */
}

[data-theme="light"] {
  /* v11 frame: cool neutral field hosting the sidebar, with the
     content floating inside a white panel */
  --canvas: #f2f3f5;
  --panel: #ffffff;
  --surface: #ffffff;
  --surface-hover: #f6f7f9;
  --inset: #e9ebef;
  --ink: #1a1c20;
  --ink-2: #676d78;
  --ink-3: #969ca7;
  --home-ink: #42474f;
  --home-sub: #71767f;
  --hairline: rgba(20, 24, 33, 0.08);
  --hairline-strong: rgba(20, 24, 33, 0.14);
  --sidebar-hover: rgba(20, 24, 33, 0.045);
  --glow-2: rgba(132, 152, 191, 0.07);

  --c-home: #545962;

  /* Accent mix recipe: darken for text so amber passes contrast on white */
  --accent-mix-base: #171a20;
  --accent-mix-pct: 55%;
  --accent-tint-pct: 8%;
  --accent-tint2-pct: 14%;
  --on-accent: #ffffff;
  /* Whisper-level: the frame outside the panel carries the product
     colour; the panel interior stays essentially white. */
  --wash-pct: 4%;
  --wash-soft: 1.5%;

  --shadow-card:
    0 1px 1px rgba(21, 27, 40, 0.03),
    0 3px 8px rgba(21, 27, 40, 0.04),
    0 12px 28px -10px rgba(21, 27, 40, 0.07);
  --shadow-card-hover:
    0 1px 2px rgba(21, 27, 40, 0.04),
    0 6px 16px rgba(21, 27, 40, 0.06),
    0 24px 48px -16px rgba(21, 27, 40, 0.13);
  --shadow-panel:
    0 1px 2px rgba(21, 27, 40, 0.03),
    0 12px 34px -14px rgba(21, 27, 40, 0.10);

  /* Kanban column glyph colours: review gets a dusty slate-teal,
     done a properly vibrant green so the check reads at a glance */
  --st-review: #47807d;
  --st-done: #1aa04e;

  /* Whisper bar marks: saturated status colours for the home cards'
     3px segmented progress bar (and its All Clear tick) */
  --bar-review: #c88a04;
  --bar-planned: #5b82a6;
  --bar-progress: #7a6ce0;
  --bar-done: #1aa04e;

  --pill-review-bg: #fbf3db;   --pill-review-text: #8a5d00;
  --pill-planned-bg: #e8eef5;  --pill-planned-text: #3f617f;
  --pill-progress-bg: #efecfc; --pill-progress-text: #5747c0;
  --pill-done-bg: #e9f2e8;     --pill-done-text: #33683a;
  --pill-declined-bg: #edeef1; --pill-declined-text: #757a84;
  --tag-bug-bg: #fdecea;       --tag-bug-text: #a1352e;
  --tag-feature-bg: #e5f1fd;   --tag-feature-text: #1f639c;
}

[data-theme="dark"] {
  /* v11 frame: deep cool graphite field, panel a shade lifted so
     the surfaces inside step lighter again */
  --canvas: #121318;
  --panel: #17191f;
  --surface: #1b1d24;
  --surface-hover: #20232b;
  --inset: #0e1015;
  --ink: #e9ebef;
  --ink-2: #9ba1ac;
  --ink-3: #717783;
  --home-ink: #d7dbe2;
  --home-sub: #99a0ab;
  --hairline: rgba(226, 235, 255, 0.09);
  --hairline-strong: rgba(226, 235, 255, 0.16);
  --sidebar-hover: rgba(226, 235, 255, 0.05);
  --glow-2: rgba(122, 144, 194, 0.06);

  --c-home: #c2c8d2;

  /* Lighten accents so they read on the deep field */
  --accent-mix-base: #eef1f6;
  --accent-mix-pct: 62%;
  --accent-tint-pct: 11%;
  --accent-tint2-pct: 18%;
  --on-accent: #13151b;
  --wash-pct: 6%;
  --wash-soft: 2%;

  --shadow-card:
    0 1px 1px rgba(0, 0, 0, 0.2),
    0 4px 10px rgba(0, 0, 0, 0.22),
    0 16px 36px -12px rgba(0, 0, 0, 0.4);
  --shadow-card-hover:
    0 1px 2px rgba(0, 0, 0, 0.25),
    0 8px 20px rgba(0, 0, 0, 0.3),
    0 28px 56px -16px rgba(0, 0, 0, 0.55);
  --shadow-panel:
    0 1px 2px rgba(0, 0, 0, 0.28),
    0 16px 44px -18px rgba(0, 0, 0, 0.5);

  --st-review: #6fb5b0;
  --st-done: #3fd472;

  /* Whisper bar marks lift to the dark pill-text brights so the
     3px segments stay legible on the deep field */
  --bar-review: #ddb066;
  --bar-planned: #9dbbd4;
  --bar-progress: #a99ef5;
  --bar-done: #3fd472;

  --pill-review-bg: rgba(226, 178, 100, 0.13);  --pill-review-text: #ddb066;
  --pill-planned-bg: rgba(139, 170, 198, 0.13); --pill-planned-text: #9dbbd4;
  --pill-progress-bg: rgba(148, 138, 248, 0.14);--pill-progress-text: #a99ef5;
  --pill-done-bg: rgba(101, 173, 110, 0.13);    --pill-done-text: #8cc494;
  --pill-declined-bg: rgba(240, 246, 255, 0.07);--pill-declined-text: #8a909c;
  --tag-bug-bg: rgba(236, 106, 94, 0.13);       --tag-bug-text: #e08a80;
  --tag-feature-bg: rgba(94, 156, 242, 0.13);   --tag-feature-text: #85b4ef;
}

/* Per-product accent, swapped on one wrapper attribute.
   Derivations are computed on body AND on any element that
   locally overrides --accent (the home product cards). */
body, .pcard {
  --accent-ink: color-mix(in srgb, var(--accent) var(--accent-mix-pct), var(--accent-mix-base));
  --accent-tint: color-mix(in srgb, var(--accent) var(--accent-tint-pct), transparent);
  --accent-tint-2: color-mix(in srgb, var(--accent) var(--accent-tint2-pct), transparent);
  --glow-1: color-mix(in srgb, var(--accent) 8%, transparent);
  /* Deep accent: a dark, saturated take on the product colour for the
     official-reply pill. Fixed dark base (not theme-mixed) so the pill
     reads the same rich navy/forest/amber in light and dark. */
  --accent-deep: color-mix(in oklab, var(--accent) 68%, #0a1222);
}

body[data-product="home"] { --accent: var(--c-home); }
/* body[data-product="<id>"] accent bindings are generated per page
   from products.json - see the style block in <head>. */

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  /* The frame surface leans toward the active product's accent;
     the lean deepens when you step inside a product, so the whole
     frame around the panel breathes the product colour. */
  --canvas-mix: 2%;
  --side-tint: 5%;
  background: color-mix(in srgb, var(--accent) var(--canvas-mix), var(--canvas));
  /* The stronger top tint spans the WHOLE frame (not just the sidebar
     column) so the colour wraps continuously around the content panel. */
  background-image: linear-gradient(180deg, color-mix(in srgb, var(--accent) var(--side-tint), transparent), transparent 62%);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  transition: background-color 400ms var(--ease-out), color 280ms var(--ease-out), --accent 400ms var(--ease-out), --side-tint 400ms var(--ease-out);
}

body[data-view="board"] { --canvas-mix: 9%; --side-tint: 10%; }
[data-theme="dark"] body[data-view="board"] { --canvas-mix: 12%; }

/* Ambient glow field (direction-2): two soft radials pinned to the
   frame, one accent-aware, one cool. They read on the frame margins
   and through the glassy sidebar; the panel carries its own pair. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(760px 420px at 26% -6%, var(--glow-1), transparent 68%),
    radial-gradient(680px 400px at 88% 4%, var(--glow-2), transparent 70%);
}

button { font-family: inherit; font-size: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input { font-family: inherit; }
a { color: inherit; text-decoration: none; }
input, textarea { caret-color: var(--accent-ink); }

::selection { background: var(--accent-tint-2); }

::-webkit-scrollbar { width: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  border-radius: 999px;
  background-clip: padding-box;
  border: 3px solid transparent;
}
::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--accent) 42%, transparent); background-clip: padding-box; }

:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 60%, transparent);
  outline-offset: 2px;
  border-radius: 6px;
}

.num { font-variant-numeric: tabular-nums; }

/* ============ Layout ============
   The window is one continuous frame surface. The sidebar sits
   directly on it; the content floats in a rounded panel inset from
   the top, right, and bottom edges and scrolls INSIDE, so the frame
   never moves. */

.app { position: relative; z-index: 1; display: flex; height: 100vh; }

.main {
  position: relative;
  flex: 1;
  min-width: 0;
  margin: 12px 12px 12px 264px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: 18px;
  box-shadow: var(--shadow-panel);
  overflow: hidden;
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

/* Panel-local ambient glows, clipped by the panel's radius.
   Softened well below the frame's glows so the panel interior
   reads essentially white. */
.main::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(760px 420px at 26% -6%, color-mix(in srgb, var(--glow-1) 35%, transparent), transparent 68%),
    radial-gradient(680px 400px at 88% 4%, color-mix(in srgb, var(--glow-2) 35%, transparent), transparent 70%);
}

/* Product atmosphere: light through a window. Amplified inside a
   product so the accent is unmistakable; a broad soft gradient runs
   behind the whole content column, inside the panel, and stays put
   while the content scrolls. Cross-fades on the morph. */
.main::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(1100px 640px at 55% -170px, color-mix(in srgb, var(--accent) var(--wash-pct), transparent), transparent 74%),
    linear-gradient(180deg, color-mix(in srgb, var(--accent) var(--wash-soft), transparent), transparent 62%);
  opacity: 0;
  transition: opacity 500ms var(--ease-out);
}

body[data-view="board"] .main::after { opacity: 1; }

.main-scroll {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 46px 48px 72px;
  /* Column flex so the site footer's margin-top: auto pins it to the
     bottom of the panel on short pages (see "Site footer" below). */
  display: flex;
  flex-direction: column;
}

.view { max-width: 992px; width: 100%; flex: 0 0 auto; }

/* ============ Sidebar ============
   No panel of its own: it sits glassily on the frame surface, a
   near-transparent vertical tint with a touch of backdrop blur, so
   sidebar and frame read as one piece around the content panel. */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 10; /* stays above animated views if the window is narrow */
  width: 264px;
  display: flex;
  flex-direction: column;
  padding: 30px 16px 20px;
  -webkit-backdrop-filter: blur(10px) saturate(1.35);
  backdrop-filter: blur(10px) saturate(1.35);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 10px;
  margin-bottom: 28px;
  text-align: left;
}

.brand-mark {
  width: 28px; height: 28px;
  border-radius: 8px;
  object-fit: contain;
  flex-shrink: 0;
  transition: transform 260ms var(--ease-spring);
}

.brand:hover .brand-mark { transform: scale(1.06) rotate(-4deg); }

/* Sidebar wordmark: Plus Jakarta Sans uppercase, THEODORE at 800 /
   HQ at 700, tight -0.04em tracking. On home and consolidated views
   it is a clean ink fill (theme-appropriate). Inside a product it
   takes the landing page's gradient text fills, built from the
   product accent, so the fills ride the registered --accent morph
   and tint smoothly over the same 400ms. */
.brand-word {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  line-height: 0.95;
  white-space: nowrap;
}

.bw-theodore,
.bw-hq {
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* Home + consolidated: solid ink, no glass */
  background-image: linear-gradient(var(--ink), var(--ink));
}

.bw-hq { font-weight: 700; }

/* Inside a product: the landing page's exact gradient-fill mechanism.
   THEODORE carries a soft glass sheen over the accent ramp. */
body[data-view="board"] .bw-theodore {
  background-image:
    linear-gradient(to bottom, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.07) 30%, rgba(255,255,255,0) 56%),
    linear-gradient(176deg, color-mix(in oklab, var(--accent) 94%, #fff 6%) 0%, var(--accent) 30%, color-mix(in oklab, var(--accent) 86%, #08101b 14%) 72%, color-mix(in oklab, var(--accent) 78%, #08101b 22%) 100%);
}

/* HQ: same structure with a slightly brighter sheen */
body[data-view="board"] .bw-hq {
  background-image:
    linear-gradient(to bottom, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0.07) 30%, rgba(255,255,255,0) 56%),
    linear-gradient(176deg, color-mix(in oklab, var(--accent) 94%, #fff 6%) 0%, var(--accent) 30%, color-mix(in oklab, var(--accent) 86%, #08101b 14%) 72%, color-mix(in oklab, var(--accent) 78%, #08101b 22%) 100%);
}

/* Dark mode biases the mix stops toward #fff so the tint stays luminous */
[data-theme="dark"] body[data-view="board"] .bw-theodore {
  background-image:
    linear-gradient(to bottom, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.07) 30%, rgba(255,255,255,0) 56%),
    linear-gradient(176deg, color-mix(in oklab, var(--accent) 80%, #fff 20%) 0%, color-mix(in oklab, var(--accent) 92%, #fff 8%) 30%, var(--accent) 72%, color-mix(in oklab, var(--accent) 90%, #08101b 10%) 100%);
}

[data-theme="dark"] body[data-view="board"] .bw-hq {
  background-image:
    linear-gradient(to bottom, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0.07) 30%, rgba(255,255,255,0) 56%),
    linear-gradient(176deg, color-mix(in oklab, var(--accent) 76%, #fff 24%) 0%, color-mix(in oklab, var(--accent) 88%, #fff 12%) 30%, var(--accent) 72%, color-mix(in oklab, var(--accent) 90%, #08101b 10%) 100%);
}

.side-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0 10px;
  margin-bottom: 7px;
}

.side-list { list-style: none; }
.side-list li + li { margin-top: 1px; }

.side-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 10px;
  border-radius: 9px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink-2);
  text-align: left;
  transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out);
}

.side-item:hover { background: var(--sidebar-hover); color: var(--ink); }

.side-item.is-active {
  background: var(--accent-tint);
  color: var(--accent-ink);
  font-weight: 600;
}

.side-item .nav-icon {
  width: 15px; height: 15px;
  flex-shrink: 0;
  color: var(--ink-3);
  transition: color 180ms var(--ease-out), transform 220ms var(--ease-spring);
}

.side-item:hover .nav-icon { color: var(--ink-2); transform: translateX(1px); }
.side-item.is-active .nav-icon { color: var(--accent-ink); }

.home-block { margin-bottom: 24px; }
.products-block { margin-bottom: 24px; }

/* Real app icons */
.picon {
  display: block;
  object-fit: contain;
  flex-shrink: 0;
}

.side-item .picon {
  width: 20px; height: 20px;
  transition: transform 220ms var(--ease-spring);
}

.side-item:hover .picon { transform: scale(1.08); }

/* Shiny ships a dark-tile variant that sits better on charcoal */
[data-theme="dark"] .picon[data-icon="shiny"] { content: url("/assets/favicons/shiny-dark.png"); }

.count {
  margin-left: auto;
  min-width: 21px;
  padding: 1px 7px;
  border-radius: 999px;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  background: var(--sidebar-hover);
  transition: background-color 240ms var(--ease-out), color 240ms var(--ease-out);
}

.side-item.is-active .count {
  background: var(--accent-tint-2);
  color: var(--accent-ink);
}

/* Browsing from home: no number counts on the Browse categories */
body:not([data-view="board"]) .board-nav .count { display: none; }

/* ============ Views ============ */

.view { display: none; }
.view.is-active { display: block; animation: view-in 380ms var(--ease-out) both; }

@keyframes view-in {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ============ Home view ============ */

.home-head { margin-bottom: 36px; }

.home-head h1 {
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.2;
  color: var(--home-ink);
  transition: color 280ms var(--ease-out);
}

.home-sub {
  font-size: 14.5px;
  color: var(--home-sub);
  margin-top: 6px;
  max-width: 52ch;
  transition: color 280ms var(--ease-out);
}

/* Cards span two shared subgrid rows: body + whisper footer. Both
   tracks size to content (auto): the footer row is one common track,
   so when ANY caption wraps to two lines (narrow viewport) every
   card's footer grows to match; the body track hugs its tallest
   content with no min-height padding, and any slack inside a shorter
   card gathers above the name block, so the tagline-to-footer gap
   stays at its regular comfortable spacing at every width. */
.product-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: auto auto;
  align-items: stretch;
  gap: 12px;
  margin-bottom: 46px;
}

.pcard {
  --accent: var(--pc);
  position: relative;
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 2;
  text-align: left;
  border-radius: 15px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition:
    border-color 260ms var(--ease-out),
    box-shadow 260ms var(--ease-out),
    transform 260ms var(--ease-out),
    background-color 280ms var(--ease-out);
}

/* Whole-card accent ring on hover: the border warms to the accent
   and a 1px shadow ring doubles it to ~2px, plus a soft outer glow */
.pcard:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent) 60%, var(--hairline));
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent),
    0 6px 16px rgba(21, 27, 40, 0.06),
    0 18px 42px -14px color-mix(in srgb, var(--accent) 38%, transparent);
}

.pcard:active { transform: translateY(0) scale(0.985); }

/* Row 1 of the subgrid: icon, name, tagline */
.pcard-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 17px 16px 0;
  min-width: 0;
}

/* Top row: icon and name inline, vertically centred. */
.pcard-top {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  margin-bottom: 9px;
}

.pcard .picon {
  width: 30px; height: 30px;
  flex-shrink: 0;
  transition: transform 280ms var(--ease-spring);
}

.pcard:hover .picon { transform: scale(1.08) rotate(-3deg); }

.pcard-name {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* One tagline, fitting on one physical line where it can and wrapping
   to a graceful maximum of two lines where it cannot. The reserved
   two-line min-height keeps every card's body track equal via the
   shared subgrid, so all five stay the same height at every width. */
.pcard-tagline {
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-2);
  min-height: calc(2 * 1.45em);
  margin-bottom: 12px;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* Progress whisper: one muted caption line over a 3px segmented
   status bar. Row 2 of the shared subgrid track: its height is the
   tallest footer's natural height, so all five cards always match at
   every width; the column bottom-aligns so a one-line caption sits
   flush with a wrapped one. All Clear cards keep the same two-line
   structure (tick + caption, calm full-width green bar). */
.pcard-whisper {
  padding: 0 16px 13px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 7px;
}

.wcap {
  display: flex;
  align-items: center;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.35;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  transition: color 280ms var(--ease-out);
}

.wcheck {
  width: 11px; height: 11px;
  flex-shrink: 0;
  color: var(--bar-done);
  opacity: 0.85;
  margin-right: 6px;
}

.wcheck svg { display: block; width: 100%; height: 100%; }

.wbar { display: flex; gap: 3px; height: 3px; }

.wseg { border-radius: 2px; min-width: 10px; }

.wseg-review   { background: var(--bar-review); }
.wseg-planned  { background: var(--bar-planned); }
.wseg-progress { background: var(--bar-progress); }
.wseg-done     { background: var(--bar-done); }
/* The settled share of an active product's bar: the same calm light green
   as the All Clear bar, so resolved work reads as baseline, not activity. */
.wseg-clear    { background: color-mix(in srgb, var(--bar-done) 22%, var(--inset)); }

.wbar.is-clear .wseg {
  flex: 1;
  min-width: 0;
  background: color-mix(in srgb, var(--bar-done) 22%, var(--inset));
}

/* Recent activity */
.activity {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 15px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

.activity-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 17px 22px 15px;
  border-bottom: 1px solid var(--hairline);
  transition: border-color 280ms var(--ease-out);
}

.activity-head h2 {
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.activity-head span {
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.activity-list { list-style: none; }

.activity-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 11.5px 22px;
  border-bottom: 1px solid var(--hairline);
  font-size: 13.5px;
  transition: background-color 180ms var(--ease-out), border-color 280ms var(--ease-out);
  animation: row-in 500ms var(--ease-out) calc(var(--i) * 45ms) both;
}

.activity-row:last-child { border-bottom: none; }
.activity-row:hover { background: var(--surface-hover); }

.activity-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--pc);
  margin-top: 6px;
}

.activity-product {
  font-weight: 700;
  font-size: 12.5px;
  flex-shrink: 0;
  min-width: 52px;
  padding-top: 1px;
}

.activity-main { flex: 1; min-width: 0; }

.activity-title {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.4;
}

.activity-sub {
  display: block;
  font-size: 12.5px;
  color: var(--ink-2);
  margin-top: 1px;
}

.activity-date {
  flex-shrink: 0;
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  padding-top: 1px;
}

/* ============ Board view ============ */

.board-head {
  display: flex;
  align-items: center;
  gap: 15px;
  margin-bottom: 30px;
}

/* When a section toolbar follows, the header hands most of its
   breathing room to the toolbar row. */
.board-head:has(+ .section-toolbar) { margin-bottom: 14px; }

.board-head .picon {
  width: 42px; height: 42px;
  flex-shrink: 0;
  filter: drop-shadow(0 6px 18px color-mix(in srgb, var(--accent) 55%, transparent));
  transition: filter var(--accent-ms) var(--ease-out);
}

[data-theme="dark"] .board-head .picon {
  filter: drop-shadow(0 6px 22px color-mix(in srgb, var(--accent) 75%, transparent));
}

.board-head h1,
.board-head .board-title {
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--ink);
}

.board-tagline {
  display: block;
  font-size: 13.5px;
  color: var(--ink-2);
  margin-top: 5px;
}

/* Pattern 1: clickable product identity (icon + name) links out to the
   product's marketing site. A hover-revealed external-link glyph plus a
   name colour/underline shift signal the link so it is never a mystery. */
.board-identity {
  display: flex;
  align-items: center;
  gap: 15px;
  min-width: 0;
  border-radius: 12px;
}

/* Stack the name above the tagline with clear separation - the two
   must never run together on one line. */
.board-id-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.board-identity .board-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: color 200ms var(--ease-out);
}

/* On hover the name shifts to the product accent as the only link
   signal (no underline, no external glyph); the icon gives a gentle
   micro-move. The explicit Visit button is the clear affordance. */
.board-identity:hover .board-title,
.board-identity:focus-visible .board-title { color: var(--accent-ink); }

.board-identity:hover .picon { transform: scale(1.05) rotate(-3deg); }

/* Pattern 2: explicit Visit link, pinned to the header's right.
   Quiet accent tint rather than a filled button: the header row is
   brand-level, and the one filled accent button on a section page
   should be its primary action (the add button in the toolbar). */
.board-visit {
  margin-left: auto;
  flex-shrink: 0;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border-radius: 9px;
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
  background: var(--accent-tint);
  color: var(--accent-ink);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transition: background-color var(--accent-ms) var(--ease-out), color var(--accent-ms) var(--ease-out), border-color var(--accent-ms) var(--ease-out), transform 220ms var(--ease-spring), box-shadow 220ms var(--ease-out);
}

.board-visit:hover {
  background: var(--accent-ink);
  border-color: var(--accent-ink);
  color: var(--on-accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--accent) 32%, transparent);
}

.board-visit:active { transform: scale(0.97); }

/* ============ Status glyphs ============
   One glyph family across kanban column heads: 13px circles,
   1.5px strokes, state-coloured. */

.st-glyph {
  width: 13px; height: 13px;
  flex-shrink: 0;
  transition: transform 240ms var(--ease-spring);
}

.st-glyph svg { display: block; width: 13px; height: 13px; }

.st-all .st-glyph      { color: var(--ink-3); }
.st-review .st-glyph   { color: var(--st-review); }
.st-planned .st-glyph  { color: var(--pill-planned-text); }
.st-progress .st-glyph { color: var(--pill-progress-text); }
.st-done .st-glyph     { color: var(--st-done); }
.st-declined .st-glyph { color: var(--pill-declined-text); }

/* Overview only exists inside a product */
body:not([data-view="board"]) #boardNav [data-nav="overview"] { display: none; }

/* Board sections (Overview / board / panel) */
.bsec { display: none; }
.bsec.is-active { display: block; animation: view-in 380ms var(--ease-out) both; }

/* Inside a product the surfaces themselves carry a faint accent tint,
   so the whole board reads as the product's world. */
body[data-view="board"] .ov-panel,
body[data-view="board"] .kcol,
body[data-view="board"] .group-list,
body[data-view="board"] .faq-list,
body[data-view="board"] .tcard,
body[data-view="board"] .thread,
body[data-view="board"] .comment-form,
body[data-view="board"] .tl-notes,
body[data-view="board"] .product-empty {
  background: color-mix(in srgb, var(--accent) 3%, var(--surface));
}

body[data-view="board"] .tcard {
  border-color: color-mix(in srgb, var(--accent) 18%, var(--hairline));
}

body[data-view="board"] .ov-card:hover,
body[data-view="board"] .ov-t:hover,
body[data-view="board"] .kcard:hover,
body[data-view="board"] .gitem:hover,
body[data-view="board"] .faq-q:hover,
body[data-view="board"] .ov-faq:hover {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface-hover));
}

/* ============ Overview kanban ============ */

/* 1fr auto rows: every row resolves to the tallest row's height,
   so all six panels always match regardless of their content.
   Short panels keep their content at the top and simply breathe. */
.ov-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 1fr;
  align-items: stretch;
  gap: 14px;
}

.ov-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  border-radius: 15px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  animation: row-in 480ms var(--ease-out) calc(var(--i) * 45ms) both;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out), box-shadow 240ms var(--ease-out), transform 240ms var(--ease-out);
}

.ov-panel:hover { transform: translateY(-1px); box-shadow: var(--shadow-card-hover); }

.ov-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 12px 16px 11px;
  text-align: left;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 20%, var(--hairline));
  transition: background-color 400ms var(--ease-out), border-color 400ms var(--ease-out);
}

.ov-head h2 { font-size: 13px; font-weight: 700; letter-spacing: -0.005em; }

.ov-count {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.ov-all {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--accent-ink);
  opacity: 0.72;
  transition: opacity 200ms var(--ease-out);
}

.ov-head:hover .ov-all { opacity: 1; }

/* Square "+" in the header of panels users can add to
   (Bugs, Features, Testimonials). Sits over the header button
   as a sibling so the markup stays valid. Concentric radius:
   panel 15px minus the 8px corner inset = 7px, so the two
   curves nest. */
.ov-panel.can-add .ov-head { padding-right: 48px; }

.ov-add {
  position: absolute;
  top: 8px; right: 8px;
  width: 27px; height: 27px;
  border-radius: 7px;
  display: grid;
  place-items: center;
  background: var(--accent-tint);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--accent-ink);
  z-index: 1;
  transition:
    background-color 200ms var(--ease-out),
    border-color 200ms var(--ease-out),
    color 200ms var(--ease-out),
    transform 240ms var(--ease-spring);
}

.ov-add:hover {
  background: var(--accent-tint-2);
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  transform: scale(1.1);
}

.ov-add:active { transform: scale(0.92); }
.ov-add svg { width: 12px; height: 12px; }

.ov-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 8px 10px;
}

.ov-card {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 9px;
  border-radius: 9px;
  font-size: 12.5px;
  transition: background-color 180ms var(--ease-out);
}

.ov-card:hover { background: var(--surface-hover); }

.ov-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.ov-title {
  min-width: 0;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ov-sub {
  font-size: 11.5px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ov-card .pill { flex-shrink: 0; font-size: 10.5px; padding: 1.5px 8px; }

.ov-vote {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
  padding: 2.5px 8px;
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition:
    border-color 220ms var(--ease-out),
    background-color 220ms var(--ease-out),
    color 220ms var(--ease-out),
    transform 260ms var(--ease-spring);
}

.ov-vote svg { width: 10px; height: 10px; }
.ov-vote:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--accent-ink);
  background: var(--accent-tint);
}
.ov-vote:active { transform: scale(0.93); }
.ov-vote.voted {
  background: var(--accent-tint-2);
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  color: var(--accent-ink);
}
.ov-vote.is-popping { animation: vote-pop 420ms var(--ease-spring); }

/* Overview testimonial card */
.ov-t { display: block; padding: 9px 9px 10px; border-radius: 9px; transition: background-color 180ms var(--ease-out); }
.ov-t:hover { background: var(--surface-hover); }
.ov-t + .ov-t { border-top: 1px solid var(--hairline); }

.ov-t .tstars { margin-bottom: 5px; }
.ov-t .tstars svg { width: 11px; height: 11px; }

.ov-quote {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ov-t-foot { display: flex; align-items: baseline; gap: 7px; margin-top: 7px; }
.ov-t-name { font-size: 11.5px; font-weight: 600; color: var(--ink); }
.ov-t-date { font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* Overview FAQ row */
.ov-faq {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  text-align: left;
  padding: 8px 9px;
  border-radius: 9px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out);
}

.ov-faq:hover { background: var(--surface-hover); color: var(--accent-ink); }
.ov-faq .ov-sub { font-weight: 500; }
.ov-faq svg { width: 11px; height: 11px; flex-shrink: 0; color: var(--ink-3); }

/* Inside the equal-height grid the FAQ panel's preview rows stretch
   to share whatever height the tallest panel dictates, so the panel
   never shows a dead band at the bottom. Content stays centred per
   row; other panels keep their top-aligned rhythm. */
.ov-panel[data-sec="faq"] .ov-body .ov-faq { flex: 1; }

/* Overview empty slice */
.ov-empty {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 10px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-3);
}

.ov-empty-mark {
  width: 26px; height: 26px;
  flex-shrink: 0;
  border-radius: 8px;
  background: var(--accent-tint);
  display: grid;
  place-items: center;
  color: var(--accent-ink);
  transition: background-color var(--accent-ms) var(--ease-out), color var(--accent-ms) var(--ease-out);
}

.ov-empty-mark svg { width: 12px; height: 12px; }

.ver-tag {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 1.5px 7px;
  border-radius: 6px;
  background: var(--inset);
  border: 1px solid var(--hairline);
  color: var(--ink-2);
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

/* ============ Section toolbar ============
   Section controls live on their OWN row beneath the product
   identity: section label + count chip on the left, tools (the
   "Search /" chip and the add button) right-anchored. Because the
   row is otherwise empty, the expanded search field claims real
   flex space here and can never overlap the identity above. */

.section-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  margin-bottom: 24px;
}

.toolbar-label {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  flex-shrink: 0;
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.toolbar-count {
  min-width: 21px;
  padding: 1px 7px;
  border-radius: 999px;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--accent-ink);
  background: var(--accent-tint-2);
  transition: background-color var(--accent-ms) var(--ease-out), color var(--accent-ms) var(--ease-out);
}

.head-tools {
  margin-left: auto;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 11px;
}

.head-tools:empty { display: none; }

/* The search field lives inside a slot that normally shows only a
   quiet keyboard-hint chip ("Search" + a tiny "/" keycap). Pressing
   "/" or clicking the chip swaps in the live filter field; Escape
   clears and collapses it back to the chip. Opening the search grows
   the slot within the toolbar row (flex reflow, never an overlay),
   capped so the add button keeps its place beside it. */
.search-slot {
  position: relative;
  min-height: 39px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.search-slot.is-open {
  flex: 1 1 auto;
  max-width: 400px;
}

.search-hint {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 9px 7px 11px;
  border: 1px solid var(--hairline);
  border-radius: 9px;
  background: var(--surface);
  color: var(--ink-3);
  font-size: 12.5px;
  font-weight: 600;
  transition: color 180ms var(--ease-out), border-color 180ms var(--ease-out), background-color 180ms var(--ease-out);
}

.search-hint:hover {
  color: var(--ink-2);
  border-color: var(--hairline-strong);
  background: var(--surface-hover);
}

.search-hint svg { width: 12px; height: 12px; }

/* When the chip is widened to match the add button (desktop, set in JS),
   the "/" keycap rides to the far right so it reads like a real search
   field. At natural width the auto margin collapses and nothing moves. */
.search-hint .keycap { margin-left: auto; }

/* Tiny keycap: a real key, not a fake input */
.keycap {
  min-width: 17px;
  text-align: center;
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  color: var(--ink-3);
  padding: 0 5px 1px;
  border-radius: 4.5px;
  border: 1px solid var(--hairline-strong);
  border-bottom-width: 2px;
  background: var(--inset);
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

.search {
  position: relative;
  width: 100%;
  display: none;
}

.search-slot.is-open .search-hint { display: none; }

.search-slot.is-open .search {
  display: block;
  transform-origin: right center;
  animation: search-in 260ms var(--ease-out) both;
}

@keyframes search-in {
  from { opacity: 0; transform: translateX(6px) scaleX(0.98); filter: blur(2px); }
  to   { opacity: 1; transform: translateX(0) scaleX(1); filter: blur(0); }
}

.search svg {
  position: absolute;
  left: 12px; top: 50%;
  transform: translateY(-50%);
  width: 14px; height: 14px;
  color: var(--ink-3);
  pointer-events: none;
  transition: color 200ms var(--ease-out);
}

.search:focus-within svg { color: var(--accent-ink); }

.search input {
  width: 100%;
  padding: 8.5px 46px 8.5px 34px;
  border: 1px solid var(--hairline);
  border-radius: 9px;
  background: var(--surface);
  color: var(--ink);
  font-size: 13.5px;
  outline: none;
  transition: border-color 220ms var(--ease-out), box-shadow 220ms var(--ease-out), background-color 280ms var(--ease-out);
}

.search input::placeholder { color: var(--ink-3); }

.search input:focus {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 0 3px var(--accent-tint-2);
}

.search kbd {
  position: absolute;
  right: 10px; top: 50%;
  transform: translateY(-50%);
  font-family: inherit;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--ink-3);
  padding: 1.5px 6.5px;
  border-radius: 5px;
  border: 1px solid var(--hairline);
  background: var(--inset);
  pointer-events: none;
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

/* Section-level add affordance: one accent button, right of the
   search chip in the header row on Bugs, Features, Roadmap, and
   Testimonials views. */
.section-add {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  padding: 8.5px 16px;
  border-radius: 9px;
  background: var(--accent-ink);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.01em;
  transition: background-color var(--accent-ms) var(--ease-out), color 280ms var(--ease-out), transform 220ms var(--ease-spring), box-shadow 220ms var(--ease-out);
}

.section-add:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--accent) 32%, transparent);
}

.section-add:active { transform: scale(0.97); }
.section-add svg { width: 12px; height: 12px; }

@keyframes row-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Upvote chip: gentle spring (used on the item detail view) */
.vote {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  min-width: 46px;
  padding: 7px 8px 5px;
  border: 1px solid var(--hairline-strong);
  border-radius: 11px;
  background: var(--surface);
  color: var(--ink-2);
  flex-shrink: 0;
  transition:
    border-color 220ms var(--ease-out),
    background-color 220ms var(--ease-out),
    color 220ms var(--ease-out),
    transform 260ms var(--ease-spring);
}

.vote:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--accent-ink);
  background: var(--accent-tint);
}

.vote:hover svg { transform: translateY(-1.5px); }
.vote:active { transform: scale(0.93); }

.vote svg {
  width: 12px; height: 12px;
  transition: transform 240ms var(--ease-spring);
}

.vote-n {
  display: inline-block;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}

.ov-vote .vote-n { font-size: 11.5px; }

.vote-n.rolling { animation: num-roll 300ms var(--ease-out); }

@keyframes num-roll {
  from { transform: translateY(0.45em); opacity: 0; filter: blur(3px); }
  to   { transform: translateY(0); opacity: 1; filter: blur(0); }
}

.vote.voted {
  background: var(--accent-tint-2);
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  color: var(--accent-ink);
}

.vote.is-popping { animation: vote-pop 420ms var(--ease-spring); }

@keyframes vote-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.tag, .pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: background-color 280ms var(--ease-out), color 280ms var(--ease-out);
}

.tag-bug { background: var(--tag-bug-bg); color: var(--tag-bug-text); }
.tag-feature { background: var(--tag-feature-bg); color: var(--tag-feature-text); }

.pill-review   { background: var(--pill-review-bg); color: var(--pill-review-text); }
.pill-planned  { background: var(--pill-planned-bg); color: var(--pill-planned-text); }
.pill-progress { background: var(--pill-progress-bg); color: var(--pill-progress-text); }
.pill-done     { background: var(--pill-done-bg); color: var(--pill-done-text); }
.pill-declined { background: var(--pill-declined-bg); color: var(--pill-declined-text); }

.meta-sep {
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--ink-3);
  opacity: 0.45;
  flex-shrink: 0;
}

/* Purely typographic byline: name slightly stronger, date quieter */
.meta-byline { white-space: nowrap; font-variant-numeric: tabular-nums; }
.byline-name { font-weight: 600; color: var(--ink); }

/* Official Theodore HQ entries: a small ink pill with an accent dot */
.official-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2.5px 9px;
  border-radius: 999px;
  /* A deep version of the product accent (navy for Charm, deep amber for
     Solace, etc.), so the official reply pill carries the product colour
     rather than a flat black. White text stays readable on every accent. */
  background: var(--accent-deep);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
  transition: background-color var(--accent-ms) var(--ease-out), color 280ms var(--ease-out);
}

.search-empty {
  display: none;
  padding: 48px 22px;
  text-align: center;
  color: var(--ink-3);
  font-size: 13.5px;
}

/* Empty product board */
.product-empty {
  display: none;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 72px 24px;
  border-radius: 15px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  box-shadow: var(--shadow-card);
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out);
}

.empty-orb {
  width: 54px; height: 54px;
  border-radius: 17px;
  background: var(--accent-tint);
  display: grid;
  place-items: center;
  color: var(--accent-ink);
  margin-bottom: 18px;
  transition: background-color var(--accent-ms) var(--ease-out), color var(--accent-ms) var(--ease-out);
}

.empty-orb svg { width: 22px; height: 22px; }

.product-empty h3 {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 5px;
}

.product-empty p {
  font-size: 13.5px;
  color: var(--ink-2);
  margin-bottom: 22px;
}

.empty-cta {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 20px;
  border-radius: 9px;
  background: var(--accent-ink);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 700;
  transition: background-color var(--accent-ms) var(--ease-out), color 280ms var(--ease-out), transform 220ms var(--ease-spring), box-shadow 220ms var(--ease-out);
}

.empty-cta:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--accent) 32%, transparent);
}

.empty-cta:active { transform: scale(0.97); }
.empty-cta svg { width: 12px; height: 12px; }

/* ============ FAQ ============ */

.faq-no-match { padding: 40px 22px; }

.faq-cat { margin-bottom: 24px; animation: row-in 480ms var(--ease-out) calc(var(--i) * 60ms) both; }

.faq-cat-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: 9px;
  padding: 0 2px;
  transition: color var(--accent-ms) var(--ease-out);
}

.faq-list {
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  border-radius: 13px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out);
}

.faq-item {
  border-radius: 9px;
  transition: background-color 260ms var(--ease-out), box-shadow 260ms var(--ease-out);
}

.faq-item + .faq-item { border-top: 1px solid var(--hairline); }

/* Active search filter: inside the FAQ list the filtering itself is the
   signal (only matches stay visible), and the list already carries an
   accent border - so matches get only a faint background tint. A ring
   here doubled up against the container border and read as a glitch. */
.faq-item.search-hit {
  background: color-mix(in srgb, var(--accent) 4%, transparent);
}

.faq-q {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 18px;
  text-align: left;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink);
  transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out);
}

.faq-q:hover { background: var(--surface-hover); }
.faq-item.open .faq-q { color: var(--accent-ink); }

/* Question + one-line answer preview, visible while collapsed */
.faq-q-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.faq-sub {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.faq-chip {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 1.5px 8px;
  border-radius: 999px;
  background: var(--inset);
  border: 1px solid var(--hairline);
  color: var(--ink-2);
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

.faq-q .chev {
  margin-left: auto;
  width: 14px; height: 14px;
  flex-shrink: 0;
  color: var(--ink-3);
  transition: transform 340ms var(--ease-spring), color 200ms var(--ease-out);
}

.faq-item.open .chev { transform: rotate(180deg); color: var(--accent-ink); }

.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 340ms var(--ease-out);
}

.faq-item.open .faq-a { grid-template-rows: 1fr; }

.faq-a-inner { overflow: hidden; min-height: 0; }

.faq-a-inner p {
  padding: 1px 18px 15px;
  font-size: 13px;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 68ch;
  text-wrap: pretty;
}

/* ============ Consolidated views ============ */

.prod-badge {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap;
  gap: 5px;
  padding: 2px 9px 2px 4px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.01em;
  background: color-mix(in srgb, var(--pc) 9%, transparent);
  color: color-mix(in srgb, var(--pc) var(--accent-mix-pct), var(--accent-mix-base));
  transition: background-color 280ms var(--ease-out), color 280ms var(--ease-out);
}

.prod-badge .picon { width: 14px; height: 14px; }

/* Testimonials: uniform compact grid, no masonry */
.tgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 13px;
  align-items: stretch;
}

.tcard {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 13px;
  padding: 14px 15px 12px;
  box-shadow: var(--shadow-card);
  animation: row-in 480ms var(--ease-out) calc(var(--i) * 50ms) both;
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out), box-shadow 240ms var(--ease-out), transform 240ms var(--ease-out);
}

.tcard:hover { transform: translateY(-2px); box-shadow: var(--shadow-card-hover); }

.tstars {
  display: flex;
  gap: 2px;
  margin-bottom: 7px;
  color: var(--pill-review-text);
}

.tstars svg { width: 12px; height: 12px; }
.tstars .star-off { color: var(--hairline-strong); }

.tquote {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink);
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(3 * 1.55em);
}

.tfoot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding-top: 10px;
}

.tname { font-size: 12.5px; font-weight: 600; color: var(--ink); }
.tdate { font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tfoot .prod-badge { margin-left: auto; }

/* Country flag, bottom right of testimonial cards. Emoji flags,
   sized for crispness; the title carries the country name. */
.tflag {
  margin-left: auto;
  font-size: 14px;
  line-height: 1;
  cursor: default;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", var(--font);
}

.tfoot .prod-badge ~ .tflag { margin-left: 0; }
.ov-t-foot .tflag { font-size: 13px; }

/* Grouped-by-product lists (roadmap, changelog, consolidated FAQ) */
.group { margin-bottom: 28px; animation: row-in 480ms var(--ease-out) calc(var(--i) * 60ms) both; }

.group-head {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 10px;
  padding: 0 2px;
}

.group-head .picon { width: 20px; height: 20px; }
.group-head h2 { font-size: 14px; font-weight: 700; letter-spacing: -0.01em; }
.group-head .gcount { margin-left: 2px; font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.group-list {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 13px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out);
}

body[data-view="board"] .group-list { border-color: color-mix(in srgb, var(--accent) 18%, var(--hairline)); }

.gitem {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--hairline);
  font-size: 13.5px;
  transition: background-color 180ms var(--ease-out), border-color 280ms var(--ease-out);
  animation: row-in 420ms var(--ease-out) calc(var(--j, 0) * 35ms) both;
}

.gitem:last-child { border-bottom: none; }
.gitem:hover { background: var(--surface-hover); }
.gitem .gtitle { font-weight: 600; }
.gitem .gdate {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* ============ Kanban (Bugs, Features, Roadmap) ============
   Columns speak the overview panels' language: same surface,
   header wash, border, radius and shadow recipe. The accent
   column well lives on in the header band and the faint
   surface tint, so the boards read as the overview exploded
   into full sections. */

.kanban {
  display: grid;
  grid-template-columns: repeat(var(--cols, 4), 1fr);
  gap: 14px;
  align-items: start;
}

.kcol {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  border-radius: 15px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  animation: row-in 480ms var(--ease-out) calc(var(--i) * 55ms) both;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out), box-shadow 240ms var(--ease-out);
}

.kcol-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px 10px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 20%, var(--hairline));
  transition: background-color 400ms var(--ease-out), border-color 400ms var(--ease-out);
}

.kcol-head h3 {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--ink);
}

.kcount {
  margin-left: auto;
  font-size: 11.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}

.kcards {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 8px 10px;
}

/* Cards take the overview's compact row treatment */
.kcard {
  border-radius: 9px;
  padding: 9px 10px 8px;
  cursor: pointer;
  animation: row-in 420ms var(--ease-out) calc(var(--i, 0) * 55ms + var(--j, 0) * 50ms) both;
  transition: background-color 180ms var(--ease-out), transform 220ms var(--ease-out), box-shadow 260ms var(--ease-out);
}

.kcard:hover { background: var(--surface-hover); }
.kcard:hover .kcard-title { color: var(--accent-ink); }
.kcard:active { transform: scale(0.99); }

/* Active search filter: every visible match carries the home card's
   hover treatment - an accent ring plus a soft accent glow - for as
   long as the query is non-empty, in product and consolidated boards
   and both themes. */
.kcard.search-hit {
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent),
    0 10px 26px -12px color-mix(in srgb, var(--accent) 38%, transparent);
}

.kcard-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1.35;
  transition: color 200ms var(--ease-out);
}

.kcard-sub {
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-2);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.kcard-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 9px;
  flex-wrap: wrap;
}

.kcard-foot .tag { font-size: 10.5px; padding: 1.5px 8px; }
.kcard-foot .prod-badge { font-size: 10.5px; padding: 1.5px 8px 1.5px 3px; }
.kcard-foot .prod-badge .picon { width: 13px; height: 13px; }
.kcard-foot .ov-vote { margin-left: auto; }

.kcard-byline {
  font-size: 11px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}

.kcard-byline .byline-name { font-weight: 600; color: var(--ink-2); }

.kempty {
  padding: 22px 10px 24px;
  text-align: center;
  font-size: 12px;
  color: var(--ink-3);
}

/* ============ Changelog timeline ============ */

.timeline {
  position: relative;
  max-width: 720px;
  padding-left: 32px;
}

.timeline::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: var(--hairline-strong);
  transition: background-color 280ms var(--ease-out);
}

.tl-entry {
  position: relative;
  padding-bottom: 30px;
  animation: row-in 480ms var(--ease-out) calc(var(--i) * 70ms) both;
}

.tl-entry:last-child { padding-bottom: 6px; }

/* Accent node, centred on the spine */
.tl-entry::before {
  content: "";
  position: absolute;
  left: -28px;
  top: 6px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint-2);
  transition: background-color var(--accent-ms) var(--ease-out);
}

.tl-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}

.tl-date {
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.tl-title {
  font-size: 15.5px;
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.3;
}

.tl-sub {
  font-size: 13px;
  color: var(--ink-2);
  margin-top: 3px;
  max-width: 62ch;
  text-wrap: pretty;
}

/* Full release notes: the whole note set lives on the timeline,
   ready for entries to grow into long multi-release scrolls. */
.tl-notes {
  margin-top: 12px;
  padding: 13px 16px 14px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 11px;
  box-shadow: var(--shadow-card);
  max-width: 62ch;
  text-wrap: pretty;
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

.tl-notes ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.tl-notes li { position: relative; padding-left: 17px; }

.tl-notes li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.55em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.65;
  transition: background-color var(--accent-ms) var(--ease-out);
}

body[data-view="board"] .tl-notes { border-color: color-mix(in srgb, var(--accent) 18%, var(--hairline)); }

/* ============ Item detail + comments ============ */

/* Detail top bar: a proper bordered back button (chevron + the
   section you came from) at the top of the content column, plus
   quiet breadcrumb context, clearly separated from the title block. */
.detail-nav {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-bottom: 26px;
  animation: row-in 420ms var(--ease-out) both;
}

.detail-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px 7px 11px;
  border: 1px solid var(--hairline-strong);
  border-radius: 9px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-2);
  transition:
    color 200ms var(--ease-out),
    border-color 200ms var(--ease-out),
    background-color 200ms var(--ease-out),
    box-shadow 220ms var(--ease-out),
    transform 220ms var(--ease-spring);
}

.detail-back:hover {
  color: var(--accent-ink);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: var(--accent-tint);
  box-shadow: var(--shadow-card-hover);
}

.detail-back:active { transform: scale(0.97); }
.detail-back svg { width: 12px; height: 12px; transition: transform 220ms var(--ease-out); }
.detail-back:hover svg { transform: translateX(-2px); }

.detail-head {
  max-width: 720px;
  animation: row-in 480ms var(--ease-out) 60ms both;
}

.detail-title-row {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.detail-title {
  flex: 1;
  min-width: 0;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.018em;
  line-height: 1.25;
}

.detail-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 9px;
  font-size: 12px;
  color: var(--ink-3);
}

/* The original request, boxed like a reply so the page reads as one conversation */
.detail-post {
  max-width: 720px;
  margin-top: 16px;
  padding: 13px 18px 14px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  border-radius: 15px;
  box-shadow: var(--shadow-card);
  animation: row-in 480ms var(--ease-out) 100ms both;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out);
}

/* Reply thread */
.thread {
  max-width: 720px;
  margin-top: 20px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  border-radius: 15px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  animation: row-in 480ms var(--ease-out) 130ms both;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out);
}

.thread-head {
  padding: 11px 18px 10px;
  border-bottom: 1px solid var(--hairline);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  transition: border-color 280ms var(--ease-out);
}

.reply {
  padding: 13px 18px 14px;
  border-bottom: 1px solid var(--hairline);
  animation: row-in 420ms var(--ease-out) calc(180ms + var(--i, 0) * 55ms) both;
  transition: border-color 280ms var(--ease-out), background-color 280ms var(--ease-out);
}

.reply:last-child { border-bottom: none; }

/* Official replies sit on the faintest accent wash */
.reply.is-official { background: color-mix(in srgb, var(--accent) 4.5%, transparent); }

.reply-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.reply-date {
  font-size: 11.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.reply-text {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 62ch;
  text-wrap: pretty;
}

.thread-empty {
  padding: 22px 18px;
  font-size: 12.5px;
  color: var(--ink-3);
}

/* A satisfying spring entrance for a freshly posted comment */
.reply.is-new {
  animation: reply-in 520ms var(--ease-spring) both;
}

@keyframes reply-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); filter: blur(3px); }
  to   { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}

/* Add a Comment form */
.comment-form {
  max-width: 720px;
  margin-top: 16px;
  padding: 17px 18px 18px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--hairline));
  border-radius: 15px;
  box-shadow: var(--shadow-card);
  animation: row-in 480ms var(--ease-out) 200ms both;
  transition: background-color 280ms var(--ease-out), border-color 400ms var(--ease-out);
}

.form-title {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -0.005em;
  margin-bottom: 12px;
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 10px;
}

.field label {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 5px;
}

.field input,
.field textarea {
  width: 100%;
  padding: 8.5px 12px;
  border: 1px solid var(--hairline-strong);
  border-radius: 9px;
  background: color-mix(in srgb, var(--inset) 55%, var(--surface));
  color: var(--ink);
  font-size: 13px;
  line-height: 1.5;
  outline: none;
  resize: vertical;
  transition: border-color 220ms var(--ease-out), box-shadow 220ms var(--ease-out), background-color 280ms var(--ease-out);
}

.field input::placeholder,
.field textarea::placeholder { color: var(--ink-3); }

.field input:focus,
.field textarea:focus {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 0 3px var(--accent-tint-2);
  background: var(--surface);
}

.field.is-error input,
.field.is-error textarea { border-color: color-mix(in srgb, var(--tag-bug-text) 65%, transparent); }

.field-err {
  display: none;
  font-size: 11.5px;
  color: var(--tag-bug-text);
  margin-top: 4px;
}

.field.is-error .field-err { display: block; }

.form-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 12px;
}

.form-submit {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8.5px 18px;
  border-radius: 9px;
  background: var(--accent-ink);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 700;
  transition: background-color var(--accent-ms) var(--ease-out), color 280ms var(--ease-out), transform 220ms var(--ease-spring), box-shadow 220ms var(--ease-out);
}

.form-submit:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--accent) 32%, transparent);
}

.form-submit:active { transform: scale(0.97); }

/* ============================================================
   Responsive layer: tablet + phone (below 1100px).
   Desktop (1100px and up) never enters these queries, so it
   renders exactly as before. Every override lives after its
   base rule, so equal specificity resolves on source order.
   ============================================================ */

/* Mobile chrome (top app bar + drawer scrim) stays out of the
   desktop render entirely. */
.mobile-bar, .drawer-scrim { display: none; }

@media (max-width: 1099px) {
  html { -webkit-tap-highlight-color: transparent; }

  /* ---- Frame: top app bar on the frame surface, panel inset 8px.
     The bar and drawer sit on the same continuous accent-breathing
     frame; the content panel keeps its rounded, inset identity. ---- */
  .app { flex-direction: column; height: 100vh; height: 100dvh; }

  .mobile-bar {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
    min-width: 0;
    padding: calc(6px + env(safe-area-inset-top, 0px)) calc(12px + env(safe-area-inset-right, 0px)) 6px calc(6px + env(safe-area-inset-left, 0px));
  }

  .mb-menu {
    width: 44px; height: 44px;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    border-radius: 11px;
    color: var(--ink-2);
    transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out);
  }

  .mb-menu:hover, .mb-menu:active { background: var(--sidebar-hover); color: var(--ink); }
  .mb-menu svg { width: 19px; height: 19px; }

  .mb-brand {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    min-width: 0;
    min-height: 44px;
    padding: 0 8px;
    border-radius: 11px;
    text-align: left;
  }

  .mb-brand .brand-mark { width: 25px; height: 25px; }
  .mb-brand .brand-word { font-size: 15px; }

  /* Active product chip, right-aligned while inside a product */
  .mb-product {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
    min-height: 44px;
    padding: 5px 11px 5px 8px;
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--hairline));
    background: var(--accent-tint);
    color: var(--accent-ink);
    font-size: 12.5px;
    font-weight: 700;
    white-space: nowrap;
    transition: background-color var(--accent-ms) var(--ease-out), color var(--accent-ms) var(--ease-out), border-color var(--accent-ms) var(--ease-out);
  }

  .mb-product[hidden] { display: none; }
  .mb-product .picon { width: 18px; height: 18px; }
  .mb-product > span { overflow: hidden; text-overflow: ellipsis; }
  .mb-product:active { background: color-mix(in srgb, var(--accent) 14%, var(--accent-tint)); }

  .main {
    margin: 0 8px calc(8px + env(safe-area-inset-bottom, 0px));
    min-height: 0;
    border-radius: 14px;
  }

  .main-scroll { padding: 34px 28px 64px; overflow-x: hidden; }

  /* ---- Sidebar becomes a slide-over drawer ---- */
  .sidebar {
    z-index: 70;
    width: min(304px, 86vw);
    padding: calc(26px + env(safe-area-inset-top, 0px)) 16px calc(16px + env(safe-area-inset-bottom, 0px)) calc(16px + env(safe-area-inset-left, 0px));
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--accent) 9%, transparent), transparent 62%),
      color-mix(in srgb, var(--accent) 3%, var(--canvas));
    border-right: 1px solid var(--hairline);
    box-shadow: var(--shadow-panel);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(-103%);
    visibility: hidden;
    transition: transform 340ms var(--ease-out), visibility 0s linear 340ms;
  }

  body.drawer-open .sidebar {
    transform: none;
    visibility: visible;
    transition: transform 340ms var(--ease-out);
  }

  .drawer-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(9, 11, 16, 0.44);
    opacity: 0;
    pointer-events: none;
    touch-action: none;
    transition: opacity 300ms var(--ease-out);
  }

  body.drawer-open .drawer-scrim { opacity: 1; pointer-events: auto; }

  /* Comfortable touch rows inside the drawer */
  .sidebar .side-item { padding: 11px 12px; font-size: 14px; border-radius: 10px; }
  .sidebar .brand { margin-bottom: 24px; }

  /* ---- Touch targets (44px interactive heights) ---- */
  .search-hint { min-height: 44px; padding: 10px 12px 10px 13px; }
  .search input { min-height: 44px; }
  .section-add { min-height: 44px; padding: 10px 18px; }
  .board-visit { min-height: 44px; padding: 10px 16px; }
  .detail-back { min-height: 44px; padding: 8px 15px 8px 12px; }
  .empty-cta { min-height: 44px; }
  .form-submit { min-height: 44px; padding: 10px 20px; }

  /* Compact chips keep their scale but gain a 40px+ hit area */
  .ov-vote { position: relative; }
  .ov-vote::after { content: ""; position: absolute; inset: -9px; border-radius: inherit; }
  .ov-add::after { content: ""; position: absolute; inset: -9px; }

  /* ---- Section headers wrap instead of overflowing ---- */
  .board-head { flex-wrap: wrap; row-gap: 12px; }
  .section-toolbar { flex-wrap: wrap; row-gap: 10px; }

  /* ---- Home: three-up cards; strips still grow together per row ---- */
  .product-grid { grid-template-columns: repeat(3, 1fr); }

  /* ---- Overview panels: two-up ---- */
  .ov-grid { grid-template-columns: repeat(2, 1fr); }

  /* ---- Kanban: horizontal snap-scroll columns with a peek of the
     next column and a thin accent scroll indicator ---- */
  .kanban {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin: 0 -28px;
    padding: 2px 28px 14px;
    scroll-padding-left: 28px;
    -webkit-overflow-scrolling: touch;
  }

  .kcol {
    flex: 0 0 clamp(258px, 85vw, 320px);
    scroll-snap-align: start;
  }

  .kanban::-webkit-scrollbar { height: 6px; }
  .kanban::-webkit-scrollbar-thumb { border-width: 1px; }

  /* ---- Testimonials: two-up ---- */
  .tgrid { grid-template-columns: repeat(2, 1fr); }
}

/* ============ Phone (below 768px) ============ */
@media (max-width: 767px) {
  .main-scroll { padding: 22px 16px 56px; }

  .home-head { margin-bottom: 28px; }

  .board-head { gap: 12px 13px; margin-bottom: 24px; }
  .board-head:has(+ .section-toolbar) { margin-bottom: 14px; }
  .board-head .picon { width: 36px; height: 36px; }
  .board-head h1, .board-head .board-title { font-size: 21px; }

  /* The mobile bar already carries a product chip linking to the
     marketing site, so the header's Visit button would be a
     duplicate here - drop it and keep the header to one calm row. */
  .board-visit { display: none; }

  /* Toolbar row on phones: the label keeps the first line; the
     tools wrap to a full-width line beneath it when tight, with
     the add button pinned right. */
  .section-toolbar { margin-bottom: 20px; }
  .head-tools { flex-basis: 100%; margin-left: 0; justify-content: flex-start; flex-wrap: wrap; }
  .head-tools .search-slot { flex: 1 1 auto; min-width: 0; justify-content: flex-start; }
  .head-tools .section-add { margin-left: auto; }

  /* An open search takes its own full row so the field stays
     usable beside a wide add button (which wraps beneath). */
  .head-tools .search-slot.is-open { flex-basis: 100%; max-width: none; }

  /* iOS: inputs at 16px so focusing never zooms the page.
     The textarea also re-joins the app font here (the base sheet
     only inherits font-family on inputs). */
  .search input, .field input, .field textarea { font-size: 16px; }
  .field textarea { font-family: var(--font); }

  /* Home cards: two-up */
  .product-grid { grid-template-columns: repeat(2, 1fr); margin-bottom: 36px; }

  /* Overview: single column, natural heights
     (order already reads Bugs, Features, Testimonials, Roadmap,
     Changelog, FAQ) */
  .ov-grid { grid-template-columns: 1fr; grid-auto-rows: auto; }

  /* Kanban bleed matches the tighter content padding */
  .kanban { gap: 10px; margin: 0 -16px; padding: 2px 16px 14px; scroll-padding-left: 16px; }

  /* Recent Activity: dot + product name + date on the top line,
     title and summary on their own full-width line beneath */
  .activity-head { padding: 15px 16px 13px; }
  .activity-row { flex-wrap: wrap; row-gap: 3px; padding: 12px 16px; }
  .activity-row .activity-main { order: 4; flex-basis: 100%; }
  .activity-date { margin-left: auto; }

  /* Testimonials: single column */
  .tgrid { grid-template-columns: 1fr; }

  /* Changelog: tighter spine, meta wraps cleanly */
  .timeline { padding-left: 26px; }
  .tl-entry::before { left: -22px; }
  .tl-meta { flex-wrap: wrap; row-gap: 4px; }

  /* Item detail + comment form */
  .form-grid { grid-template-columns: 1fr; }
  .detail-nav { flex-wrap: wrap; row-gap: 8px; }

  /* FAQ rows breathe at full width */
  .faq-q { padding: 12px 15px; min-height: 44px; }
  .faq-a-inner p { padding: 1px 15px 14px; }
}

/* ============ Small phone (480px and below) ============ */
@media (max-width: 480px) {
  .product-grid { grid-template-columns: 1fr; }
  .faq-chip { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ============================================================
   Static-site additions
   New in production: real links inside cards, the submission
   modal, and form confirmation states. Everything reuses the
   design system's variables, radii, and easing.
   ============================================================ */

/* Textareas join the app font everywhere (the base sheet only
   inherits font-family on inputs; the mockup patched this on
   mobile only) */
textarea { font-family: var(--font); }

/* ---- Cards as real links (crawlable + keyboard friendly) ----
   The whole card stays clickable via a stretched link; the vote
   chip and product badge float above it. */
.kcard, .ov-card { position: relative; }

.kcard-link, .ov-card-link { color: inherit; }

.kcard-link::after,
.ov-card-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 9px;
}

.kcard .ov-vote,
.ov-card .ov-vote {
  position: relative;
  z-index: 1;
}

.kcard-link:focus-visible,
.ov-card-link:focus-visible { outline: none; }

.kcard:has(.kcard-link:focus-visible),
.ov-card:has(.ov-card-link:focus-visible) {
  outline: 2px solid color-mix(in srgb, var(--accent) 60%, transparent);
  outline-offset: 2px;
}

/* Voted chips rest quietly: one vote per browser, no un-vote */
.ov-vote.voted, .vote.voted { cursor: default; }

/* ---- Submission modal ---- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 20px;
}

.modal[hidden] { display: none; }

.modal-scrim {
  position: absolute;
  inset: 0;
  background: rgba(9, 11, 16, 0.44);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: scrim-in 260ms var(--ease-out) both;
}

@keyframes scrim-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.modal-panel {
  position: relative;
  width: min(560px, 100%);
  max-height: calc(100vh - 40px);
  max-height: calc(100dvh - 40px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--panel);
  border: 1px solid var(--hairline-strong);
  border-radius: 18px;
  box-shadow: var(--shadow-card-hover);
  padding: 22px 22px 20px;
  animation: reply-in 420ms var(--ease-spring) both;
}

.modal-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 14px;
}

.modal-title {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.012em;
  line-height: 1.25;
}

.modal-sub {
  font-size: 12.5px;
  color: var(--ink-2);
  margin-top: 2px;
  max-width: 46ch;
}

.modal-close {
  margin-left: auto;
  flex-shrink: 0;
  width: 30px; height: 30px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  color: var(--ink-3);
  border: 1px solid var(--hairline);
  background: var(--surface);
  transition: color 180ms var(--ease-out), border-color 180ms var(--ease-out), background-color 180ms var(--ease-out), transform 220ms var(--ease-spring);
}

.modal-close:hover {
  color: var(--ink);
  border-color: var(--hairline-strong);
  background: var(--surface-hover);
}

.modal-close:active { transform: scale(0.92); }
.modal-close svg { width: 12px; height: 12px; }

.modal .field { margin-bottom: 10px; }
.modal .form-grid .field { margin-bottom: 0; }
.modal .form-grid { margin-bottom: 10px; }

/* Selects share the soft field recipe, with a quiet chevron */
.field select {
  width: 100%;
  padding: 8.5px 34px 8.5px 12px;
  border: 1px solid var(--hairline-strong);
  border-radius: 9px;
  background-color: color-mix(in srgb, var(--inset) 55%, var(--surface));
  color: var(--ink);
  font-family: inherit;
  font-size: 13px;
  line-height: 1.5;
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='%23969ca7' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 5.5 3.5 3.5 3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 13px 13px;
  transition: border-color 220ms var(--ease-out), box-shadow 220ms var(--ease-out), background-color 280ms var(--ease-out);
}

.field select:focus {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 0 3px var(--accent-tint-2);
  background-color: var(--surface);
}

.field.is-error select { border-color: color-mix(in srgb, var(--tag-bug-text) 65%, transparent); }

/* Star picker: same star glyphs as testimonial cards, tap-sized */
.star-picker {
  display: flex;
  gap: 3px;
}

.star-btn {
  width: 32px; height: 32px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  color: var(--hairline-strong);
  transition: color 160ms var(--ease-out), background-color 160ms var(--ease-out), transform 220ms var(--ease-spring);
}

.star-btn svg { width: 17px; height: 17px; }
.star-btn:hover { background: var(--surface-hover); transform: scale(1.1); }
.star-btn:active { transform: scale(0.92); }
.star-btn.on { color: var(--pill-review-text); }

/* Honeypot: visually hidden, still in the form for bots to find */
.hp-field {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Success state: the Drawn Check ----
   Swaps in for the form once a submission lands. The disc springs
   in, the check draws itself (stroke-dashoffset) with a tiny
   settle, then one line of copy and the View/Done pair fade up.
   ~700ms all in; transform/opacity/dashoffset only. The modal
   header is hidden meanwhile (.is-success) so no copy doubles up,
   leaving just the close button at the top right. */

.modal.is-success .modal-head > div { display: none; }
.modal.is-success .modal-head { margin-bottom: 0; }

.modal-success {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 14px 12px 18px;
}

.modal-success[hidden] { display: none; }

.ms-anim {
  height: 84px;
  display: grid;
  place-items: center;
  margin-bottom: 16px;
}

/* Disc + check ride the product accent, so the confirmation is
   branded per app in both themes */
.ms-disc {
  width: 58px; height: 58px;
  border-radius: 50%;
  background: var(--accent-tint-2);
  display: grid;
  place-items: center;
  color: var(--accent-ink);
  transform: scale(0);
  opacity: 0;
}

.modal-success.play .ms-disc { animation: ms-disc-pop 420ms var(--ease-out) both; }

@keyframes ms-disc-pop {
  0%   { transform: scale(0.4); opacity: 0; }
  55%  { transform: scale(1.04); opacity: 1; }
  78%  { transform: scale(0.985); }
  100% { transform: scale(1); opacity: 1; }
}

.ms-disc svg { width: 26px; height: 26px; }

.ms-disc path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.modal-success.play .ms-disc path { animation: ms-check-draw 300ms var(--ease-out) 200ms both; }

@keyframes ms-check-draw {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}

/* One line of copy + the actions, revealed once the check has
   said its piece */
.ms-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  opacity: 0;
}

.modal-success.play .ms-foot { animation: ms-foot-in 360ms var(--ease-out) 430ms both; }

@keyframes ms-foot-in {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: translateY(0); }
}

.ms-line {
  font-size: 15.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.ms-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* View + Done: same size and shape, one colour family. Done is
   the solid accent-ink primary; View the lighter accent tint. */
.ms-view, .ms-done {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 9px 20px;
  border-radius: 9px;
  border: 1px solid transparent;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.5;
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out), border-color 200ms var(--ease-out), transform 220ms var(--ease-spring), box-shadow 220ms var(--ease-out);
}

.ms-done {
  background: var(--accent-ink);
  color: var(--on-accent);
}

.ms-done:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--accent) 32%, transparent);
}

.ms-view {
  background: var(--accent-tint);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
  color: var(--accent-ink);
}

.ms-view:hover {
  background: var(--accent-tint-2);
  transform: translateY(-1px);
}

.ms-view:active, .ms-done:active { transform: scale(0.97); }

/* Reduced motion: the final state, instantly. (The global 0.01ms
   rule leaves animation-delay alone, so these explicit end states
   are needed to skip the stagger.) */
@media (prefers-reduced-motion: reduce) {
  .modal-success.play .ms-disc,
  .modal-success.play .ms-disc path,
  .modal-success.play .ms-foot { animation: none; }
  .modal-success.play .ms-disc { transform: scale(1); opacity: 1; }
  .modal-success.play .ms-disc path { stroke-dashoffset: 0; }
  .modal-success.play .ms-foot { opacity: 1; }
}

@media (max-width: 1099px) {
  .ms-view, .ms-done { min-height: 44px; }
}

/* Inline confirmation (comment form + form errors) */
.form-confirm {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 14px;
  border-radius: 11px;
  background: var(--pill-done-bg);
  color: var(--pill-done-text);
  font-weight: 600;
  font-size: 13px;
  animation: reply-in 420ms var(--ease-spring) both;
}

.form-confirm svg { width: 14px; height: 14px; flex-shrink: 0; }

.form-error-note {
  display: none;
  margin-right: auto;
  align-self: center;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--tag-bug-text);
}

.form-actions.has-error .form-error-note { display: block; }

.form-submit[disabled] { opacity: 0.6; cursor: progress; transform: none; }

/* The app scrolls inside .main-scroll, so lock that while a modal is up */
body.modal-open .main-scroll { overflow: hidden; }
body.modal-open { overflow: hidden; }

/* ---- 404 page ---- */
.notfound {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  max-width: 52ch;
  padding-top: 24px;
}

.notfound .empty-orb { margin-bottom: 12px; }

.notfound h1 {
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--home-ink);
}

.notfound p { font-size: 14px; color: var(--ink-2); margin-bottom: 16px; }

/* ---- Rich text inside descriptions, replies, and FAQ answers ----
   Bodies come from Markdown, so multi-paragraph and list content
   needs quiet rhythm. */
.detail-desc p + p, .reply-text p + p, .faq-a-inner p + p { margin-top: 8px; }

.detail-desc ul, .reply-text ul, .faq-a-inner ul { margin: 8px 0 0 18px; }
.detail-desc li + li, .reply-text li + li, .faq-a-inner li + li { margin-top: 4px; }

.detail-desc a, .reply-text a, .faq-a-inner a {
  color: var(--accent-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.detail-desc code, .reply-text code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.92em;
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--inset);
  border: 1px solid var(--hairline);
}

/* FAQ answers keep the mockup's measure when rendered from Markdown */
.faq-a-inner ul { padding: 0 18px 15px 34px; margin: 0; }
.faq-a-inner p + ul { padding-top: 0; margin-top: -8px; }

/* ============ Site footer ============
   Quiet, hairline-topped strip at the bottom of the content panel on
   every page. margin-top: auto (the panel scroll area is a column
   flexbox) pins it to the panel bottom on short pages; .view's
   margin-bottom keeps a constant breathing gap on long ones. */

.view.is-active { margin-bottom: 52px; }

.site-footer {
  margin-top: auto;
  max-width: 992px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 18px;
  padding-top: 16px;
  border-top: 1px solid var(--hairline);
  font-size: 11.5px;
  color: var(--ink-3);
  transition: border-color 280ms var(--ease-out), color 280ms var(--ease-out);
}

.sf-brand {
  font-weight: 600;
  letter-spacing: 0.02em;
}

.sf-links { display: flex; gap: 18px; }

.sf-links a {
  color: var(--ink-3);
  font-weight: 600;
  text-decoration: none;
  transition: color 160ms var(--ease-out);
}

.sf-links a:hover,
.sf-links a:focus-visible { color: var(--ink); }

/* ============ Document pages (privacy, terms) ============
   Calm long-form prose inside the content panel: a ~720px measure,
   the site's type scale, quiet section rhythm. */

.doc { max-width: 720px; }

.doc-head { margin-bottom: 26px; }

.doc-head h1 {
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.2;
  color: var(--home-ink);
  transition: color 280ms var(--ease-out);
}

.doc-updated {
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--ink-3);
}

.doc h2 {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.014em;
  line-height: 1.3;
  color: var(--ink);
  margin: 34px 0 10px;
}

.doc p {
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink-2);
  margin: 0 0 10px;
  text-wrap: pretty;
}

.doc ul { margin: 0 0 12px 18px; }

.doc li {
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink-2);
  margin-top: 5px;
}

.doc strong { color: var(--ink); font-weight: 700; }

.doc a {
  color: var(--accent-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Data-controller card: the address block as a quiet framed card */
.doc-card {
  margin: 12px 0 16px;
  padding: 15px 18px;
  max-width: 460px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 13px;
  box-shadow: var(--shadow-card);
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink-2);
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}

.doc-card strong { color: var(--ink); }

@media (max-width: 767px) {
  .doc-head h1 { font-size: 22px; }
  .doc h2 { margin-top: 28px; }
  .view.is-active { margin-bottom: 40px; }
  .site-footer { padding-top: 14px; }
}
