@tailwind base;
@tailwind components;
@tailwind utilities;

/*
 * Savant theme tokens.
 *
 * :root holds the canonical DARK palette (Monaco editorial, 2026-06 redesign).
 * Each decimal RGB triple equals the original hex exactly, so dark mode renders
 * byte-for-byte as before — e.g. --c-ink-950: 5 5 6 == #050506.
 *
 * html.light overrides the neutral (ink), border (line), text (fg) and status
 * scales with the editorial light palette: warm paper-white canvas, near-black
 * text. The ink scale inverts role (950 = lightest page surface, 600 = darkest
 * raised surface) so existing `bg-ink-950`/`bg-ink-900` usage stays correct.
 *
 * Brand tokens (accent, magenta, prop) are theme-independent and live as hex in
 * tailwind.config.js. The channel-triple form preserves opacity modifiers.
 */
:root {
  /* surfaces (ink): deepest -> most raised */
  --c-ink-950: 5 5 6;
  --c-ink-900: 11 11 14;
  --c-ink-850: 16 16 20;
  --c-ink-800: 23 23 28;
  --c-ink-700: 33 33 41;
  --c-ink-600: 44 44 54;
  /* borders (line) */
  --c-line: 35 35 42;
  --c-line-strong: 52 52 62;
  --c-line-faint: 25 25 32;
  /* text (fg) */
  --c-fg: 244 244 242;
  --c-fg-muted: 155 155 153;
  --c-fg-faint: 97 97 99;
  /* status */
  --c-ok: 84 216 155;
  --c-warn: 255 178 112;
  --c-err: 229 72 77;
}

html.light {
  /* surfaces invert: 950 = lightest page canvas -> 600 = darkest raised surface */
  --c-ink-950: 252 252 251;
  --c-ink-900: 246 246 244;
  --c-ink-850: 240 240 237;
  --c-ink-800: 233 233 229;
  --c-ink-700: 224 224 219;
  --c-ink-600: 214 214 208;
  /* borders */
  --c-line: 228 228 223;
  --c-line-strong: 207 207 200;
  --c-line-faint: 240 240 237;
  /* text inverts: near-black primary -> light tertiary */
  --c-fg: 26 26 31;
  --c-fg-muted: 106 106 102;
  --c-fg-faint: 154 154 149;
  /* status deepened for contrast on white */
  --c-ok: 31 157 107;
  --c-warn: 178 106 26;
  --c-err: 206 44 49;
}

/* TipTap Editor */
.tiptap-editor .ProseMirror {
  @apply min-h-[400px] outline-none;
}

/* Email drafts: mail clients render the normalized body as margin-free <div>
   lines, so the email editor must space paragraphs the same way — one line
   each, blank lines only where the draft has them. */
.tiptap-editor--email .ProseMirror p {
  margin: 0;
}

/* A seeded blank line is a paragraph holding one hard break; ProseMirror
   appends its own trailing cursor break after it, which would render the
   blank line double-height. Hide the padding break unless it is the
   paragraph's only content (an empty paragraph still needs its one line). */
.tiptap-editor--email .ProseMirror p > br.ProseMirror-trailingBreak:not(:first-child) {
  display: none;
}

.tiptap-editor .ProseMirror p.is-editor-empty:first-child::before {
  @apply text-neutral-400 dark:text-neutral-500 float-left pointer-events-none h-0;
  content: attr(data-placeholder);
}

/* Merge tag chips */
.merge-tag,
.tiptap-editor .ProseMirror span[data-type="mention"] {
  @apply inline-flex items-center rounded-md bg-teal-100 px-1.5 py-0.5 text-xs font-medium text-teal-700 dark:bg-teal-900/30 dark:text-teal-300;
}

/* Brand Color Reference
 * Primary (Teal): #00ADA7 - Use primary-{50-950} classes
 * Secondary (Gold): #FFBE38 - Use secondary-{50-950} classes
 * Semantic colors also available: success-*, warning-*, danger-*
 * Neutral colors remain available from Tailwind defaults
 */

/* Start Rails Blocks Custom Styles */
kbd {
  @apply rounded-md border border-black/10 bg-white px-1 font-mono text-[11px] text-neutral-800 shadow-[0px_1.5px_0px_0px_rgba(0,0,0,0.05)] dark:border-white/10 dark:bg-neutral-900 dark:text-neutral-200 dark:shadow-[0px_1px_0px_0px_rgba(255,255,255,0.1)];
}

/* Forms */

label,
.label {
  @apply text-sm leading-6 font-medium text-neutral-700;
  @apply dark:text-neutral-100;
}

