@import "tailwindcss";

@source "../../views/**/*.erb";
@source "../../helpers/**/*.rb";
@source "../../javascript/**/*.js";

/* Cornerstone design tokens (ref -> sys -> cmp), scoped by data-brand/data-theme on <html> */
@import "@cruglobal/cornerstone-design-system/css/ref";
@import "@cruglobal/cornerstone-design-system/css/cru-light";
@import "@cruglobal/cornerstone-design-system/css/cru-dark";

/* daisyUI + Cornerstone's daisyUI theme bridge (cru-light / cru-dark) */
@plugin "daisyui" {
  themes: false;
}
@import "../../../node_modules/@cruglobal/cornerstone-design-system/libraries/daisyui.css";

/* Map Tailwind utility colors onto Cornerstone sys tokens so bg-surface,
   text-on-surface, border-outline, etc. re-skin via the cascade. */
@theme inline {
  --color-surface: var(--sys-color-surface-default);
  --color-surface-low: var(--sys-color-surface-container-low);
  --color-surface-container: var(--sys-color-surface-container);
  --color-surface-high: var(--sys-color-surface-container-high);
  --color-surface-highest: var(--sys-color-surface-container-highest);
  --color-surface-bright: var(--sys-color-surface-bright);
  --color-on-surface: var(--sys-color-on-surface);
  --color-muted: var(--sys-color-on-surface-variant);
  --color-outline: var(--sys-color-outline-variant-default);
  --color-outline-strong: var(--sys-color-outline-default);
  --color-divider: var(--sys-color-divider);
  --color-brand: var(--sys-color-primary-default);
  --color-on-brand: var(--sys-color-on-primary);
  --color-danger: var(--sys-color-danger-default);
  --color-on-danger: var(--sys-color-on-danger);
  --color-success-tone: var(--sys-color-success-default);
  --color-warning-tone: var(--sys-color-warning-default);
  --color-info-tone: var(--sys-color-information-default);
  --color-link: var(--sys-color-link-default);

  --font-display: var(--sys-string-font-family-display);
  --font-headline: var(--sys-string-font-family-headline);
  --font-body: var(--sys-string-font-family-body);
}

/* ============================================================
   Plane visual parity reskin — design-token override (U2/U3/U4)
   Re-points cornerstone sys-color + font tokens (on <html>) and the
   daisyUI bridge color + radius + border vars (on <body>) to Plane's
   measured palette. See docs/design/plane-reference/tokens.md.
   Placed after the cornerstone @imports + daisyUI bridge so it wins on
   source order (cornerstone) / unlayered precedence (daisyUI) at equal
   selector specificity. oklch values are authoritative.
   ============================================================ */

/* U2/U3 — cornerstone sys tokens + Inter, dark */
[data-brand="cru"][data-theme="dark"] {
  --sys-color-surface-default: oklch(0.169 0.002 231);
  --sys-color-surface-container-low: oklch(0.193 0.002 231);
  --sys-color-surface-container: oklch(0.216 0.003 231);
  --sys-color-surface-container-high: oklch(0.238 0.003 231);
  --sys-color-surface-container-highest: oklch(0.259 0.003 231);
  --sys-color-surface-bright: oklch(0.259 0.003 231);
  --sys-color-on-surface: oklch(0.924 0.002 231);
  --sys-color-on-surface-variant: oklch(0.684 0.007 231);
  --sys-color-outline-variant-default: oklch(0.342 0.005 231);
  --sys-color-outline-default: oklch(0.404 0.006 231);
  --sys-color-divider: oklch(0.301 0.004 231);
  --sys-color-primary-default: oklch(0.631 0.126 238);
  --sys-color-on-primary: #ffffff;
  /* Dark-theme danger sat too low (0.62) — barely above the light value, so
     text-danger delete/destroy controls were hard to read on the dark surface.
     Lift the lightness for legible red on dark; on-danger stays #fff for the
     solid danger-button case (white-on-red remains readable at this L). */
  --sys-color-danger-default: oklch(0.70 0.19 25);
  --sys-color-on-danger: #ffffff;
  --sys-color-success-default: oklch(0.68 0.15 152);
  --sys-color-warning-default: oklch(0.79 0.147 82);
  --sys-color-information-default: oklch(0.631 0.126 238);
  --sys-color-link-default: oklch(0.66 0.13 238);
  --sys-string-font-family-display: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
  --sys-string-font-family-headline: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
  --sys-string-font-family-body: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
}

