/* ==========================================================================
   CCS ASPIRE — component styles
   Load AFTER aspire-tokens.css. No literal colours: every value is a token.
   Logical properties throughout so right-to-left documents mirror correctly.
   ========================================================================== */

.asp-btn,
.asp-chip,
.asp-field,
.asp-banner,
.asp-card,
.asp-table {
  font-family: var(--font-body);
  box-sizing: border-box;
}

.asp-btn *, .asp-field *, .asp-banner *, .asp-card *, .asp-table * { box-sizing: border-box; }

/* ------------------------------------------------------------ chrome --- */

.asp-appbar {
  display: flex;
  align-items: center;
  gap: var(--space-2xl);
  block-size: 76px;
  padding-inline: var(--space-2xl);
  background: var(--brand);
  color: var(--on-brand);
}

[data-theme="dark"] .asp-appbar,
[data-theme="hc"] .asp-appbar { background: var(--surface-sunken); color: var(--ink-strong); }

/* The one place CCS Red appears in the interface. It is an identity rule,
   never a status signal. Do not reuse this token anywhere else. */
.asp-identity-rule {
  block-size: 4px;
  background: var(--identity);
}

/* The ASPIRE mark. brandMark() in app.js chooses the file — the full form, and the
   reversed artwork wherever the surface is dark — and sets width and height on the
   <img>, so the mark is the right size before any stylesheet arrives and the chrome
   does not reflow as it loads. Which surface counts as dark is not the same question
   as which theme is active on this build; app.js carries the note.

   This rule only holds the shape. The brand notes forbid stretching the mark,
   rotating it, sitting it inside another circle or badge, and adding a shadow,
   glow, gradient or outline, so nothing here does any of that, and no rule
   elsewhere should either. Clear space on all four sides is one satellite
   diameter — 20% of the mark's width, about 7px at the 34px chrome size — which
   the gap on .brand, .signin-brand and .mobile-bar already exceeds. */
.brand-mark {
  display: block;
  flex: 0 0 auto;
  border-radius: 0;
  box-shadow: none;
}

.asp-wordmark {
  font-family: var(--font-display);
  font-size: 23px;
  line-height: 26px;
  font-weight: 600;
  letter-spacing: 0.06em;
}

.asp-appbar__nav { display: flex; align-items: center; gap: var(--space-lg); flex-grow: 1; }

.asp-appbar__link {
  font-size: var(--text-body-size);
  color: var(--on-brand);
  text-decoration: none;
  padding: var(--space-sm) var(--space-2xs);
  opacity: 0.86;
}

.asp-appbar__link[aria-current="page"] {
  opacity: 1;
  font-weight: 700;
  border-block-end: 3px solid var(--identity);
}

/* ------------------------------------------------------------ button --- */

.asp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  min-block-size: 46px;          /* 44px minimum tappable, plus border */
  padding-inline: var(--space-lg);
  border: 2px solid transparent;
  border-radius: var(--radius-md);
  font-family: var(--font-display);
  font-size: var(--text-body-size);
  font-weight: 600;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.asp-btn--primary   { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
.asp-btn--primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); }

.asp-btn--secondary { background: var(--surface-raised); color: var(--brand); border-color: var(--brand); }
.asp-btn--secondary:hover { background: var(--brand-wash); }

.asp-btn--neutral   { background: var(--surface-raised); color: var(--ink-strong); border-color: var(--line-strong); }
.asp-btn--neutral:hover { background: var(--surface-subtle); }

.asp-btn--quiet     { background: none; color: var(--link); border-color: transparent; padding-inline: var(--space-md); }
.asp-btn--quiet:hover { background: var(--surface-subtle); }

/* Destructive is outlined, never filled: a red fill invites the accidental
   click it is warning about. Uses past-due, not the identity red. */
.asp-btn--danger    { background: var(--surface-raised); color: var(--status-past-due); border-color: var(--status-past-due); }
.asp-btn--danger:hover { background: var(--wash-past-due); }

.asp-btn--sm { min-block-size: 38px; padding-inline: var(--space-base); font-size: var(--text-small-size); }

.asp-btn[disabled], .asp-btn[aria-disabled="true"] {
  background: var(--surface-subtle);
  color: var(--ink-muted);
  border-color: var(--line);
  cursor: not-allowed;
}