.form-input[disabled] {
  @apply cursor-not-allowed bg-neutral-200;
}

/* non-input elements (like the Stripe card form) can be styled to look like an input */
div.form-control {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: #fff;
  border-width: 1px;
  padding-top: 0.5rem;
  padding-right: 0.75rem;
  padding-bottom: 0.5rem;
  padding-left: 0.75rem;
  font-size: 1rem;
  line-height: 1.5rem;
}

.form-control {
  /* Alias of console-input: one input style everywhere; legacy call sites keep the class name. */
  @apply block w-full rounded border border-line bg-ink-850 px-2.5 py-1.5 text-[13px] leading-5 text-fg shadow-none ring-0 placeholder:text-fg-faint outline-none focus:border-accent-500 focus:ring-1 focus:ring-accent-500;
}

@media (min-width: 640px) {
  .form-control {
    font-size: 0.875rem; /* text-sm equivalent (14px) for larger screens */
  }
}

.form-control[disabled] {
  @apply cursor-not-allowed bg-neutral-100 dark:bg-neutral-600;
}

.form-control.error {
  @apply border-red-400 ring-red-300 focus:ring-red-500 dark:border-red-600 dark:ring-red-500;
}

:where(select:not([multiple])) {
  @apply w-full appearance-none rounded-lg border-0 bg-white px-3 py-2 text-base leading-6 text-neutral-900 shadow-sm ring-1 ring-neutral-300 outline-none ring-inset focus:ring-2 focus:ring-neutral-600;

  /* Custom dropdown arrow */
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23737373' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
  background-position: right 0.75rem center;
  background-repeat: no-repeat;
  background-size: 1.25em 1.25em;
  padding-right: 2.5rem;
}

@media (min-width: 640px) {
  :where(select:not([multiple])) {
    font-size: 0.875rem; /* text-sm equivalent (14px) for larger screens */
  }
}

/* Dark mode styling for single select */
:where(.dark) :where(select:not([multiple])) {
  @apply dark:bg-neutral-700 dark:text-white dark:ring-neutral-600 dark:focus:ring-neutral-500;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23A1A1AA' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
}

:where(select:not([multiple])[disabled]) {
  @apply cursor-not-allowed bg-neutral-100 opacity-75 ring-neutral-200 dark:bg-neutral-600 dark:ring-neutral-500;
}

select[multiple] {
  @apply w-full rounded-lg rounded-r-none border-0 bg-white px-3 py-2.5 text-base leading-6 text-neutral-900 shadow-sm outline-1 -outline-offset-1 outline-neutral-300 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-neutral-600 dark:outline-neutral-600;
  min-height: 120px;
}

select[multiple] option {
  @apply rounded-md;
}

@media (min-width: 640px) {
  select[multiple] {
    font-size: 0.875rem; /* text-sm equivalent (14px) for larger screens */
  }
}

/* Dark mode styling for multiple select */
.dark {
  select[multiple] {
    @apply dark:bg-neutral-700 dark:text-white dark:ring-neutral-600 dark:focus:ring-neutral-500;
  }
}

select[multiple][disabled] {
  @apply cursor-not-allowed bg-neutral-100 opacity-75 ring-neutral-200 dark:bg-neutral-600 dark:ring-neutral-500;
}

option {
  @apply bg-white px-3 py-2 text-sm text-neutral-900;
}

option:checked {
  @apply bg-neutral-200 text-neutral-950;
}

option:hover {
  @apply bg-neutral-100 text-neutral-950;
}

.caret {
  @apply pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-neutral-800;
}

[type="checkbox"] {
  @apply size-4 cursor-pointer appearance-none rounded-sm border border-neutral-300 bg-white checked:border-neutral-700 checked:bg-neutral-700 focus:outline-2 focus:outline-offset-2 focus:outline-neutral-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 disabled:border-neutral-300 disabled:bg-neutral-100 disabled:checked:bg-neutral-100 dark:border-white/20 dark:bg-neutral-800 dark:checked:border-white/20 dark:checked:bg-neutral-900 dark:focus:outline-neutral-200 dark:focus-visible:outline-neutral-200 dark:disabled:border-neutral-500 dark:disabled:bg-neutral-400 dark:disabled:checked:bg-neutral-500 forced-colors:appearance-auto;
}

[type="checkbox"]:checked {
  @apply text-white dark:text-neutral-800;
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
}