/* U2/U3 — cornerstone sys tokens + Inter, light */
[data-brand="cru"][data-theme="light"] {
  --sys-color-surface-default: oklch(0.954 0.001 231);
  --sys-color-surface-container-low: oklch(1 0 0);
  --sys-color-surface-container: oklch(0.985 0.001 231);
  --sys-color-surface-container-high: oklch(0.970 0.001 231);
  --sys-color-surface-container-highest: oklch(0.955 0.001 231);
  --sys-color-surface-bright: oklch(1 0 0);
  --sys-color-on-surface: oklch(0.238 0.003 231);
  --sys-color-on-surface-variant: oklch(0.667 0.008 231);
  --sys-color-outline-variant-default: oklch(0.905 0.004 231);
  --sys-color-outline-default: oklch(0.835 0.005 231);
  --sys-color-divider: oklch(0.930 0.003 231);
  --sys-color-primary-default: oklch(0.58 0.14 245);
  --sys-color-on-primary: #ffffff;
  --sys-color-danger-default: oklch(0.58 0.20 25);
  --sys-color-on-danger: #ffffff;
  --sys-color-success-default: oklch(0.62 0.15 152);
  --sys-color-warning-default: oklch(0.75 0.15 70);
  --sys-color-information-default: oklch(0.58 0.14 245);
  --sys-color-link-default: oklch(0.55 0.15 250);
  --sys-string-font-family-display: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
  --sys-string-font-family-headline: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
  --sys-string-font-family-body: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
}

/* U2/U4 — daisyUI bridge theme vars (unlayered beats the @plugin theme) */
[data-theme="cru-dark"] {
  --color-base-100: #0f1112;
  --color-base-200: #16191b;
  --color-base-300: #1e2123;
  --color-base-content: #e7e9eb;
  --color-primary: #2f80d8;
  --color-primary-content: #ffffff;
  --radius-selector: 0.375rem;
  --radius-field: 0.375rem;
  --radius-box: 0.5rem;
  --border: 1px;
}
[data-theme="cru-light"] {
  --color-base-100: #ffffff;
  --color-base-200: #f6f6f7;
  --color-base-300: #eceef0;
  --color-base-content: #1e2123;
  --color-primary: #2f6fd0;
  --color-primary-content: #ffffff;
  --radius-selector: 0.375rem;
  --radius-field: 0.375rem;
  --radius-box: 0.5rem;
  --border: 1px;
}

@layer base {
  html {
    @apply h-full;
  }
  body {
    @apply h-full bg-surface text-on-surface font-body antialiased text-[13px];
  }
  ::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }
  ::-webkit-scrollbar-thumb {
    background: var(--sys-color-outline-variant-default);
    border-radius: 4px;
  }
  ::-webkit-scrollbar-track {
    background: transparent;
  }
}