/* ------------------------------------------------------- status chip --- */
/* FOUR channels, always: shape (the inline SVG), word, date, colour.
   Colour is the last of the four and never travels alone. */

.asp-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 6px var(--space-md);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: var(--text-small-size);
  line-height: 20px;
  font-weight: 700;
  white-space: nowrap;
}

.asp-chip__shape { inline-size: 14px; block-size: 14px; flex: none; }
.asp-chip__when  { font-weight: 400; }

.asp-chip--not-started { color: var(--status-not-started); background: var(--wash-not-started); }
.asp-chip--in-progress { color: var(--status-in-progress); background: var(--wash-in-progress); }
.asp-chip--due-soon    { color: var(--status-due-soon);    background: var(--wash-due-soon); }
.asp-chip--past-due    { color: var(--status-past-due);    background: var(--wash-past-due); }
.asp-chip--complete    { color: var(--status-complete);    background: var(--wash-complete); }

/* High contrast collapses the washes to black, so the border carries shape. */
[data-theme="hc"] .asp-chip { border-color: currentColor; }

/* -------------------------------------------------------- progress ----- */

.asp-progress__track {
  block-size: 10px;
  background: var(--surface-sunken);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.asp-progress__fill { block-size: 10px; background: var(--status-in-progress); }
.asp-progress__fill--complete { background: var(--status-complete); }

/* Always paired with a text fraction ("9 of 14 sections"). Never a bare
   percentage, and never a fill that shifts red-to-green as it grows. */
.asp-progress__text { font-size: var(--text-small-size); color: var(--ink-muted); }

/* -------------------------------------------------------- form field --- */

.asp-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-block-end: var(--space-lg);
}

.asp-field__label {
  font-size: var(--text-label-size);
  line-height: var(--text-label-line);
  font-weight: 700;
  color: var(--ink-strong);
}

.asp-field__required { font-weight: 400; color: var(--ink-muted); }

/* Help text renders BEFORE the input, in source order and on screen. */
.asp-field__help { font-size: var(--text-small-size); line-height: var(--text-small-line); color: var(--ink-muted); margin: 0; }

.asp-input, .asp-textarea, .asp-select {
  font-family: var(--font-body);
  font-size: var(--text-body-size);
  line-height: var(--text-body-line);
  color: var(--ink-strong);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-md) var(--space-base);
  min-block-size: 46px;
  inline-size: 100%;
}

.asp-textarea { min-block-size: 140px; max-inline-size: 72ch; resize: vertical; }

.asp-input--invalid, .asp-textarea--invalid {
  border-color: var(--status-past-due);
  border-width: 2px;
}

.asp-field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  font-size: var(--text-small-size);
  line-height: var(--text-small-line);
  font-weight: 700;
  color: var(--status-past-due);
  margin: 0;
}

.asp-field__count { font-family: var(--font-data); font-size: var(--text-small-size); color: var(--ink-muted); align-self: flex-end; }

/* ------------------------------------------------------------ banner --- */

.asp-banner {
  display: flex;
  gap: var(--space-base);
  padding: var(--space-lg);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  color: var(--ink-strong);
}

.asp-banner__icon { inline-size: 28px; block-size: 28px; flex: none; }
.asp-banner__title { font-family: var(--font-display); font-size: var(--text-title3-size); font-weight: 600; color: var(--ink-strong); margin: 0 0 var(--space-xs); }
.asp-banner__text { font-size: var(--text-body-size); line-height: var(--text-body-line); margin: 0; max-inline-size: 72ch; }
.asp-banner__actions { display: flex; gap: var(--space-sm); margin-block-start: var(--space-md); }

.asp-banner--info      { border-color: var(--line); }
.asp-banner--info .asp-banner__icon { color: var(--status-in-progress); }
.asp-banner--attention { border-color: var(--status-due-soon); }
.asp-banner--attention .asp-banner__icon { color: var(--status-due-soon); }
/* alert = data loss or a blocked action ONLY. Never a deadline, never a count. */
.asp-banner--alert     { border-color: var(--status-past-due); border-width: 2px; }
.asp-banner--alert .asp-banner__icon { color: var(--status-past-due); }

/* -------------------------------------------------------------- card --- */

.asp-card {
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
}