[type="checkbox"]:indeterminate {
  @apply border-neutral-400 bg-neutral-500 dark:border-white/20 dark:bg-neutral-700;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3e%3cg fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' %3e%3cline x1='10.75' y1='6' x2='1.25' y2='6'%3e%3c/line%3e%3c/g%3e%3c/svg%3e");
  background-size: 75% 75%;
  background-position: center;
  background-repeat: no-repeat;
}

[type="checkbox"]:disabled {
  @apply cursor-not-allowed border-neutral-300 bg-neutral-300 text-neutral-400 opacity-75 hover:text-neutral-300 dark:border-neutral-600 dark:bg-neutral-700 dark:text-neutral-300 dark:hover:text-neutral-500;
}

[type="checkbox"]:disabled:checked {
  @apply border-neutral-300 dark:border-neutral-600 dark:bg-neutral-600;
}

[type="radio"] {
  @apply size-4 cursor-pointer appearance-none rounded-full border border-neutral-300 bg-white checked:border-neutral-700 checked:bg-neutral-700 focus:outline-2 focus:outline-offset-2 focus:outline-neutral-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 disabled:border-neutral-300 disabled:bg-neutral-100 disabled:checked:bg-neutral-100 dark:border-white/20 dark:bg-neutral-800 dark:checked:border-white/20 dark:checked:bg-neutral-900 dark:focus:outline-neutral-200 dark:focus-visible:outline-neutral-200 dark:disabled:border-neutral-500 dark:disabled:bg-neutral-400 dark:disabled:checked:bg-neutral-500 forced-colors:appearance-auto;
}

[type="radio"]:checked {
  @apply text-white dark:text-neutral-800;
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
}

[type="radio"]:disabled {
  @apply cursor-not-allowed border-neutral-300 bg-neutral-300 text-neutral-400 opacity-75 hover:text-neutral-300 dark:border-neutral-600 dark:bg-neutral-700 dark:text-neutral-300 dark:hover:text-neutral-500;
}

[type="radio"]:disabled:checked {
  @apply border-neutral-300 dark:border-neutral-600 dark:bg-neutral-600;
}

/* Datalist styling */
input[list] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

/* Replace default datalist arrow in WebKit browsers */
input[list].replace-default-datalist-arrow::-webkit-calendar-picker-indicator {
  display: none !important;
  -webkit-appearance: none !important;
}

input[list].replace-default-datalist-arrow {
  padding-right: 2.5rem;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23737373' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
  background-position: right 0.75rem center;
  background-repeat: no-repeat;
  background-size: 1.25em 1.25em;
}

/* Dark mode datalist arrow */
.dark {
  input[list].replace-default-datalist-arrow {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23A1A1AA' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
  }
}

/* Dialog */

/* Hide dialogs by default to prevent flash of open state */
dialog:not([open]) {
  display: none !important;
}

/* Firefox has a bug with backdrop, so we can use a box-shadow instead */
dialog.modal {
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.5);
}

dialog.slideover {
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.5);
}

dialog.max-w-full {
  box-shadow: none;
}

dialog::backdrop {
  background: none;
}

/* Modal animations */
dialog.modal:not(.max-w-full)[open] {
  animation: fadeIn 200ms forwards, scaleIn 200ms forwards;
}

dialog.modal:not(.max-w-full)[closing] {
  animation: fadeOut 200ms forwards, scaleOut 200ms forwards;
}

/* Fullscreen modal animations - fade only */
dialog.modal.max-w-full[open] {
  animation: fadeIn 200ms forwards;
}

dialog.modal.max-w-full[closing] {
  animation: fadeOut 200ms forwards;
}

/* Center modals */
dialog.modal {
  margin: auto;
  position: fixed;
  inset: 0;
  align-items: center;
  justify-content: center;
}

/* Slideover animations */
dialog.slideover[open] {
  animation: fadeIn 200ms forwards ease-in-out, slide-in-from-right 200ms forwards ease-in-out;
}

dialog.slideover[closing] {
  pointer-events: none;
  animation: fadeOut 200ms forwards ease-in-out, slide-out-to-right 200ms forwards ease-in-out;
}

/* Slideover animations for top */
dialog.slideover-top[open] {
  animation: fadeIn 200ms forwards ease-in-out, slide-in-from-top 200ms forwards ease-in-out;
}

dialog.slideover-top[closing] {
  animation: fadeOut 200ms forwards ease-in-out, slide-out-to-top 200ms forwards ease-in-out;
}

/* Slideover animations for bottom */
dialog.slideover-bottom[open] {
  animation: fadeIn 200ms forwards ease-in-out, slide-in-from-bottom 200ms forwards ease-in-out;
}