@layer components {
  /* App shell */
  .fd-rail-btn {
    @apply flex flex-col items-center gap-1 px-2 py-1.5 rounded-md text-muted transition-colors
      hover:text-on-surface hover:bg-surface-high cursor-pointer text-[10px];
  }
  .fd-rail-btn.active {
    @apply text-on-surface bg-surface-high;
  }
  .fd-side-link {
    @apply flex items-center gap-2 px-2 py-1.5 rounded-md text-[13px] text-muted transition-colors
      hover:bg-surface-high hover:text-on-surface;
  }
  .fd-side-link.active {
    @apply bg-surface-high text-on-surface;
  }
  /* FD-497: sidebar project rows repeat ~90× per page — the repeated utility lists
     live here once instead of ~90× in the HTML (page-weight cut). */
  summary.fd-side-link {
    @apply cursor-pointer list-none select-none;
  }
  .fd-star-btn {
    @apply ml-auto shrink-0 flex items-center cursor-pointer text-muted hover:text-on-surface
      opacity-0 group-hover:opacity-100 focus:opacity-100;
  }
  .fd-star-btn.on {
    /* declared after the base so its color/opacity win on hover too */
    @apply opacity-100 text-warning-tone hover:opacity-70;
  }
  .fd-side-chevron {
    @apply shrink-0 text-muted group-open:rotate-90 transition-transform;
  }

  /* Square icon button used in the top bar (hamburger, search, help, inbox) */
  .fd-icon-btn {
    @apply inline-flex items-center justify-center size-9 rounded-md text-muted transition-colors
      hover:text-on-surface hover:bg-surface-high cursor-pointer shrink-0;
  }

  /* Property chips on work item rows/cards */
  .fd-chip {
    @apply inline-flex items-center gap-1 rounded-sm border border-outline px-1.5 py-0.5
      text-[11px] leading-4 text-muted transition-colors hover:bg-surface-high cursor-pointer whitespace-nowrap;
  }

  /* Plane-style ↑N ↓N vote counts in the work-item header (FD-188) */
  .fd-vote {
    @apply inline-flex items-center gap-0.5 rounded-md border border-outline px-1.5 h-7
      text-[12px] text-muted transition-colors hover:bg-surface-high hover:text-on-surface cursor-pointer;
  }
  .fd-vote-on {
    @apply border-brand text-on-surface;
  }

  .fd-input {
    @apply input input-sm bg-surface-low border-outline w-full rounded-md text-[13px]
      focus:outline-none focus:border-outline-strong;
  }

  /* FD-560: .fd-input @applies daisyUI's .input, whose single-line contract
     (white-space:nowrap, display:inline-flex, align-items:center, height:var(--size))
     is wrong for a <textarea>: text never wraps and rows= is inert. Element-scope the
     override so <input>/<select>/<code>.fd-input are untouched. This can live in
     @layer components (unlike .select[multiple] below): a <textarea> carries no
     `input` class, so daisyUI's own .input rule never matches it — only the
     @apply-inlined copy inside .fd-input competes, and textarea.fd-input outranks it
     by specificity within the layer. pre-wrap (not whitespace-normal) is the native
     textarea default and preserves the indentation/blank lines the Markdown editors
     rely on. */
  textarea.fd-input {
    @apply block h-auto py-2 leading-5;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    align-items: normal;
  }

  /* Plane-style collapsible groups in the Properties rail (Details / Project structure) */
  .fd-prop-group {
    @apply border-t border-divider/60 pt-2 mt-2 first:border-0 first:pt-0 first:mt-0;
  }
  .fd-prop-group-summary {
    @apply flex items-center gap-1 cursor-pointer list-none select-none py-0.5
      text-[12px] font-medium text-on-surface;
  }
  .fd-prop-group-summary::-webkit-details-marker { display: none; }
  .fd-prop-group-chevron {
    @apply text-[10px] leading-none text-muted transition-transform;
  }

  /* Plane-style property picker: trigger pill + popover panel */
  .fd-prop-pill {
    @apply inline-flex items-center gap-1.5 w-full rounded-md border border-transparent px-1.5 py-1
      text-[12px] text-on-surface text-left transition-colors cursor-pointer
      hover:bg-surface-high hover:border-outline focus:outline-none focus:bg-surface-high focus:border-outline-strong;
  }
  .fd-date-pill {
    @apply bg-transparent border border-transparent rounded-md px-1.5 py-1 text-[12px] w-full
      transition-colors hover:bg-surface-high hover:border-outline focus:outline-none focus:border-outline-strong;
  }
  /* Inline variants for the under-title property strip (Plane shows State/Priority/
     Assignees/dates as a row of discrete pills beneath the title). */
  .fd-prop-pill-inline {
    @apply inline-flex items-center gap-1.5 rounded-md border border-outline px-2 py-1
      text-[12px] text-on-surface transition-colors cursor-pointer whitespace-nowrap
      hover:bg-surface-high focus:outline-none focus:border-outline-strong;
  }
  .fd-date-pill-inline {
    @apply inline-flex items-center rounded-md border border-outline bg-transparent px-2 py-1 text-[12px]
      transition-colors hover:bg-surface-high focus:outline-none focus:border-outline-strong;
  }
  .fd-popover {
    @apply absolute left-0 top-full mt-1 z-50 w-64 max-w-[80vw] rounded-lg border border-outline
      bg-surface shadow-lg overflow-hidden;
  }
  /* FD-274 D10: when a trigger sits near the right edge (e.g. a property pill in the
     peek panel, whose overflow-y-auto also clips horizontally) the left-anchored
     popover would overflow and be clipped. popover_controller flips it to right-anchored. */
  .fd-popover--flip {
    @apply left-auto right-0;
  }
  /* FD-426: open the popover ABOVE its trigger — for pickers anchored to the bottom
     (e.g. the fixed bulk-action bar) whose downward panel would fall off-screen. */
  .fd-popover--up {
    @apply top-auto bottom-full mt-0 mb-1;
  }
  .fd-popover-list {
    @apply max-h-64 overflow-y-auto p-1 flex flex-col;
  }
  .fd-popover-opt {
    @apply flex items-center gap-2 px-2 py-1.5 rounded-md text-[12px] cursor-pointer
      transition-colors hover:bg-surface-high;
  }
  .fd-popover-check {
    @apply ml-auto shrink-0 text-brand opacity-0;
  }
  .fd-popover-opt .peer:checked ~ .fd-popover-check { @apply opacity-100; }
  .fd-popover-opt:has(.peer:checked) { @apply bg-surface-high/60; }
  /* daisyUI 5's .btn carries no cursor, and Tailwind v4 dropped the old
     button→pointer default, so add it here for <button> elements (links already
     get pointer). */
  .fd-btn-primary {
    @apply btn btn-sm btn-primary rounded-md font-medium cursor-pointer;
  }
  .fd-btn-ghost {
    @apply btn btn-sm btn-ghost rounded-md font-normal border border-outline cursor-pointer;
  }

  .fd-card {
    @apply bg-surface-low border border-outline rounded-lg;
  }

  /* Kanban — full-ish width columns on phones (swipe between); base 320px on
     desktop. FD-516: _layout_board layers md:flex-1 + min/max-w utilities on top
     so columns flex into ultrawide viewports while md:w-[320px] stays the
     fallback for any bare .fd-kanban-col. */
  .fd-kanban-col {
    @apply w-[86vw] max-w-[320px] shrink-0 flex flex-col rounded-lg bg-surface-low/60 snap-start
      md:w-[320px] md:max-w-none;
  }
  .fd-kanban-card {
    @apply bg-surface-low border border-outline rounded-lg p-3 flex flex-col gap-2 cursor-pointer hover:bg-surface-container shadow-sm;
  }
  .fd-kanban-card.sortable-ghost {
    @apply opacity-40 border-dashed border-outline-strong;
  }
  /* FD-595: the whole card opens the item, not just the ~18px title strip. The
     title link is the single accessible/focusable control; its ::after is
     stretched over the whole (position:relative) card so a click anywhere on the
     card body opens the peek editor — matching the card-wide cursor:pointer and
     Plane's clickable cards. Interactive children (the ⋯ actions menu) are raised
     above it with z-10 so they keep receiving their own clicks. Used by the board
     and gallery cards (both tall cards where the title is a small target). */
  .fd-card-stretch::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
  }

  /* Rich text (Action Text, rendered read-only) */
  .fd-prose {
    @apply max-w-none leading-relaxed text-[13px];
  }
  .fd-prose h1 { @apply text-xl font-semibold mt-4 mb-2 font-headline; }
  .fd-prose h2 { @apply text-lg font-semibold mt-3 mb-1.5 font-headline; }
  .fd-prose h3 { @apply text-base font-semibold mt-2 mb-1; }
  .fd-prose ul { @apply list-disc pl-5 my-1.5; }
  .fd-prose ol { @apply list-decimal pl-5 my-1.5; }
  .fd-prose a { @apply text-link underline; }
  .fd-prose pre { @apply bg-surface-high rounded-md p-3 my-2 overflow-x-auto text-xs; }
  .fd-prose blockquote { @apply border-l-2 border-outline-strong pl-3 text-muted my-2; }
  .fd-prose img { @apply rounded-md my-2 max-w-full; }

  /* FD-427: Markdown pages (GFM tables, inline code, Mermaid). The Action Text
     rules above cover Trix output; these add what commonmarker emits. All use
     cornerstone/daisyUI tokens, so they adapt to cru-light / cru-dark. */
  .fd-prose h4 { @apply text-sm font-semibold mt-2 mb-1; }
  .fd-prose h5, .fd-prose h6 { @apply text-xs font-semibold uppercase tracking-wide text-muted mt-2 mb-1; }
  .fd-prose p { @apply my-2; }
  .fd-prose li { @apply my-0.5; }
  .fd-prose hr { @apply border-outline my-4; }
  .fd-prose code { @apply bg-surface-high border border-outline rounded px-1 py-0.5 text-[11px] font-mono; }
  .fd-prose pre code { @apply bg-transparent border-0 p-0 text-xs; }
  /* GitHub-style auto header-anchor links: keep them out of the text flow. */
  .fd-prose a.anchor { @apply hidden; }
  /* GFM task-list checkboxes render as <li> with a leading <input>. */
  .fd-prose ul:has(input[type="checkbox"]) { @apply list-none pl-1; }
  .fd-prose input[type="checkbox"] { @apply mr-1 align-middle; }

  .fd-prose table { @apply w-full my-3 text-xs border-collapse; }
  .fd-prose thead { @apply bg-surface-high; }
  .fd-prose th { @apply text-left font-semibold p-2 border border-outline; }
  .fd-prose td { @apply p-2 border border-outline align-top; }
  .fd-prose tbody tr:nth-child(even) { @apply bg-surface-high/40; }

  /* Mermaid diagram: client-rendered SVG dropped into a <figure class="fd-mermaid">. */
  .fd-prose .fd-mermaid { @apply my-4 flex justify-center overflow-x-auto rounded-md border border-outline bg-surface-high p-3; }
  .fd-prose .fd-mermaid svg { @apply max-w-full h-auto; }
  /* A diagram that failed to parse falls back to its visible source. */
  .fd-prose .fd-mermaid-error { @apply border border-danger; }

  /* Help center long-form docs */
  .help-doc h1 { @apply text-2xl font-headline font-semibold mb-3; }
  .help-doc h2 { @apply text-base font-headline font-semibold mt-6 mb-2; }
  .help-doc p { @apply my-2 leading-relaxed text-[13px]; }
  .help-doc ul, .help-doc ol { @apply my-2 leading-relaxed; }
  .help-doc li { @apply my-1; }
  .help-doc code { @apply bg-surface-high border border-outline rounded px-1 py-0.5 text-[11px]; }
  .help-doc kbd { @apply kbd kbd-sm; }
  .help-doc strong { @apply text-on-surface; }
  .help-doc .not-prose a, .help-doc .not-prose div { @apply no-underline text-on-surface; }
  .help-doc .not-prose .text-muted { @apply text-muted; }
  .help-doc table { @apply w-full my-3 text-[12px] border border-outline rounded-lg; }
  .help-doc th { @apply text-left text-muted font-medium px-3 py-1.5 border-b border-outline bg-surface-low; }
  .help-doc td { @apply px-3 py-1.5 border-b border-divider align-top; }


  /* FD-208: Tiptap block editor (progressive enhancement of Action Text fields) */
  .fd-block-editor {
    @apply bg-surface-low border border-outline rounded-md overflow-hidden focus-within:border-outline-strong;
  }
  .fd-block-toolbar {
    @apply flex flex-wrap items-center gap-0.5 px-1.5 py-1 border-b border-outline bg-surface-low/60;
  }
  .fd-block-btn {
    @apply inline-flex items-center justify-center min-w-7 h-7 px-1.5 rounded text-[12px] text-muted
      cursor-pointer hover:bg-surface-high hover:text-on-surface transition-colors;
  }
  .fd-block-sep { @apply w-px h-4 mx-1 bg-outline; }
  .fd-block-surface { @apply min-h-64 p-3 overflow-y-auto relative; } /* FD-69: relative anchors presence carets */
  .fd-block-surface--compact { @apply min-h-16; } /* FD-212: comment composers */
  .fd-block-content { @apply outline-none; }
  .fd-block-content > :first-child { @apply mt-0; }
  /* Placeholder text on the empty first line (Tiptap Placeholder extension). */
  .fd-block-content p.is-editor-empty:first-child::before {
    content: attr(data-placeholder);
    @apply text-muted float-left h-0 pointer-events-none;
  }

  /* FD-69: real-time editing presence — avatar roster, remote carets, concurrency banner. */
  .fd-presence-bar { @apply flex items-center ml-auto pl-2 pr-1; }
  .fd-presence-avatar {
    @apply inline-flex items-center justify-center w-6 h-6 rounded-full text-[10px] font-semibold
      text-white ring-2 ring-surface-low -ml-1.5 first:ml-0 select-none;
  }
  .fd-presence-banner {
    @apply hidden items-center gap-2 px-3 py-1.5 text-[12px] text-on-surface bg-surface-high border-b border-outline;
  }
  .fd-presence-banner.is-active { @apply flex; }
  .fd-presence-caret { @apply absolute z-20 w-0.5 -ml-px pointer-events-none rounded-sm; }
  .fd-presence-caret-flag {
    @apply absolute -top-4 left-0 px-1 rounded text-[9px] leading-4 text-white whitespace-nowrap select-none;
  }

  /* FD-267: CollaborationCaret remote carets (colors are injected inline per user). */
  .collaboration-carets__caret {
    border-left: 1px solid currentColor;
    border-right: 1px solid currentColor;
    margin-left: -1px;
    margin-right: -1px;
    pointer-events: none;
    position: relative;
    word-break: normal;
  }
  .collaboration-carets__label {
    @apply text-[10px] font-semibold text-white whitespace-nowrap select-none;
    border-radius: 3px 3px 3px 0;
    left: -1px;
    line-height: normal;
    padding: 0.1rem 0.3rem;
    position: absolute;
    top: -1.4em;
  }
  .collaboration-carets__selection { border-radius: 0.1em; }

  /* FD-209/FD-621: the two block-editor suggestion popups ("/" blocks and "@" people).
     Both are mounted outside the editor — on <body>, or on the enclosing <dialog> when
     one is open — so the editor's overflow container can't clip them, and both are
     `fixed` because lib/suggestion_popup positions them from a viewport-relative rect. */
  .fd-slash-menu, .fd-mention-menu {
    @apply fixed z-[60] min-w-44 max-h-72 overflow-y-auto p-1 rounded-md border border-outline
      bg-surface-low shadow-lg text-[13px];
  }
  .fd-slash-item, .fd-mention-item {
    @apply block w-full text-left px-2 py-1.5 rounded cursor-pointer text-on-surface hover:bg-surface-high;
  }
  .fd-slash-item.is-selected, .fd-mention-item.is-selected { @apply bg-surface-high; }
  .fd-slash-empty, .fd-mention-empty { @apply px-2 py-1.5 text-muted; }

  /* FD-621: "@" picker rows — avatar + full name + email, so two people sharing a first
     name are actually tellable apart. */
  .fd-mention-menu { @apply min-w-64; }
  .fd-mention-item { @apply flex items-center gap-2; }
  .fd-mention-avatar {
    @apply inline-flex shrink-0 items-center justify-center rounded-full size-5 overflow-hidden
      text-[10px] font-medium;
  }
  .fd-mention-avatar.is-initials { @apply text-white; }
  .fd-mention-avatar img { @apply size-5 rounded-full object-cover; }
  .fd-mention-name { @apply truncate; }
  .fd-mention-email { @apply ml-auto pl-2 shrink-0 text-[11px] text-muted truncate max-w-40; }

  /* FD-625: the asks table's Owner cell. Resting state is COMPACT — a matched member's avatar,
     or the raw text when the stored value resolves to nobody — which is where the table width
     FD-615's 112px input spent comes back. The picker input is revealed on demand.

     The input is absolutely positioned so revealing it cannot reflow the table: column widths
     here are decisions, not slack (FD-597's `Ask w-2/5 min-w-64`, FD-520's `Blocker / notes
     w-1/5 min-w-40`), and a cell that grew on focus would shove them around mid-edit. It is
     wider than the cell on purpose — a name needs more room to type than to display — and the
     popup itself is mounted on <body> by the shared shell, so it costs the table nothing and the
     card's overflow container cannot clip it. */
  .fd-owner-cell { @apply relative inline-block align-top; }
  /* max-w-28 is the width CEILING, and it is deliberately FD-615's exact input width (w-28). A
     table column is as wide as its widest cell, so without a cap one "Acme Vendor Co." row would
     set the whole column's floor and the avatars would buy nothing. With it, the worst case is
     never worse than what FD-615 already cost, the common case (a resolved member) is a 20px
     avatar, and nothing is lost to the truncation — the full stored value rides on the button's
     title and aria-label.

     Measured at 1440x900, 5 asks, Chrome — the Owner column and the note table's overflow:
       every owner a member       136px -> 69px   |  table 243px -> 176px
       2 of 5 free-typed          136px -> 132px  |  table 243px -> 238px
     i.e. the reclaim scales with how many owners actually resolve, which is the design: a value
     the app cannot be certain of keeps its text, and text costs what text costs. */
  .fd-owner-display {
    @apply inline-flex items-center h-8 min-w-8 max-w-28 px-1 rounded-md text-[12px] text-left
      hover:bg-surface-high focus:outline-none focus:ring-1 focus:ring-outline-strong;
  }
  /* min-w-0 is what lets the text actually truncate: a flex item's default min-width is
     auto (= its content), so `truncate` alone would silently do nothing inside the button. */
  .fd-owner-display > * { @apply min-w-0; }
  .fd-owner-input {
    @apply absolute left-0 top-0 z-20 h-8 w-56 rounded-md bg-surface-low border border-outline
      px-2 text-[12px] focus:outline-none focus:border-outline-strong;
  }
  /* Explicit, because the rule above sets no `display` and the UA's [hidden] rule is what would
     otherwise be relied on — one future `@apply block` here and every row's input would be
     permanently visible. */
  .fd-owner-input[hidden] { @apply hidden; }

  /* FD-621: a mention that the server will actually match, highlighted while composing.
     This is a ProseMirror decoration, not stored markup — it appears only in the editor,
     and only over text Mention.scan! recognises, so it reads as "this will notify". */
  .fd-block-content .fd-mention {
    @apply rounded px-0.5 font-medium text-brand bg-brand/10 underline decoration-brand/40 underline-offset-2;
  }

  /* FD-209: to-do (task) lists — styled for both the editor and the read-only render. */
  [data-type="taskList"] { @apply list-none pl-0 my-1.5; }
  [data-type="taskItem"] { @apply flex items-start gap-2; }
  [data-type="taskItem"] > label { @apply mt-1 shrink-0; }
  [data-type="taskItem"] > div { @apply flex-1; }
  [data-type="taskItem"] > div > p { @apply my-0; }

  /* FD-210: table controls — hidden until the controller flags the caret in a table. */
  .fd-block-table-ops { @apply hidden items-center; }
  .fd-block-toolbar.is-in-table .fd-block-table-ops { @apply inline-flex; }

  /* Horizontal scroll container for wide tables, emitted by MarkdownRenderer around every
     <table>. Without it a wide table (a spreadsheet or CSV import, or a wide .docx table)
     pushes past the max-w-3xl prose column and the whole content pane scrolls instead —
     carrying the page heading and toolbar off-screen, and on a published page scrolling the
     entire document on mobile. `w-full` on the table below is not in tension with this: a
     table cannot render narrower than its min-content width, so it still fills the column
     when narrow and overflows into this scroller when wide. */
  /* A visible cue that the table continues past the edge, which the scrollbar alone does not
     provide: macOS uses overlay scrollbars that occupy zero layout height until you scroll,
     and Chrome ignores ::-webkit-scrollbar sizing there — measured at a 0px track either way.
     A real 87-column import is ~7,800px inside a ~700px column, so without a cue the page is
     indistinguishable from the truncation this container exists to fix.

     The shadow is painted on the scroll container: the `local` gradients scroll with the
     content and mask the shadow at each end, so the shadow appears only on the side where
     there is more to see, and disappears when you reach that end. No JS. Body cells are
     transparent, so it shows through them; the sticky-looking header covers it only in the
     header row. */
  .fd-prose .fd-table-scroll {
    @apply overflow-x-auto max-w-full;
    /* No fallback on --color-surface: it is always defined, and a #fff fallback would paint
       a white mask over a dark surface if it ever did fire. */
    background-image:
      linear-gradient(to right, var(--color-surface) 40%, transparent),
      linear-gradient(to left, var(--color-surface) 40%, transparent),
      linear-gradient(to right, rgb(0 0 0 / 18%), transparent),
      linear-gradient(to left, rgb(0 0 0 / 18%), transparent);
    background-position: left center, right center, left center, right center;
    background-repeat: no-repeat;
    background-size: 28px 100%, 28px 100%, 12px 100%, 12px 100%;
    background-attachment: local, local, scroll, scroll;
  }

  /* Sticky horizontal scrollbar for wide tables, built by table_scroll_controller.
     The block is the sticky containing element, so the rail rides the bottom of the window
     while any part of ITS table is on screen and releases once you scroll past — rather than
     sitting at the bottom of a 131-row table, where finding it means scrolling past all the
     content you wanted to read. The block needs no positioning of its own — a sticky child's
     containing block is its parent's content box either way. */
  .fd-prose .fd-table-rail {
    @apply sticky bottom-0 z-20 h-3 mt-1 rounded-full cursor-pointer select-none touch-none
           bg-surface-high;
    box-shadow: 0 -6px 12px -8px rgb(0 0 0 / 25%);
  }
  .fd-prose .fd-table-rail[hidden] { display: none; }

  /* Not the bg-outline utility: it resolves to outline-VARIANT-default (#b6b6b5), which is
     visibly fainter than the resting thumb wants. */
  .fd-prose .fd-table-rail-thumb {
    @apply h-full rounded-full transition-colors;
    background-color: var(--sys-color-outline-default);
  }
  .fd-prose .fd-table-rail:hover .fd-table-rail-thumb,
  .fd-prose .fd-table-rail.is-dragging .fd-table-rail-thumb { @apply bg-muted; }

  /* FD-210: tables + callouts — styled for both the editor and the read-only render. */
  .fd-prose table, .fd-block-content table { @apply w-full my-3 text-[12px] border border-outline rounded-lg border-collapse; }
  .fd-prose th, .fd-block-content th { @apply text-left font-medium px-3 py-1.5 border border-outline bg-surface-low; }
  .fd-prose td, .fd-block-content td { @apply px-3 py-1.5 border border-outline align-top; }
  .fd-block-content .selectedCell { @apply bg-brand/10; } /* Tiptap cell selection */
  [data-type="callout"] {
    @apply my-2 px-3 py-2 rounded-md border-l-2 border-brand bg-surface-high/40;
  }
  [data-type="callout"] > :first-child { @apply mt-0; }
  [data-type="callout"] > :last-child { @apply mb-0; }

  /* FD-211: block-editor image/file attachments (the editor nodeView). */
  .fd-block-attachment { @apply my-2; }
  .fd-block-attachment img { @apply max-w-full rounded-md; }
  .fd-block-attachment.ProseMirror-selectednode img { @apply outline outline-2 outline-brand; }
  .fd-block-file-chip {
    @apply inline-flex items-center gap-1 px-2 py-1 rounded-md border border-outline bg-surface-high text-[12px] text-muted;
  }

  /* ============================================================
     U12 motion — subtle Plane-like transitions on interactive
     component classes (popover open/close, prop-group disclosure
     chevron, hover-reveal of row/card controls). ~150ms ease-out.
     The prefers-reduced-motion block below zeroes all of these.
     ============================================================ */

  /* Popover open/close: fade + tiny rise. The Stimulus popover controller
     toggles the `hidden` attribute, so we animate the visible (:not([hidden]))
     state and use @starting-style to give it an enter origin. */
  .fd-popover,
  .fd-slash-menu,
  .fd-mention-menu {
    transition: opacity 150ms ease-out, transform 150ms ease-out;
  }
  .fd-popover:not([hidden]),
  .fd-slash-menu,
  .fd-mention-menu {
    opacity: 1;
    transform: translateY(0);
  }
  @starting-style {
    .fd-popover:not([hidden]),
    .fd-slash-menu,
    .fd-mention-menu {
      opacity: 0;
      transform: translateY(-4px);
    }
  }

  /* Disclosure chevron in the Properties rail (Details / Project structure).
     The base class already declares transition-transform; pin its timing to
     the Plane ~150ms ease-out feel. */
  .fd-prop-group-chevron {
    transition: transform 150ms ease-out;
  }

  /* Hover-reveal of per-row / per-card controls (item rows, board cards).
     These containers carry `opacity-0 group-hover:opacity-100` in markup but
     no transition utility, so they snap; ease the fade here keyed off the
     existing class names (no view edits needed). */
  [class~="opacity-0"][class*="group-hover:opacity-100"] {
    transition: opacity 150ms ease-out;
  }

  /* Instant hover labels (see app/javascript/tooltips.js). A single reusable
     chip, positioned in JS. Inverse surface so it stays legible in both themes.
     Always present in the DOM (only opacity toggles) so JS can measure it. */
  .fd-tooltip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9999;
    max-width: 20rem;
    padding: 0.25rem 0.5rem;
    border-radius: 0.375rem;
    font-size: 0.75rem;
    line-height: 1rem;
    font-weight: 500;
    color: var(--color-surface);
    background: var(--color-on-surface);
    box-shadow: 0 4px 12px rgb(0 0 0 / 0.25);
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity 90ms ease-out, transform 90ms ease-out;
  }
  .fd-tooltip-show {
    opacity: 1;
    transform: translateY(0);
  }
}