.asp-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-base);
  padding: var(--space-lg) var(--space-xl);
  border-block-end: 1px solid var(--line);
}

.asp-card__body { padding: var(--space-lg) var(--space-xl); }

/* ------------------------------------------------------------- table --- */

.asp-table {
  inline-size: 100%;
  border-collapse: collapse;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.asp-table caption {
  text-align: start;
  font-size: var(--text-small-size);
  color: var(--ink-muted);
  padding-block-end: var(--space-sm);
}

.asp-table th, .asp-table td {
  text-align: start;
  padding: var(--space-base);
  border-block-end: 1px solid var(--line);
  font-size: var(--text-body-size);
  line-height: var(--text-body-line);
  color: var(--ink-strong);
  vertical-align: middle;
}

.asp-table thead th {
  background: var(--surface-subtle);
  font-size: var(--text-label-size);
  font-weight: 700;
  color: var(--ink-strong);
}

.asp-table tbody tr:hover { background: var(--surface-subtle); }
.asp-table tr[aria-selected="true"] { background: var(--brand-wash); }

/* A row is NEVER coloured by status. One chip in the status column carries
   it. A caseload with four past-due students must not look like an alarm. */

.asp-table__name { font-weight: 700; color: var(--ink-strong); }
.asp-table__id, .asp-table__date { font-family: var(--font-data); font-size: var(--text-small-size); font-variant-numeric: tabular-nums; }

/* A Chromebook in a classroom is the common case, not the edge case:
   below 1024px the table stacks rather than scrolling sideways. */
@media (max-width: 1023px) {
  .asp-table thead { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }
  .asp-table tbody tr { display: block; border-block-end: 1px solid var(--line); padding-block: var(--space-sm); }
  .asp-table td { display: flex; justify-content: space-between; gap: var(--space-base); border: none; padding-block: var(--space-xs); }
  .asp-table td::before { content: attr(data-label); font-size: var(--text-small-size); font-weight: 700; color: var(--ink-muted); }
}

/* ------------------------------------------------------------ shared --- */

.asp-visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------- print --- */
/* Generated documents print in greyscale. Status is stated in words; no
   status colour survives into a printed document. */
@media print {
  body { background: #ffffff; color: #000000; }
  .asp-appbar, .asp-identity-rule, .asp-btn { display: none; }
  .asp-chip { border: 1px solid #000000; background: none; color: #000000; }
  .asp-card { border: 1px solid #000000; box-shadow: none; }
  .asp-doc-body { font-size: 10.5pt; line-height: 15pt; }
}

/* ==========================================================================
   Additions for this application, built only from Aspire tokens.
   Kept below the imported contract so the boundary stays visible.
   ========================================================================== */

/* A label that carries no state: a document category, a ruleset version, a
   catalogue tier. Deliberately shapeless — a status shape here would assert an
   urgency the value does not have. */
.asp-tag {
  display: inline-flex;
  align-items: center;
  padding: 4px var(--space-md);
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-strong);
  background: var(--surface-subtle);
  color: var(--ink-strong);
  font-family: var(--font-body);
  font-size: var(--text-small-size);
  line-height: 20px;
  white-space: nowrap;
}

/* ============================================================
   Language switcher — the fixed bottom-right control

   Shaped after the switcher Columbus City Schools runs on
   ccsoh.us: a small raised card in the bottom-right corner
   carrying a rectangular flag and the full language name, which
   opens upward into the list. The district's is a hosted Weglot
   widget; this one is ours, so it is themed like the rest of the
   app and works with no network.

   It sits at z-index 50: above the page and the portal tab bar,
   below the modal overlay (60) and the toasts (80), because a
   language control should never cover a confirmation the user
   has to answer. #toasts is lifted clear of it in app.css.
   ============================================================ */
.lang-switch {
  position: fixed; inset-inline-end: 22px; bottom: 22px; z-index: 50;
  font-family: var(--font-body);
}
.lang-switch > summary {
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--surface-raised); color: var(--ink-strong);
  border: 1px solid var(--line-strong); border-radius: var(--radius-pill);
  box-shadow: var(--shadow-raised); cursor: pointer;
  font-size: var(--text-small-size); line-height: var(--text-small-line); font-weight: 600;
  list-style: none; user-select: none;
}
/* The native disclosure triangle is replaced by our own caret, which can sit
   on the correct side in RTL and rotate on open. */
.lang-switch > summary::-webkit-details-marker { display: none; }
.lang-switch > summary::marker { content: ""; }
.lang-switch > summary:hover { background: var(--surface-subtle); }
.lang-switch > summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.lang-caret { display: inline-flex; transition: transform .15s ease; }
.lang-caret svg { width: 16px; height: 16px; }
.lang-switch[open] .lang-caret { transform: rotate(180deg); }

/* A hairline around every flag: several of these are white at the edge and
   would otherwise bleed into the card they sit on. */
.lang-flag {
  width: 20px; height: 15px; flex: none; border-radius: 2px;
  border: 0.5px solid var(--line-strong); object-fit: cover; display: block;
}

.lang-menu {
  position: absolute; inset-inline-end: 0; bottom: calc(100% + var(--space-sm));
  min-width: 232px; max-height: min(60vh, 420px); overflow-y: auto;
  background: var(--surface-raised); border: 1px solid var(--line-strong);
  border-radius: var(--radius-md); box-shadow: var(--shadow-overlay);
  padding: var(--space-xs);
}
.lang-menu-head {
  padding: var(--space-sm) var(--space-sm) var(--space-xs);
  font-size: 14px; line-height: 20px; font-weight: 700;
  letter-spacing: .02em; color: var(--ink-muted);
}
.lang-opt {
  display: flex; align-items: center; gap: var(--space-md); width: 100%;
  padding: var(--space-sm) var(--space-sm);
  background: none; border: 0; border-radius: var(--radius-sm);
  font: inherit; font-size: var(--text-small-size); line-height: var(--text-small-line);
  color: var(--ink-strong); text-align: start; cursor: pointer;
}
.lang-opt:hover { background: var(--surface-subtle); }
.lang-opt:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.lang-opt.on { background: var(--brand-wash); font-weight: 700; }
/* Inert options are not dimmed. They are still information — the eight
   languages the district publishes — and dimming them would drop them below
   contrast to say something the tooltip and the note already say. */
.lang-opt[aria-disabled="true"] { cursor: not-allowed; }
.lang-menu-note {
  margin: var(--space-xs) 0 var(--space-2xs);
  padding: var(--space-sm);
  border-top: 1px solid var(--line);
  font-size: 14px; line-height: 20px; color: var(--ink-muted);
}

/* Clear of the portal's bottom tab bar, which is 52px plus the safe area and
   only exists below this width. Staff screens have no tab bar, but lifting the
   control on a phone costs them nothing. */
@media (max-width: 860px) {
  .lang-switch {
    inset-inline-end: var(--space-md);
    bottom: calc(64px + env(safe-area-inset-bottom, 0px));
  }
  .lang-menu { max-height: min(50vh, 340px); }
}

/* The machine-translation caveat sits under the note it qualifies, so it takes
   no rule of its own — two hairlines a line apart read as a broken border. */
.lang-menu-caveat {
  margin-top: 0; padding-top: 0; border-top: 0;
  display: flex; gap: var(--space-sm); align-items: flex-start;
}
.lang-menu-caveat svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }

/* ============================================================
   Feedback tickets — the edge tab, the pin overlay, the board

   Tooling for the two people building this site, not part of the
   demonstration (js/tickets.js says why). Drawn in the chrome's own
   fixed navy ramp so it reads as the same family as the rail, and so
   the pin marker stays visible on a screenshot in any theme.

   Layering: the tab sits at 50 beside the language switcher, its
   panel at 55, the pin overlay at 58, all below the modal (60) and
   the toasts (80). The tab is parked well above the bottom corner so
   the two never overlap.
   ============================================================ */
.fb-tab {
  position: fixed; z-index: 50;
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-md) var(--space-sm);
  writing-mode: vertical-rl;
  background: var(--chrome); color: var(--on-chrome);
  border: 1px solid var(--chrome-hairline);
  box-shadow: var(--shadow-raised);
  font-family: var(--font-body); font-size: 15px; font-weight: 700; letter-spacing: .04em;
  cursor: grab; touch-action: none; user-select: none;
}
.fb-tab.fb-right { right: 0; border-radius: var(--radius-md) 0 0 var(--radius-md); border-right: 0; }
.fb-tab.fb-left  { left: 0;  border-radius: 0 var(--radius-md) var(--radius-md) 0; border-left: 0; }
.fb-tab:hover { background: var(--chrome-hover); }
.fb-tab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.fb-tab.fb-dragging { cursor: grabbing; border-radius: var(--radius-md); }
.fb-tab-ic { display: inline-flex; transform: rotate(90deg); }
.fb-tab-ic svg { width: 18px; height: 18px; }