dialog.slideover-bottom[closing] {
  animation: fadeOut 200ms forwards ease-in-out, slide-out-to-bottom 200ms forwards ease-in-out;
}

/* Slideover animations for left */
dialog.slideover-left[open] {
  animation: fadeIn 200ms forwards ease-in-out, slide-in-from-left 200ms forwards ease-in-out;
}

dialog.slideover-left[closing] {
  animation: fadeOut 200ms forwards ease-in-out, slide-out-to-left 200ms forwards ease-in-out;
}

/* Slideover animations for right */
dialog.slideover-right[open] {
  animation: fadeIn 200ms forwards ease-in-out, slide-in-from-right 200ms forwards ease-in-out;
}

dialog.slideover-right[closing] {
  animation: fadeOut 200ms forwards ease-in-out, slide-out-to-right 200ms forwards ease-in-out;
}

body {
  scrollbar-gutter: stable;
  overflow-y: scroll;
}

/* Prevent scrolling while dialog is open */
body:has(dialog.modal[open]) {
  overflow: hidden;
}

body:has(dialog.slideover[open]) {
  overflow: hidden;
}

/* Scrollbar compensation for fixed elements */
:root {
  --scrollbar-compensation: 0px;
}

/* Apply compensation to body when a modal or slideover is open */
body.modal-open,
body.slideover-open {
  padding-right: var(--scrollbar-compensation);
}

/* Apply compensation to fixed elements */
body.modal-open .fixed,
body.slideover-open .fixed {
  padding-right: var(--scrollbar-compensation);
}

/* Exclude slideover dialogs from scrollbar compensation */
body.slideover-open [data-slideover-target="dialog"] {
  padding-right: 0 !important;
}

dialog.modal {
  cursor: auto;
}

/* Div-based modals */
.modal-div {
  cursor: auto;
}

.modal-div.modal-open {
  display: flex !important;
}

/* Div modal animations - fade in and scale in content */
.modal-div.modal-visible {
  opacity: 1;
}

.modal-div.modal-visible > div {
  transform: scale(1);
}

.modal-div:not(.modal-visible) {
  opacity: 0;
}

.modal-div:not(.modal-visible) > div {
  transform: scale(0.95);
}

/* Prevent scrolling while div modal is open */
body:has(.modal-div.modal-open) {
  overflow: hidden;
}

/* Keyframes for fade animations */
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* Keyframes for new animations */
@keyframes slide-in-from-top {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes slide-out-to-top {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-100%);
  }
}

@keyframes slide-in-from-bottom {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes slide-out-to-bottom {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(100%);
  }
}

@keyframes slide-in-from-left {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slide-out-to-left {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100%);
  }
}

@keyframes slide-in-from-right {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slide-out-to-right {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(100%);
  }
}

/* Add new keyframes for scale animations */
@keyframes scaleIn {
  from {
    transform: scale(0.95);
  }
  to {
    transform: scale(1);
  }
}

@keyframes scaleOut {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(0.95);
  }
}

/* Add specific box-shadow handling for slideover directions */
dialog.slideover-top,
dialog.slideover-bottom {
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.6);
}

/* Scrollbar */

.small-scrollbar {
  scrollbar-width: thin;
  scrollbar-color: #a2a2a270 #7878780b;
}

.small-scrollbar::-webkit-scrollbar {
  width: 6px;
}

.small-scrollbar::-webkit-scrollbar-track {
  background: #7878780b;
}

.small-scrollbar::-webkit-scrollbar-thumb {
  background-color: #a2a2a270;
  border-radius: 3px;
}

/* Cursor pointer for buttons */

@layer base {
  button:not(:disabled),
  [role="button"]:not(:disabled) {
    cursor: pointer;
  }
}

/* Toast Notifications */
.toast-item {
  @apply absolute w-full left-0 select-none;
  z-index: var(--toast-z-index, 100);

  /* Position based on data attributes */
  top: var(--toast-top, auto);
  bottom: var(--toast-bottom, auto);
  transform: var(--toast-transform, translateY(0));
  scale: var(--toast-scale, 100%);
  opacity: var(--toast-opacity, 1);

  /* Separate transitions for better control - like Sonner */
  transition: transform 400ms ease, opacity 400ms ease, scale 400ms ease, top 400ms ease, bottom 400ms ease,
    height 200ms ease;
}

/* Initial hidden state for enter animation */
.toast-item[data-mounted="false"] {
  opacity: 0;
}

.toast-item[data-mounted="false"][data-position*="bottom"] {
  transform: translateY(100%);
}