/* FD-561: daisyUI 5's .select is built for single-select dropdowns — its
   display:inline-flex collapses a <select multiple> listbox into one overlapping
   row, and overflow:hidden swallows the scrollbar, so size=N is inert. The original
   FD-559 fix put this in @layer components, but the element carries the literal
   `select` class, so daisyUI's own .select — which compiles into a later cascade
   layer — won on layer order (which beats specificity), leaving the fix inert. It
   must live in @layer utilities to sort after daisyUI's layer. Verified against the
   compiled bundle: options stack vertically, scroll and token border/background
   preserved.

   FD-581: daisyUI also opts every .select into Chrome's customizable-select API
   (@supports (appearance:base-select) { .select { appearance: base-select } }).
   Under base-select, Chrome's UA sheet re-renders options as flex boxes — the
   option{display:flex} FD-561 blamed on daisyUI is really UA styling; daisyUI
   authors no `display` on option at all — and breaks native listbox
   click-to-select: the option renders at a sensible rect and receives the click,
   yet option.selected never flips. appearance:none opts [multiple] listboxes back
   out (single-select dropdowns keep daisyUI's base-select picker). */
@layer utilities {
  .select[multiple] {
    appearance: none; /* opt out of base-select — restores mouse selection (FD-581) */
    display: block;
    height: auto;
    overflow-y: auto;
    background-image: none; /* the single-select caret */
    padding-inline: 0.5rem; /* reclaim the space reserved for it */
  }
}

