@import "tailwindcss";

/* Fonts: vendored and served with the app, never fetched from a third party.
   Every host loads this stylesheet, so the faces are declared once here rather
   than in each entry document. A self-hosted deployment may not be able to
   reach Google Fonts at all; a synchronous stylesheet from there used to hold
   the whole console blank until the request timed out. The bundler resolves
   these url()s into content-hashed assets next to the rest of the build, and
   `swap` means text paints in the system stack the instant the document does.
   Variable faces cover every weight the console uses (300 to 700) in one file
   each. Source: the `geist` npm package (SIL OFL, see fonts/LICENSE.txt). */
@font-face {
  font-family: "Geist";
  src: url("./fonts/geist-sans.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Geist Mono";
  src: url("./fonts/geist-mono.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@custom-variant dark (&:is(.dark *));

@source "../**/*.{ts,tsx}";
@source "../../../../apps/local/src/**/*.{ts,tsx}";
@source "../../../../apps/cloud/src/**/*.{ts,tsx}";
@source "../../../plugins/*/src/**/*.{ts,tsx}";
/* The artifact page embeds the MCP-Apps shell, so the shell's own chrome
   (loading state, trusted-approval modal) must compile into the app stylesheet.
   Classes the MODEL invents at runtime are not scannable at build time — the
   shell compiles those in-browser inside its sandboxed frame. */
@source "../../../hosts/mcp-apps-shell/src/shell/**/*.{ts,tsx}";

/* The artifact GALLERY draws stored preview markup directly in this document
   (see `artifact-preview.tsx`), so unlike the shell there is no in-browser
   Tailwind compiler to fall back on — a class the model used that this
   stylesheet lacks simply does not apply, and the preview loses the structure
   that made it worth showing.
   Most of what a preview needs is already here because the console uses it
   too. What is NOT is the wide end of the layout scales: the console is a
   settings UI and never needs a four-column stat row, while a generated
   dashboard almost always does. Inlining the grid and flex tracks is enough to
   keep a preview's SHAPE intact; the fine typography and spacing utilities are
   already compiled from console sources.
   Deliberately narrow: this is a fixed list of layout primitives, not an
   attempt to precompile everything a model might write. Anything missing
   degrades to an unstyled block inside the preview, never a broken console. */
@source inline("grid-cols-{1,2,3,4,5,6,7,8,9,10,11,12}");
@source inline("md:grid-cols-{1,2,3,4,5,6}");
@source inline("lg:grid-cols-{1,2,3,4,5,6}");
@source inline("col-span-{1,2,3,4,5,6,7,8,9,10,11,12}");
@source inline("row-span-{1,2,3,4,5,6}");
@source inline("grid-rows-{1,2,3,4,5,6}");

@theme inline {
  /* Geist sets UI and prose; Geist Mono sets code, slugs, IDs, counts, and labels.
     font-display maps to Geist too: headings are sans, the wordmark uses font-mono. */
  --font-sans: "Geist", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --font-display: "Geist", ui-sans-serif, system-ui, sans-serif;

  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);

  --color-sidebar: var(--sidebar);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-active: var(--sidebar-active);

  --radius-sm: calc(var(--radius) * 0.6);
  --radius-md: calc(var(--radius) * 0.8);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) * 1.4);
  --color-sidebar-ring: var(--sidebar-ring);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
}

/* Light theme.
   Grayscale, registry-grade minimal: white surfaces, a near-neutral gray ramp,
   hairline borders, and color held back to one role (destructive). Hierarchy
   comes from tone and borders, not hue. */
:root {
  color-scheme: light dark;
  --radius: 0.5rem;

  --background: #ffffff;
  --foreground: #111111;
  --card: #ffffff;
  --card-foreground: #111111;
  --popover: #ffffff;
  --popover-foreground: #111111;
  --primary: #0a0a0a;
  --primary-foreground: #ffffff;
  --secondary: #fafafa;
  --secondary-foreground: #0a0a0a;
  --muted: #fafafa;
  --muted-foreground: #666666;
  --accent: #f5f5f5;
  --accent-foreground: #0a0a0a;
  --destructive: #b4261a;
  --border: #eaeaea;
  --input: #d4d4d4;
  --ring: #888888;

  --sidebar: #ffffff;
  --sidebar-foreground: #666666;
  --sidebar-border: #eaeaea;
  --sidebar-active: #f5f5f5;

  --scrollbar-thumb: #d4d4d4;
  --scrollbar-thumb-hover: #999999;
  --sidebar-primary: #0a0a0a;
  --sidebar-primary-foreground: #ffffff;
  --sidebar-accent: #f5f5f5;
  --sidebar-accent-foreground: #0a0a0a;
  --sidebar-ring: #888888;
}

/* Dark theme.
   The gray ramp inverts: near-black surfaces, a white primary, hairlines at low
   contrast. Depth comes from a one-step-lighter surface, not a heavier shadow. */