.toast-item[data-mounted="false"][data-position*="top"] {
  transform: translateY(-100%);
}

/* Removed state for exit animation */
.toast-item[data-removed="true"] {
  opacity: 0;
  scale: 95%;
  pointer-events: none;
}

/* In stacked mode, removed toasts should slide away */
.toast-item[data-removed="true"][data-expanded="false"][data-position*="bottom"] {
  transform: translateY(calc(var(--toast-index) * 14px + 5%));
}

.toast-item[data-removed="true"][data-expanded="false"][data-position*="top"] {
  transform: translateY(calc(-1 * (var(--toast-index) * 14px + 5%)));
}

/* Overflow toasts (removed due to limit) slide in opposite direction */
.toast-item[data-removed="true"][data-overflow="true"][data-expanded="false"][data-position*="bottom"] {
  transform: translateY(calc(-1 * (var(--toast-index) * 14px + 25%)));
  scale: 78%;
}

.toast-item[data-removed="true"][data-overflow="true"][data-expanded="false"][data-position*="top"] {
  transform: translateY(calc(var(--toast-index) * 14px + 25%));
  scale: 78%;
}

/* Pointer events based on visibility */
.toast-item[data-visible="false"] {
  pointer-events: none;
}

/* Expanded mode styles */
.toast-item[data-expanded="true"] {
  --toast-scale: 100%;
  height: var(--initial-height);
}

.toast-item[data-expanded="true"][data-position*="bottom"] {
  --toast-top: auto;
  --toast-bottom: var(--toast-offset, 0px);
  --toast-transform: translateY(0);
}

.toast-item[data-expanded="true"][data-position*="top"] {
  --toast-top: var(--toast-offset, 0px);
  --toast-bottom: auto;
  --toast-transform: translateY(0);
}

/* Stacked mode styles */
.toast-item[data-expanded="false"][data-front="true"] {
  --toast-scale: 100%;
  --toast-opacity: 1;
  height: var(--initial-height);
}

.toast-item[data-expanded="false"][data-front="true"][data-position*="bottom"] {
  --toast-top: auto;
  --toast-bottom: 0px;
  --toast-transform: translateY(0);
}

.toast-item[data-expanded="false"][data-front="true"][data-position*="top"] {
  --toast-top: 0px;
  --toast-bottom: auto;
  --toast-transform: translateY(0);
}

/* Non-front toasts in stack - Sonner approach */
.toast-item[data-expanded="false"]:not([data-front="true"]) {
  height: var(--front-toast-height);
  overflow: hidden;
  --toast-scale: calc(100% - (var(--toast-index) * 6%));
  display: flex;
  flex-direction: column;
}

.toast-item[data-expanded="false"]:not([data-front="true"])[data-position*="bottom"] {
  --toast-top: auto;
  --toast-bottom: 0px;
  --toast-transform: translateY(calc(-1 * var(--toast-index) * 14px));
  justify-content: flex-start; /* Content at top, bottom gets cut */
}

.toast-item[data-expanded="false"]:not([data-front="true"])[data-position*="top"] {
  --toast-top: 0px;
  --toast-bottom: auto;
  --toast-transform: translateY(calc(var(--toast-index) * 14px));
  justify-content: flex-end; /* Content at bottom, top gets cut */
}

/* Hidden toasts (beyond 3rd) */
.toast-item[data-expanded="false"][data-visible="false"] {
  --toast-opacity: 0;
  --toast-scale: 82%;
}

.toast-item[data-expanded="false"][data-visible="false"][data-position*="bottom"] {
  --toast-top: auto;
  --toast-bottom: -200px;
  --toast-transform: translateY(0);
}

.toast-item[data-expanded="false"][data-visible="false"][data-position*="top"] {
  --toast-top: -200px;
  --toast-bottom: auto;
  --toast-transform: translateY(0);
}

/* Kanban Sortable Styles */
.sortable-fallback {
  opacity: 0.8;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}

.sortable-ghost {
  opacity: 0.4;
}

.sortable-chosen {
  @apply ring-2 ring-primary-500;
}

.kanban-card {
  touch-action: auto;
  user-select: none;
  -webkit-user-select: none;
}

.kanban-card.sortable-chosen,
.kanban-card.sortable-ghost {
  touch-action: none;
}

/* Tasks board drawdown + layout modes (board_layout_controller.js).
   "stack" distributes columns into vertical stacks that fit the screen —
   one stack per row on phones — so a drawn-down column lets everything
   beneath it shift up like a dynamic list; "row" keeps the classic single
   scrolling row. A collapsed column hides its cards: in stack mode it
   becomes a one-line header bar, in row mode a slim vertical rail. */