/* FD-627: a closed dropdown palette stayed invisible but fully clickable, so clicking a
   comment's body silently added an emoji reaction the user never chose.

   Same layer-order trap as FD-561 above. daisyUI's closed state
   (.dropdown:not(…) .dropdown-content { display:none }) compiles into a NESTED
   utilities.daisyui.* sublayer, while a literal `flex` utility on the element — and
   daisyUI's own .menu — sort in the TOP-LEVEL utilities layer. Rules directly in
   `utilities` sort after its nested sublayers and layer order beats specificity, so
   display:none lost and the palette never hid: it rendered at opacity:0 with
   pointer-events:auto. The comment picker is dropdown-top, so it sat directly over the
   comment body above it (measured: 169x39 of live emoji buttons covering 100% of the
   body's text line, hit-testing to a DIFFERENT emoji at each x-offset).

   display:none is the whole fix, and it must stay the ONLY declaration here. Adding
   pointer-events:none looks like a useful belt-and-braces for the 200ms window daisyUI
   spends fading a CLOSING palette out (it transitions `display` with
   transition-behavior:allow-discrete, so display:flex outlives the blur) — but
   pointer-events is NOT in that transition list, so it flips the instant focus leaves.
   WebDriver's click on an <option> inside a <select multiple> momentarily drops focus
   to the body, which un-matches :focus-within; with pointer-events:none the Filters
   menu's own listbox then becomes unclickable mid-click (FD-561/FD-581's
   filters_menu_multiselect system test fails deterministically). That 200ms grace is
   load-bearing for any control inside a dropdown that transiently blurs. It also is
   not the reported bug: a closing palette was already deliberately opened, and at
   mousedown it is legitimately open and covering that area — ordinary dropdown
   behaviour. The bug was the palette being hittable having never been opened at all.

   display:none additionally pulls the six phantom emoji buttons per comment back out
   of the tab order and the accessibility tree.

   Mirrors daisyUI's own closed-state selector (including the details exclusion, which
   keeps the <details class="dropdown"> action menus on native open/closed semantics),
   so this restores the component's intended behaviour rather than inventing new state.
   No markup changes, so FD-495's single shared form, its session-global token and
   FD-528's class-keyed wrappers are untouched. */