.fb-panel {
  position: fixed; z-index: 55; width: 248px;
  padding: var(--space-xs);
  background: var(--surface-raised); color: var(--ink-strong);
  border: 1px solid var(--line-strong); border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
  font-family: var(--font-body);
}
.fb-panel-head {
  padding: var(--space-sm) var(--space-sm) var(--space-xs);
  font-size: 14px; font-weight: 700; color: var(--ink-muted);
}
.fb-panel-item {
  display: flex; align-items: center; gap: var(--space-sm); width: 100%;
  padding: var(--space-sm); border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--ink-strong); text-decoration: none; text-align: start;
  font: inherit; font-size: var(--text-small-size); cursor: pointer;
}
.fb-panel-item:hover { background: var(--surface-subtle); }
.fb-panel-item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.fb-panel-item svg { width: 18px; height: 18px; flex: none; color: var(--ink-muted); }

/* The pin overlay. Transparent itself; the dimming is the highlight box's
   own enormous shadow, so the thing under the cursor is the one bright area. */
.fb-pick { position: fixed; inset: 0; z-index: 58; cursor: crosshair; user-select: none; touch-action: none; }
.fb-pick.capturing { cursor: progress; }
.fb-pick-box {
  position: absolute; pointer-events: none;
  border: 2px solid var(--focus-ring); border-radius: var(--radius-xs);
  box-shadow: 0 0 0 9999px color-mix(in srgb, var(--overlay) 45%, transparent);
}
.fb-pick-box.dashed { border-style: dashed; }
.fb-pick-bar {
  position: absolute; top: var(--space-lg); left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--space-md); flex-wrap: wrap; justify-content: center;
  max-width: calc(100vw - 32px);
  padding: var(--space-sm) var(--space-sm) var(--space-sm) var(--space-md);
  background: var(--chrome); color: var(--on-chrome);
  border-radius: var(--radius-pill); box-shadow: var(--shadow-overlay);
  font-family: var(--font-body); font-size: 14px; font-weight: 600;
}
.fb-pick-skip {
  padding: var(--space-xs) var(--space-md); border: 1px solid var(--chrome-hairline);
  border-radius: var(--radius-pill); background: var(--chrome-hover); color: var(--on-chrome);
  font: inherit; cursor: pointer;
}
.fb-pick-skip:hover { background: var(--chrome-hover-strong); }