.kanban-board[data-layout="stack"] {
  overflow-x: visible;
}
.kanban-board[data-layout="stack"] .kanban-lanes {
  min-width: 0;
  align-items: flex-start;
}
.kanban-stack {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.kanban-board[data-layout="stack"] .kanban-column {
  width: auto;
}
.kanban-column[data-collapsed="true"] .kanban-cards,
.kanban-column[data-collapsed="true"] .kanban-colnote {
  display: none;
}
.kanban-column[data-collapsed="true"] .kanban-colhead {
  border-bottom-width: 0;
}
.kanban-column[data-collapsed="true"] .kanban-collapse-icon {
  transform: rotate(-90deg);
}
.kanban-board[data-layout="row"] .kanban-column[data-collapsed="true"] {
  width: 2.75rem;
  min-height: 11rem;
}
.kanban-board[data-layout="row"] .kanban-column[data-collapsed="true"] .kanban-colhead {
  height: 100%;
  flex-direction: column;
  padding: 0.625rem 0.25rem;
  gap: 0.5rem;
}
.kanban-board[data-layout="row"] .kanban-column[data-collapsed="true"] .kanban-colhead h3 {
  writing-mode: vertical-rl;
  max-height: 7rem;
}
.kanban-board[data-layout="row"] .kanban-column[data-collapsed="true"] .kanban-colcount {
  margin-left: 0;
  margin-top: auto;
}
.kanban-board[data-layout="row"] .kanban-column[data-collapsed="true"] .kanban-collapse-icon {
  transform: rotate(90deg);
}

/* End Rails Blocks Custom Styles */

/* ============================================================
   Savant design system (Palantir aesthetic)
   Canonical source: mockups/_shell-template.html
   Tokens live in tailwind.config.js (ink/line/fg/accent/ok/warn/err/prop).
   ============================================================ */

/* Self-hosted fonts (app/assets/fonts, served by Propshaft) */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/inter-latin-400-1e94a563.woff2") format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/inter-latin-500-5949f5fc.woff2") format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/inter-latin-600-a957bd0d.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-latin-400-d803141a.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-latin-500-3f7bbac1.woff2") format('woff2');
}
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/newsreader-latin-400-a1bd2648.woff2") format('woff2');
}
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/newsreader-latin-500-9ca2106a.woff2") format('woff2');
}
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/newsreader-latin-600-b16b95ed.woff2") format('woff2');
}

body {
  font-feature-settings: 'cv11', 'ss01', 'tnum';
}