@layer utilities {
  .dropdown.dropdown-close .dropdown-content,
  .dropdown:not(details, .dropdown-open, .dropdown-hover:hover, :focus-within) .dropdown-content {
    display: none;
  }
}

/* Safe-area insets for installed PWA / notched devices (no-ops on desktop). */
.pt-safe { padding-top: env(safe-area-inset-top); }
.pb-safe { padding-bottom: env(safe-area-inset-bottom); }
.pl-safe { padding-left: env(safe-area-inset-left); }
.pr-safe { padding-right: env(safe-area-inset-right); }

/* Keyboard focus visibility for interactive shell controls. */
.fd-icon-btn:focus-visible,
.fd-side-link:focus-visible,
.fd-rail-btn:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: -1px;
}

/* Roomier tap targets on touch / small screens (desktop density unchanged). */
@media (max-width: 767px) {
  .fd-side-link { padding-top: 0.5rem; padding-bottom: 0.5rem; }
  .fd-icon-btn { width: 2.75rem; height: 2.75rem; }
  .fd-rail-btn { min-height: 2.75rem; justify-content: center; }
  /* Smoother momentum scrolling for horizontal surfaces (board, spreadsheet). */
  .fd-scroll-x { scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; }
}

/* Respect reduced-motion: disable the drawer slide / scrim fade transitions. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