@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
    --card: #0f0f0f;
    --card-foreground: #ededed;
    --popover: #141414;
    --popover-foreground: #ededed;
    --primary: #ffffff;
    --primary-foreground: #0a0a0a;
    --secondary: #141414;
    --secondary-foreground: #ededed;
    --muted: #141414;
    --muted-foreground: #9a9a9a;
    --accent: #1a1a1a;
    --accent-foreground: #ededed;
    --destructive: #e0726a;
    --border: #1f1f1f;
    --input: #333333;
    --ring: #777777;

    --sidebar: #0a0a0a;
    --sidebar-foreground: #9a9a9a;
    --sidebar-border: #1f1f1f;
    --sidebar-active: #141414;

    --scrollbar-thumb: #333333;
    --scrollbar-thumb-hover: #444444;
    --sidebar-primary: #ffffff;
    --sidebar-primary-foreground: #0a0a0a;
    --sidebar-accent: #1a1a1a;
    --sidebar-accent-foreground: #ededed;
    --sidebar-ring: #777777;
  }
}

@layer base {
  * {
    @apply border-border;
  }

  html,
  body,
  #root {
    min-height: 100%;
    height: 100%;
  }

  body {
    @apply bg-background font-sans text-foreground antialiased;
  }

  ::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }
  ::-webkit-scrollbar-track {
    background: transparent;
  }
  ::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: 3px;
  }
  ::-webkit-scrollbar-thumb:hover {
    background: var(--scrollbar-thumb-hover);
  }
}

/* The sidebar header sits at the top-left of the desktop window, under the
   native macOS traffic-light controls (trafficLightPosition {x:16,y:17} in
   apps/desktop/src/main/index.ts). Offset its content past the lights and make
   the freed strip draggable like a native title bar. The desktop window stays
   at or above the mobile breakpoint (minWidth 768), so the sidebar header is
   the only header the lights ever overlap. */
.executor-desktop-macos .desktop-macos-titlebar {
  -webkit-app-region: drag;
  padding-left: 88px;
}

.executor-desktop-macos .desktop-macos-no-drag {
  -webkit-app-region: no-drag;
}

/* The main content area sits to the right of the sidebar. On the frameless
   desktop window it renders page content straight to the top edge with nothing
   marked as a drag region, so the window could not be moved or
   double-clicked-to-zoom from there (only the sidebar header worked, see
   .desktop-macos-titlebar above). Lay a title-bar-height drag strip along the
   top of the main area so the whole top row behaves like the native title bar.
   Hidden off-desktop. It OVERLAYS the top of the main area (absolute, behind
   page content via z-index) rather than reserving its own row: reserving space
   pushed every page header down a full title-bar height, so its bottom border
   no longer lined up with the sidebar header's. Sitting behind, it keeps page
   headers flush with the top (borders aligned again) while the empty/text parts
   of the header stay draggable. Interactive controls carve themselves out of
   the drag region via the global no-drag rule below, so the strip never
   swallows their clicks. The traffic lights sit over the sidebar, never the
   main area, so no left offset is needed here. */
.desktop-macos-main-titlebar {
  display: none;
}

.executor-desktop-macos .desktop-macos-main-titlebar {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3rem; /* matches the sidebar header (h-12) */
  z-index: -1; /* behind page content so header controls stay clickable */
  -webkit-app-region: drag;
}

/* Safety net for the overlaid main drag strip: any interactive control that
   ends up within the top title-bar strip must carve itself out of the drag
   region, or the native window-drag would steal its clicks. Mirrors the
   explicit .desktop-macos-no-drag the sidebar header uses on its controls. */
.executor-desktop-macos button,
.executor-desktop-macos a,
.executor-desktop-macos input,
.executor-desktop-macos select,
.executor-desktop-macos textarea,
.executor-desktop-macos [role="button"],
.executor-desktop-macos [role="tab"] {
  -webkit-app-region: no-drag;
}

/* The 88px title-bar offset eats into the sidebar's width; without extra room
   the brand wordmark and the server-connection menu collide. Widen the macOS
   sidebar so both clear the traffic lights with comfortable spacing. */
.executor-desktop-macos .desktop-macos-sidebar {
  width: 15rem;
}

.dark {
  --background: #0a0a0a;
  --foreground: #ededed;
  --card: #0f0f0f;
  --card-foreground: #ededed;
  --popover: #141414;
  --popover-foreground: #ededed;
  --primary: #ffffff;
  --primary-foreground: #0a0a0a;
  --secondary: #141414;
  --secondary-foreground: #ededed;
  --muted: #141414;
  --muted-foreground: #9a9a9a;
  --accent: #1a1a1a;
  --accent-foreground: #ededed;
  --destructive: #e0726a;
  --border: #1f1f1f;
  --input: #333333;
  --ring: #777777;

  --sidebar: #0a0a0a;
  --sidebar-foreground: #9a9a9a;
  --sidebar-primary: #ffffff;
  --sidebar-primary-foreground: #0a0a0a;
  --sidebar-accent: #1a1a1a;
  --sidebar-accent-foreground: #ededed;
  --sidebar-border: #1f1f1f;
  --sidebar-active: #141414;
  --sidebar-ring: #777777;
  --scrollbar-thumb: #333333;
  --scrollbar-thumb-hover: #444444;
}

@keyframes ios-spinner-fade {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0.25;
  }
}

/* ---------------------------------------------------------------------------
 * Reduced motion — WCAG 2.2 (motion-sensitive users).
 *
 * Neutralizes transitions/animations/scroll-behavior when the OS requests
 * reduced motion, per the standard modern-CSS-reset pattern. The spinner
 * (ios-spinner-fade) is capped to a single 0.01ms iteration — effectively
 * static — which is the standard behavior: its meaning is preserved by
 * `role="status"` (announced by assistive tech), and an opacity pulse would
 * be a non-motion affordance but is not required for reduced-motion users.
 * ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