@layer components {
  .microlabel { @apply text-[10.5px] font-medium uppercase tracking-[0.08em] text-fg-muted; }
  /* Named type scale — new views use these instead of raw text-[Npx] */
  .t-title { @apply text-[15px] font-medium text-fg; }
  .t-body  { @apply text-[13px] text-fg leading-[1.5]; }
  .t-meta  { @apply text-[11.5px] text-fg-muted; }
  .t-mono  { @apply font-mono text-[11.5px] tabular-nums; }
  .panel { @apply bg-ink-900 border border-line rounded-lg; }
  /* Monaco editorial layer (2026-06-18 redesign) */
  .eyebrow { @apply text-[11px] tracking-[0.04em] text-fg-faint; }
  .display { @apply font-serif font-normal tracking-[-0.02em] text-fg; }
  .pill { @apply inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-[11.5px] font-medium; }
  .pill-grad { @apply text-white; background-image: linear-gradient(95deg, #8161FF, #C766E8); }
  .pill-green { @apply text-ok; background-color: rgba(84, 216, 155, 0.14); }
  .pill-amber { @apply text-warn; background-color: rgba(255, 178, 112, 0.15); }
  .pill-neutral { @apply text-fg-muted bg-ink-800; }
  .btn-white { @apply inline-flex items-center justify-center gap-1.5 rounded-full bg-white px-3.5 py-1.5 text-[13px] font-medium text-ink-950 hover:bg-fg transition-colors; }
  .btn-ghost { @apply inline-flex items-center justify-center gap-1.5 rounded-full border border-line-strong px-3.5 py-1.5 text-[13px] font-medium text-fg hover:bg-ink-800 transition-colors; }
  .ask-bar { @apply flex items-center gap-3 rounded-2xl border border-line-strong bg-white/[0.035] px-4 py-3.5; }
  .ask-send { @apply flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-white text-ink-950; }
  /* Light mode only: the dark ask bar leans on a faint white veil + a white send
     button (white icon-on-white would vanish on the light canvas). Re-skin for
     light here; the two dark rules above are left untouched. In light, bg-fg is
     near-black and text-ink-950 (from .ask-send) is near-white -> a crisp dark
     send button with a light arrow. */
  html.light .ask-bar { @apply bg-ink-900; }
  html.light .ask-send { @apply bg-fg; }
  .glass { @apply border border-line bg-ink-850/70 backdrop-blur-xl; }
  .icon-tile { @apply flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-line text-fg; }
  .panel-header { @apply flex items-center justify-between px-3 h-9 border-b border-line; }
  .console-btn { @apply inline-flex items-center gap-1.5 h-7 px-2.5 rounded text-[12px] font-medium border border-line text-fg hover:bg-ink-800 transition-colors duration-100; }
  .console-btn-primary { @apply border-accent-600 bg-accent-500 text-white hover:bg-accent-400; }
  .console-btn-danger { @apply border-err/40 text-err hover:bg-err/10; }
  .board-mode-active { @apply border-accent-500 !text-fg bg-ink-800; }
  .status-dot { @apply inline-block w-1.5 h-1.5 rounded-[1px] shrink-0; }
  .id-chip { @apply font-mono text-[11px] text-fg-muted bg-ink-800 border border-line-faint px-1 py-px rounded-sm; }
  .sidebar-section { @apply space-y-1; }
  .sidebar-section-toggle { @apply flex h-7 w-full items-center justify-between rounded px-2.5 text-left text-[10.5px] font-medium uppercase tracking-[0.08em] text-fg-muted hover:bg-ink-800 hover:text-fg transition-colors duration-100; }
  .sidebar-section-chevron { @apply h-3 w-3 shrink-0 text-fg-faint transition-transform duration-100; }
  .sidebar-section[data-sidebar-section-collapsed="true"] .sidebar-section-chevron { transform: rotate(-90deg); }
  .nav-item { @apply flex items-center gap-2.5 h-8 px-2.5 rounded text-[13px] text-fg-muted hover:bg-ink-800 hover:text-fg transition-colors duration-100; }
  .nav-item-active { @apply bg-ink-700 text-fg relative; }
  .nav-item-active::before { content: ''; @apply absolute left-0 top-1 bottom-1 w-[2px] bg-accent-400 rounded-r; }
  .console-kbd { @apply font-mono text-[10px] text-fg-muted bg-ink-800 border border-line rounded-sm px-1 py-px; }
  .console-input { @apply block w-full rounded border border-line bg-ink-850 px-2.5 py-1.5 text-[13px] leading-5 text-fg shadow-none ring-0 placeholder:text-fg-faint outline-none focus:border-accent-500 focus:ring-1 focus:ring-accent-500; }
  /* Safe areas (notched iPhones, standalone PWA): the shell draws under the
     status bar (viewport-fit=cover + black-translucent), so every surface
     pinned to a screen edge must pad by the matching inset. env() is 0 in
     desktop browsers, so these are no-ops outside phones. */
  /* NOTE: keep the env() padding in .safe-top only — combined with px-3's
     padding-left/right in one rule, the CSS minifier merges padding-* and
     silently drops the env() declaration (verified against the compiled
     bundle 2026-07-03). Markup composes .app-topbar with .safe-top. */
  .app-topbar { @apply shrink-0 bg-ink-850 border-b border-line flex items-center gap-3 px-3; min-height: 3rem; }
  .safe-top { padding-top: env(safe-area-inset-top, 0px); }
  .mobile-bottom-nav { @apply fixed inset-x-0 bottom-0 z-40 border-t border-line bg-ink-900/95 shadow-[0_-12px_30px_rgba(0,0,0,0.28)] backdrop-blur; padding-bottom: env(safe-area-inset-bottom); padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px); }
  .mobile-bottom-nav-grid { @apply grid h-16 items-stretch px-1.5; }
  .mobile-bottom-nav-item { @apply relative flex min-w-0 flex-col items-center justify-center gap-0.5 rounded text-fg-muted no-underline transition-colors duration-100 hover:bg-ink-800 hover:text-fg; }
  .mobile-bottom-nav-item-active { @apply text-accent-300; }
  .mobile-bottom-nav-item-active::before { content: ''; @apply absolute left-3 right-3 top-1 h-[2px] rounded-full bg-accent-400; }
  .mobile-bottom-nav-label { @apply block max-w-full truncate px-0.5 text-[10.5px] font-medium leading-none; }
  .as-drawer { transform: translateX(100%); }
  .as-backdrop { opacity: 0; }
  .ask-open .as-drawer { transform: translateX(0); }
  .ask-open .as-backdrop { opacity: 1; }
  .mobile-bottom-nav-badge { @apply absolute -right-2 -top-1 min-w-4 rounded-sm border border-accent-500/50 bg-accent-500 px-1 text-center font-mono text-[9px] leading-4 text-white; }
}

@media (max-width: 767px) {
  .app-main {
    padding-bottom: calc(5rem + env(safe-area-inset-bottom));
  }

  html[data-display-mode="standalone"] body {
    overscroll-behavior-y: none;
  }

  /* Keep the pull gesture inside the app's scroll pane so the standalone
     shell never rubber-bands the whole viewport while pulling to refresh. */
  html[data-display-mode="standalone"] .app-main {
    overscroll-behavior-y: contain;
  }
}

/* Native select dropdowns: without an explicit color-scheme the OS renders
   the option list light-on-light and unreadable against the dark UI. These
   rules are dark-theme-scoped so light mode gets native light chrome. */
html.dark select.console-input,
html.dark .console-input select,
html.dark select {
  color-scheme: dark;
}
html.dark select option {
  background-color: #10141B;
  color: #E6EAF2;
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
.pulse { animation: pulse-dot 2s ease-in-out infinite; }

/* ---------------------------------------------------------------------------
   iPad / tablet touch optimization (added 2026-06-16)

   Scope is deliberately narrow: `pointer: coarse` matches finger-driven
   touch devices, and `min-width: 768px` limits this to iPad-sized screens
   and up. As a result:
     - Desktop with a mouse/trackpad (pointer: fine) is COMPLETELY untouched.
     - Phones (< 768px, which already have their own mobile drawer view)
       are untouched.
   Only iPads in the desktop shell get larger tap targets. The layout itself
   is unchanged — we only grow the height of small interactive controls
   toward Apple's ~44px finger-friendly guideline. We rely on min-height,
   which clamps any smaller `height` (incl. Tailwind's `!h-6`/`!h-7`
   utilities) up to the minimum without needing !important.
--------------------------------------------------------------------------- */
/* Tap feedback polish (all touch surfaces): kill the default gray tap flash
   and the 300ms double-tap-zoom delay on controls; the hover/active classes
   the components already carry become the visible feedback. */
a, button, [role="button"], input[type="submit"], label, summary {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* ---------------------------------------------------------------------------
   Phone touch optimization (< 768px, coarse pointer) — the phone-side
   sibling of the iPad block below (2026-07-03). Same min-height clamp idea
   at Apple's 44px line, plus the iOS-specific form rule: text controls
   below 16px make Safari force-zoom the page on focus, which is the #1
   "the app jumped around while I typed" complaint on the task review
   screen's draft editor.
--------------------------------------------------------------------------- */
@media (pointer: coarse) and (max-width: 767px) {
  .console-btn,
  button:not([data-compact]),
  input[type="submit"] {
    min-height: 44px;
  }

  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="hidden"]):not([type="file"]),
  select,
  textarea,
  .console-input {
    min-height: 44px;
    font-size: max(16px, 1rem);
  }

  .nav-item {
    min-height: 44px;
  }

  /* The task review approve/skip bar sticks to the bottom of the scroll
     pane, but the fixed bottom nav (4rem + safe area) overlays that edge on
     phones, hiding the primary action on long cards. Lift it clear. */
  .task-action-bar {
    bottom: calc(4rem + env(safe-area-inset-bottom, 0px));
  }
}

@media (pointer: coarse) and (min-width: 768px) {
  /* Console buttons (search, ADD, etc.) and the compact filter pills that
     force a 24/28px height via !h-6 / !h-7. */
  .console-btn {
    min-height: 40px;
  }

  /* Primary form controls: quick-add task field, status select, search, and
     any shared console inputs. Match all text-like inputs (incl. type-less
     and submit/button) by excluding the non-text input types, so we don't
     depend on an explicit type="text" attribute being present. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="hidden"]):not([type="file"]),
  select,
  textarea,
  .console-input {
    min-height: 40px;
  }

  button {
    min-height: 40px;
  }

  /* Sidebar / drawer navigation rows. */
  .nav-item {
    min-height: 44px;
  }

  /* Icon-only buttons in the top shell (search, menu, close). */
  header button,
  [data-sidebar-target="mobilePanel"] button {
    min-height: 40px;
    min-width: 40px;
  }
}