/* A screenshot with the reporter's click drawn on top. The pin is positioned
   in percentages of the picture, so it lands on the same spot at any size. */
.fb-shot { position: relative; display: inline-block; max-width: 100%; margin-bottom: var(--space-md);
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.fb-shot img { display: block; max-width: 100%; max-height: 220px; width: auto; }
.fbb-shot img { max-height: 420px; }
.fb-pin {
  position: absolute; width: 20px; height: 20px; transform: translate(-50%, -50%);
  border-radius: 50%; background: var(--chrome); border: 3px solid var(--on-chrome);
  box-shadow: 0 0 0 2px var(--chrome), var(--shadow-raised); pointer-events: none;
}
.fb-shot-remove {
  position: absolute; top: var(--space-xs); right: var(--space-xs);
  display: inline-flex; padding: var(--space-xs); border: 0; border-radius: 50%;
  background: var(--chrome); color: var(--on-chrome); cursor: pointer;
}
.fb-shot-remove svg { width: 16px; height: 16px; }

.fb-memo-row { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: var(--space-sm); }
.fb-memo-row audio { flex: 1 1 240px; min-width: 0; height: 40px; }
.fb-rec-on { color: var(--status-past-due); }
.fb-file-input { font-size: 14px; max-width: 100%; }
.fb-chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-sm); }
.fb-chip {
  display: inline-flex; align-items: center; gap: var(--space-xs);
  padding: var(--space-2xs) var(--space-sm); border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill); background: var(--surface-subtle); color: var(--ink-strong);
  font-size: 14px; text-decoration: none; max-width: 100%;
}
.fb-chip > span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.fb-chip svg { width: 16px; height: 16px; flex: none; }
.fb-chip-size { color: var(--ink-muted); }
.fb-chip-x { display: inline-flex; padding: 2px; border: 0; background: none; color: var(--ink-muted); cursor: pointer; border-radius: 50%; }
.fb-chip-x:hover { background: var(--surface-sunken); color: var(--ink-strong); }

/* The board: six columns side by side, scrolling sideways inside the page
   rather than making the page itself scroll sideways. */
.fbb-board {
  display: grid; grid-template-columns: repeat(6, minmax(220px, 1fr)); gap: var(--space-md);
  overflow-x: auto; padding-bottom: var(--space-md);
}
.fbb-col {
  display: flex; flex-direction: column; min-height: 240px;
  background: var(--surface-sunken); border: 1px solid var(--line); border-radius: var(--radius-md);
}
.fbb-col.over { outline: 2px dashed var(--focus-ring); outline-offset: -2px; }
.fbb-col.collapsed { min-height: 0; }
.fbb-col-head { display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-sm) var(--space-md); }
.fbb-col-head h2 { font-size: 15px; font-weight: 700; color: var(--ink-strong); margin: 0; }
.fbb-count { font-size: 14px; color: var(--ink-muted); margin-inline-end: auto; }
.fbb-cards { display: flex; flex-direction: column; gap: var(--space-sm); padding: 0 var(--space-sm) var(--space-sm); flex: 1; }
.fbb-card {
  display: flex; flex-direction: column; gap: var(--space-xs);
  padding: var(--space-sm) var(--space-md);
  background: var(--surface-raised); color: var(--ink-strong); text-decoration: none;
  border: 1px solid var(--line); border-radius: var(--radius-sm); box-shadow: var(--shadow-raised);
  cursor: grab;
}
.fbb-card:hover { border-color: var(--line-strong); }
.fbb-card:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.fbb-card.dragging { opacity: .5; }
.fbb-card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); }
.fbb-num { font-family: var(--font-data); font-size: 14px; color: var(--ink-muted); }
.fbb-title { font-size: 15px; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.fbb-meta { font-size: 14px; color: var(--ink-muted); }

.fbb-pickers { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-md); }
.fbb-desc { white-space: pre-wrap; overflow-wrap: anywhere; margin: var(--space-sm) 0 var(--space-md); line-height: 1.5; }
.fbb-figure { margin: 0 0 var(--space-md); }
.fbb-figure figcaption a { display: inline-flex; align-items: center; gap: var(--space-xs); }
.fbb-figure figcaption svg { width: 16px; height: 16px; }
.fbb-context { margin: var(--space-md) 0; padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-subtle); }
.fbb-context summary { cursor: pointer; font-weight: 600; }
.fbb-context dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-xs) var(--space-md); margin: var(--space-md) 0; }
.fbb-context dt { color: var(--ink-muted); font-size: 14px; }
.fbb-context dd { margin: 0; overflow-wrap: anywhere; font-size: 14px; }
.fbb-context h3, .fbb-h { font-size: 15px; font-weight: 700; margin: var(--space-md) 0 var(--space-sm); }
.fbb-errors { margin: 0; padding-inline-start: var(--space-lg); font-size: 14px; }
.fbb-errors code { overflow-wrap: anywhere; }
.fbb-comments { list-style: none; margin: 0 0 var(--space-md); padding: 0; display: flex; flex-direction: column; gap: var(--space-sm); }
.fbb-comment { padding: var(--space-sm) var(--space-md); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.fbb-comment-body { white-space: pre-wrap; overflow-wrap: anywhere; margin-top: var(--space-xs); }
.fbb-reply-row { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }
.fbb-reply-row label.btn { position: relative; overflow: hidden; cursor: pointer; }
.fbb-reply-row label.btn input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.fbb-reply-row .btn-primary { margin-inline-start: auto; }

@media (max-width: 860px) {
  .fbb-board { grid-template-columns: repeat(6, minmax(78vw, 1fr)); scroll-snap-type: x mandatory; }
  .fbb-col { scroll-snap-align: start; }
}
