@font-face {
  font-family: "Pretendard Variable";
  font-weight: 45 920;
  font-style: normal;
  font-display: swap;
  src: url("/fonts/pretendard/PretendardVariable.woff2") format("woff2-variations");
}

:root {
  color-scheme: light;
  /*
   * One editable viewport frame for every route. Future fixed side panels use
   * the same inset as their split gap instead of introducing page-local math.
   */
  --app-viewport-inset: 5px;
  --app-viewport-radius: 5px;
  --app-content-inset: 20px;
  --app-viewport-height: calc(100dvh - var(--app-viewport-inset) - var(--app-viewport-inset));
  /* Figma 1734:3986 — fixed workspace rail and the split before it. */
  --canvas-workspace-panel-width: 440px;
  --canvas-workspace-panel-gap: var(--app-viewport-inset);
  --canvas-workspace-panel-reserved: calc(
    var(--canvas-workspace-panel-width) + var(--canvas-workspace-panel-gap)
  );
  --canvas-workspace-panel-center-offset: 222.5px;
  --canvas-workspace-panel-padding-block: 27px;
  --canvas-workspace-panel-padding-inline: 19px;
  --canvas-workspace-panel-content-gap: 20px;
  --canvas-workspace-panel-portrait-height: min(56%, 620px);
  --color-red: #c32a2a;
  --color-red-strong: #a42626;
  /*
   * Hairline on a solid --color-red surface, the way --color-black-line is the
   * hairline on --color-black. Distinct from --color-red-line (#d32828), which
   * edges the frosted nav pills and reads lighter than its surface.
   */
  --color-red-line-strong: #b03030;
  --color-red-dark-1: #ba2a2a;
  --color-black: #181818;
  --color-black-soft: #2c2c2c;
  --color-black-muted: #353535;
  --color-black-line: #3c3c3c;
  --color-black-strong: #000000;
  --color-black-dim: rgb(24 24 24 / 50%);
  --color-black-faint: rgb(24 24 24 / 25%);
  /* Shared page fade behind modal and full-window popup surfaces. */
  --color-popup-backdrop: rgb(24 24 24 / 20%);
  --color-white: #ffffff;
  --color-white-subtle: #f5f5f5;
  --color-white-subtle-dim: rgb(245 245 245 / 50%);
  --color-white-soft: #f9f9f9;
  --color-white-muted: #f3f3f3;
  --color-white-dim: #e5e5e5;
  /*
   * The light chrome surfaces introduced with the redesigned canvas bar
   * (Figma 1504:2190 / 1476:1936) — a white that is a shade off #fff so the
   * card still reads as a card against a white artboard.
   */
  --color-white-bright: #fdfdfd;
  /*
   * The raised hover state for dark send controls, one step up from
   * --color-black (Figma 1917:3524).
   */
  --color-black-raised: #282828;
  --color-presence-online: #0fbc5f;
  --color-remote-cursor-stroke: #e5e5e5;
  --color-remote-cursor-label-text: #f5f5f5;

  --color-bg: #f5f5f2;
  --color-surface-subtle: #ecece7;
  --color-ink: #171714;
  --color-ink-muted: #68685f;
  --color-border: #d8d8d0;
  --color-border-strong: #b9baae;
  --color-accent: #225c4f;
  --color-accent-strong: #153c34;
  --color-accent-soft: #dbece6;
  --color-warning: #9d5b16;
  --color-warning-soft: #f6e1c5;
  --color-danger: #a63737;
  --color-danger-soft: #f3d7d7;
  --color-info: #325f8f;
  --color-info-soft: #dce8f5;
  --shadow-panel: 0 18px 48px rgb(32 32 25 / 10%);
  --shadow-window: 0 4px 50px 25px rgb(0 0 0 / 15%);
  --shadow-pop: 0 1px 25px 0 rgb(0 0 0 / 15%);
  --shadow-cursor-status: 0 1px 25px 0 rgb(0 0 0 / 10%);
  --shadow-presence-avatar: 0 1px 25px 0 rgb(0 0 0 / 10%);
  --shadow-remote-cursor-marker: drop-shadow(0 1px 25px rgb(0 0 0 / 10%));
  --shadow-menu: 0 1px 25px 0 rgb(0 0 0 / 10%);
  --shadow-menu-item-active: 0 1px 12.5px 0 rgb(0 0 0 / 10%);
  /*
   * Figma's "drop-weak" effect style (#0000000D, offset 0, radius 10, spread 0)
   * — the barely-there lift under a selected settings row and the small action
   * buttons beside it, always paired with a --color-white-dim hairline.
   */
  --shadow-drop-weak: 0 0 10px 0 rgb(0 0 0 / 5%);
  /*
   * Figma's "drop-bg-blur" effect style — a background blur paired with
   * #00000013 dropped 1px at radius 25. It is the lift under every frosted
   * surface the newer frames draw: the home nav's controls (1330:397), the
   * workspace menu (1298:2788), the project tile's roster (1320:241).
   */
  --shadow-drop-bg-blur: 0 1px 25px 0 rgb(0 0 0 / 8%);
  /*
   * Figma's "drop-button-hover" effect style — the inner shadow a flat nav
   * control takes on once the pointer is over it (1352:451, 1352:465,
   * 1352:478). Inner, so it reads as the surface pressing in rather than the
   * control lifting off the page.
   */
  --shadow-button-hover: inset 0 1px 5px 0 rgb(0 0 0 / 10%);
  /* The panel itself: Figma settings-account (974:1545) drops it 4px, not 1px. */
  --shadow-page: 0 4px 25px 0 rgb(0 0 0 / 15%);

  /*
   * Figma's `drop-weak` effect style — a centred 10px bloom at 5%. It is the
   * lift under the home nav's controls (1261:1265), which sit on white and so
   * want a far lighter touch than --shadow-menu gives the canvas chrome.
   */
  --shadow-drop-weak: 0 0 10px 0 rgb(0 0 0 / 5%);

  /*
   * The frosted surface every floating control is cut from — the canvas nav and
   * its dropdowns, and the home nav's own controls (Figma 1231:2354 / 2356 /
   * 2361 and the menu at 1229:2208). Declared once here; --color-white-dim is
   * the 1px stroke around it and --shadow-menu the lift under it.
   *
   * Nearly opaque rather than the half wash it was: chrome laid over a canvas
   * full of photographs has to be read, and at 50% every control took on
   * whatever happened to be behind it. The blur stays — it is what keeps the
   * surface reading as glass rather than as a flat plate — but it now sits on
   * a fill that its text can be trusted against.
   */
  --surface-frosted: rgb(245 245 245 / 95%);
  /*
   * The same glass at the two weights the newer frames draw it: 75% under a
   * control that has to be read at a glance (the home nav's pills and workspace
   * trigger, Figma 1330:397 / 1330:401), half under the panel one of those
   * opens (the workspace menu at 1298:2788, the project tile's roster at
   * 1320:241). Both float over the page's own white, so the lighter wash still
   * reads — --color-white-dim is the 1px stroke around them and
   * --shadow-drop-bg-blur the lift under them.
   */
  --surface-frosted-control: rgb(245 245 245 / 75%);
  --surface-frosted-panel: rgb(245 245 245 / 50%);
  /*
   * Interactive menu states from Figma `menu/item` (1637:446). Keep tone
   * (neutral/danger) independent from state so Canvas, popovers and future
   * module menus can share the same behavior without duplicating selectors.
   */
  --surface-menu-canvas: rgb(245 245 245 / 80%);
  --color-menu-item-neutral-hover: var(--color-black-muted);
  --color-menu-item-neutral-pressed: var(--color-black-raised);
  --color-menu-item-danger-hover: var(--color-red);
  --color-menu-item-danger-pressed: var(--color-red-dark-1);
  --color-menu-item-active-foreground: var(--color-white-subtle);
  --opacity-menu-item-disabled: 0.5;
  --shadow-menu-item-state: var(--shadow-drop-weak);
  --duration-menu-item-state: 150ms;
  --ease-menu-item-state: ease;
  /*
   * Every transient popup appears in place. Menus, popovers, alerts and modal
   * cards share this opacity-only cadence; no direction, scale or bounce is
   * encoded in the popup itself. Keep the numeric Motion values in
   * usePopupFadeMotion.ts in sync with these CSS durations.
   */
  --duration-popup-enter: 160ms;
  --duration-popup-exit: 120ms;
  --duration-popup-enter-reduced: 100ms;
  --duration-popup-exit-reduced: 80ms;
  --ease-popup: cubic-bezier(0.23, 1, 0.32, 1);
  /*
   * Compact primary action states (Figma button 1674:1733 / 1735 / 1737).
   * Keeping the paint separate from a button's geometry lets dialogs reuse the
   * same Default -> Hover -> Pressed behavior without changing their layout.
   */
  --surface-button-primary-default: var(--color-white-subtle);
  --border-button-primary-default: var(--color-white-dim);
  --foreground-button-primary-default: var(--color-black);
  --surface-button-primary-hover: var(--color-green);
  --border-button-primary-hover: var(--color-green-line);
  --foreground-button-primary-hover: var(--color-white-subtle);
  --surface-button-primary-pressed: var(--color-green-line);
  --border-button-primary-pressed: var(--color-green-line);
  --foreground-button-primary-pressed: var(--color-white-subtle);
  /* Validation-invalid actions keep the requested red fill in both states. */
  --surface-button-invalid-hover: var(--color-red);
  --border-button-invalid-hover: var(--color-red-line-strong);
  --foreground-button-invalid-hover: var(--color-white-subtle);
  --surface-button-invalid-pressed: var(--color-red);
  --border-button-invalid-pressed: var(--color-red-line-strong);
  --foreground-button-invalid-pressed: var(--color-white-subtle);
  --opacity-button-primary-disabled: 0.5;
  --duration-button-primary-state: 120ms;
  --ease-button-primary-state: ease;
  --surface-frosted-blur: 10px;
  --text-shadow-adaptive: 0 0 3px rgb(245 245 245 / 95%), 0 0 9px rgb(245 245 245 / 75%);
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-menu: 15px;
  --radius-menu-item: 10px;
  --radius-menu-item-active: 7.5px;
  --radius-pill: 50px;
  --input-slot-width: 410px;
  --input-slot-height: 45px;
  --input-slot-radius: 10px;
  --input-slot-bg: #f3f3f3;
  --input-slot-font-size: 14px;
  --input-slot-x-padding: 10px;
  /*
   * Figma 1304:86 is scaled from its 21.5032px source canvas to a 20px cursor.
   * Its source tip at approximately (2.29, 1.89) lands at (2.13, 1.76), so the
   * cross-browser integer hotspot is (2, 2). Keep the SVG in Vite's asset graph
   * so deployments fingerprint size or artwork changes instead of reusing an
   * immutable public URL. The native cursor remains the load-failure fallback.
   */
  --cursor-default: url("/assets/default-cursor-CISp--46.svg") 2 2, default;
  --cursor-popup-gap: 8px;
  /* The 20px cursor reaches 2px before and 18px after its hotspot. */
  --cursor-default-visible-inline-start: 2px;
  --cursor-default-visible-inline-end: 18px;
  --cursor-crosshair-visible-inline-radius: 16px;
  --cursor-status-blur: 12.5px;
  --canvas-presence-avatar-size: 34px;
  --canvas-presence-remote-step: 20px;
  --canvas-presence-self-x-one-remote: 44px;
  --canvas-presence-self-x-two-remotes: 64px;
  --canvas-presence-self-x-three-remotes: 84px;
  --canvas-presence-width-one-remote: 78px;
  --canvas-presence-width-two-remotes: 98px;
  --canvas-presence-width-three-remotes: 118px;
  --canvas-presence-avatar-ring-width: 1px;
  --canvas-presence-avatar-font-size: 11px;
  --canvas-presence-online-dot-size: 10px;
  --canvas-presence-online-dot-border-width: 2px;
  --canvas-remote-cursor-marker-size: 15px;
  --canvas-remote-cursor-label-gap: 8px;
  --canvas-remote-cursor-label-height: 19px;
  --canvas-remote-cursor-label-padding-block: 2.5px;
  --canvas-remote-cursor-label-padding-inline: 7.5px;
  --canvas-remote-cursor-label-radius: 10px;
  --canvas-remote-cursor-letter-spacing: 0;
  /* Shared with canvasPositionInterpolation.ts for all realtime motion. */
  --canvas-position-interpolation-duration: 80ms;

  --canvas-comment-pin-size: 50px;
  --canvas-comment-pin-padding: 4px;
  /*
   * The 10px that separates a comment's parts side by side: the pin from the
   * card beside it, an entry's avatar from its text, and the reply field from
   * its send button (Figma 1182:854, 1182:863, 1182:869 — all 10).
   */
  --canvas-comment-card-gap: 10px;
  /*
   * The thread's vertical rhythm, which is not the same number. Figma 1182:857
   * stacks its rows on a flat 15 — entry, entry, reply field — so the card and
   * its message list both space on this, and the field takes the full 15 like
   * any other row rather than being pulled up under the last entry.
   */
  --canvas-comment-thread-gap: 15px;
  --canvas-comment-card-radius: 20px;
  --canvas-comment-thread-width: 350px;
  /*
   * How tall a thread's messages get before they scroll. Sized to show roughly
   * four entries, which keeps the whole bubble — messages plus the composer
   * pinned under them — well inside a laptop viewport.
   */
  --canvas-comment-thread-messages-max-height: 280px;
  /*
   * How far the messages dissolve into the card at a scrolled end. Kept in sync
   * with MESSAGES_FADE in CanvasCommentLayer.tsx, which drives it from the
   * scroll position. Deeper than a line of text so the cut never lands on one
   * crisp half-row, shallower than an entry so a whole message is never lost.
   */
  --canvas-comment-thread-messages-fade: 28px;
  /* Kept in sync with COMMENT_VIEWPORT_MARGIN in canvasCommentGeometry.ts. */
  --canvas-comment-viewport-margin: 10px;
  --canvas-comment-field-width: 250px;
  --canvas-comment-entry-avatar-size: 35px;
  --canvas-comment-send-size: 32px;
  --canvas-comment-border-width: 1px;
  --canvas-comment-blur: 10px;
  --canvas-comment-letter-spacing: -0.15px;
  /*
   * The card reads as a near-solid sheet of the canvas chrome's own off-white
   * (--color-white-subtle) rather than a half-transparent pane of white: a
   * thread has to stay readable over whatever artwork it is pinned to.
   */
  --canvas-comment-surface: rgb(245 245 245 / 95%);
  --canvas-comment-send-bg: var(--color-black-raised);
  --shadow-canvas-comment: 0 1px 25px 0 rgb(0 0 0 / 10%);
  /* The same shadow pushed further out, for a pin held above the canvas. */
  --shadow-canvas-comment-lifted: 0 6px 30px 0 rgb(0 0 0 / 18%);
  --shadow-canvas-comment-avatar: inset 0 1px 5px 0 rgb(0 0 0 / 5%);
  --shadow-canvas-comment-field: 0 2px 25px 0 rgb(0 0 0 / 5%);

  /*
   * The name-prompt dialog (Figma 1192:1287 "folder-extend", 1211:1802
   * "new-project" — one frosted card reused verbatim for folders and projects),
   * which shares its blur and surfaces with the folder card on the canvas.
   */
  --dialog-blur: 10px;
  --dialog-surface: rgb(245 245 245 / 95%);
  --dialog-field-surface: rgb(255 255 255 / 95%);

  /* Folders (Figma 1192:1176 / 1181 / 1207). */
  --canvas-folder-blur: 10px;
  --canvas-folder-card-surface: rgb(229 229 229 / 75%);
  --canvas-folder-card-border: #c5c5c5;
  /*
   * World-space geometry of the card and the photo it hides behind itself.
   * The design's box is also the smallest a card may be: a folder resizes like
   * a window, and a card grown past this carries its own box, overriding these
   * for its own subtree (see CanvasFolderLayer).
   */
  --canvas-folder-card-width: 300px;
  --canvas-folder-card-height: 200px;
  --canvas-folder-card-radius: 10px;
  --canvas-folder-photo-width: 280px;
  --canvas-folder-photo-height: 210px;
  --canvas-folder-photo-radius: 5px;
  /* Gap between the name tag and whatever it labels (Figma 1209:1798). */
  --canvas-folder-head-gap: 8px;
  /* Collapsed, only this much of the photo shows above the card... */
  --canvas-folder-photo-peek: 20px;
  /* ...and hovering lifts it by this much to reveal the whole frame. */
  --canvas-folder-photo-lift: 160px;
  /* On-screen reach of the resize grips along the card's edges. */
  --canvas-folder-handle-size: 10px;

  /*
   * Module header action row (Figma 1223:2139). One size and one gap for every
   * icon in it, so pin, eye, download and trash sit on an even rhythm — the
   * field tag uses the same pair.
   */
  --module-header-action-size: 17px;
  --module-header-action-gap: 7.5px;

  /* Fields — named regions of a canvas page (Figma 1218:1896 / 1219:2088). */
  /* The tag row, measured off the design: 18px tall, 10px clear of the box. */
  --canvas-field-tag-height: 18px;
  --canvas-field-tag-gap: 10px;
  /* Eye and trash are the module header's own icons; see the pair above. */
  /*
   * Grab band along each edge. Wider than the 2px stroke so an edge can be
   * caught without pixel-hunting, and no wider than a module's own margin so
   * it does not sit over what it surrounds.
   */
  --canvas-field-handle-size: 10px;
  /* Swatch row in the Change color submenu (Figma 1219:2028). */
  --canvas-field-swatch-size: 25px;

  /*
   * Bottom interaction bar (Figma 1504:2190 "main-bar"). A light card carrying
   * the prompt over the tool row, where the dark frosted strip used to be.
   *
   * A tool that is held — its panel open, the field tool armed, or simply the
   * pointer over it — says so with a 12px rule under its icon and nothing
   * else. No box is drawn and the 30px slot never changes, so picking a tool
   * up cannot reflow the bar under the pointer reaching for it.
   */
  /*
   * The editing overlay's wash. The blur is the 25 the design asks for; the
   * tint over it is what stops a light canvas from reading as merely smeared.
   */
  --canvas-edit-overlay-blur: 25px;
  --canvas-edit-overlay-wash: rgb(245 245 245 / 55%);

  /*
   * The bar is frosted rather than solid: Figma draws a flat #fdfdfd card, but
   * over a busy canvas — and over the editing overlay's own wash — a sheet of
   * glass sits on the page where a flat fill sits in front of it. Kept near
   * opaque so the 15px prompt text never has artwork reading through it.
   */
  --canvas-bar-surface: color-mix(in srgb, var(--color-white-bright) 88%, transparent);
  --canvas-bar-blur: 25px;

  --canvas-bar-icon-size: 20px;
  --canvas-bar-icon-color: var(--color-black);
  --canvas-bar-button-size: 30px;
  /*
   * Figma 1509:2443 "Vector 22" — M9 28H21, a round-capped 1.5px stroke. The
   * path is a zero-height line, so the drawn band straddles y=28 and lands
   * 1.25px off the bottom of the 30px button, not 2px.
   */
  --canvas-bar-underline-width: 12px;
  --canvas-bar-underline-height: 1.5px;
  --canvas-bar-underline-inset: 1.25px;

  /*
   * Canvas nav bar (Figma 1183:939 and the controls hanging off it). Every
   * control on the bar — status pills, active users, zoom, share, and each
   * dropdown they open — is cut from one frosted surface, so the surface,
   * blur and control height live here instead of in five stylesheets.
   *
   * Reused rather than redeclared: --color-red is already the pill red,
   * --shadow-menu the 0 1px 25px/10% lift, --shadow-menu-item-active the row
   * shadow, and --radius-menu-item / --radius-menu-item-active the corners.
   *
   * The bar is 40 tall (1183:939), and every measurement on it is taken from
   * that: the 28px status pills sit at y=6 and the breadcrumb's 18px line at
   * y=11, which is what centring each of them on this height produces. The
   * four buttons at the far end — pin, active-users, zoom, share (1320:212
   * through 1320:215) — fill it outright.
   */
  --canvas-nav-inset: var(--app-content-inset);
  --canvas-nav-gap: 7.5px;
  --canvas-nav-surface: var(--surface-frosted);
  --canvas-nav-blur: var(--surface-frosted-blur);
  --canvas-nav-control-height: 40px;
  --canvas-nav-border-width: 1px;

  /* Status pills: red while work is outstanding, green once it lands. */
  --canvas-nav-pill-height: 28px;
  --canvas-nav-pill-gap: 5px;
  --canvas-nav-pill-dot-size: 6px;
  --canvas-nav-pill-count-size: 16px;
  --canvas-nav-pill-count-font-size: 10px;
  --color-red-line: #d32828;
  /* Lighter than --color-red-line: the hairline on the flat --color-red
     destructive buttons (Figma 974:1573), not on a frosted pill. */
  --color-red-line-soft: #e33131;
  --color-green: #03b15c;
  --color-green-line: #00ab58;
  --surface-agent-activity: #247a43;
  --border-agent-activity: color-mix(
    in srgb,
    var(--surface-agent-activity) 78%,
    var(--color-black)
  );
  /* Figma 1736:4335 — the translucent surface behind a Generate task tag. */
  --color-green-task-surface: rgb(0 171 88 / 15%);
  --color-red-task-surface: rgb(195 42 42 / 20%);
  /* The dot and the count badge are the label colour at half strength. */
  --canvas-nav-pill-veil: rgb(245 245 245 / 50%);

  /* The job/user dropdowns a nav control opens. */
  --canvas-nav-menu-width: 280px;
  --canvas-nav-menu-gap: 5px;
  --canvas-nav-menu-row-height: 34px;
  --canvas-nav-zoom-menu-width: 200px;
  /*
   * The zoom readout's slot. Figma 1320:213 draws the percentage in a 33px text
   * frame inside a 91px button (10 + 15 + 5 + 33 + 5 + 15 + 8), which is what
   * holds the button still: the number runs 5%..200%, so a slot that shrank to
   * fit would resize the button on every zoom step and shove the whole right
   * end of the bar sideways.
   */
  --canvas-nav-zoom-value-width: 33px;

  /* Stacked presence avatars on the bar, and the larger ones in its dropdown. */
  --canvas-nav-avatar-size: 24px;
  --canvas-nav-avatar-overlap: 8px;
  --canvas-nav-user-avatar-size: 35px;
  --shadow-canvas-nav-avatar: 0 1px 25px 0 rgb(0 0 0 / 20%);

  /* Share modal (Figma 1191:902), centred over the canvas. */
  --canvas-share-width: 500px;
  --canvas-share-field-surface: rgb(255 255 255 / 50%);
  --canvas-share-field-border: #f5f5f5;

  --font-sans:
    "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto,
    "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic",
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;
  --font-size-sm: 12px;
  /*
   * Figma's `midtext` style — Pretendard Regular 13 on -1% tracking, so -0.13px
   * — which the canvas nav's four buttons are cut from (nodes 1320:212 through
   * 1320:215).
   *
   * A step between --font-size-sm and --font-size-md, and named after the Figma
   * style rather than after its place in the ladder: `sm`/`md`/`lg` had no room
   * left for a fourth size, and a reader who finds `midtext` in the file should
   * find the same word here. It does read close to `md` — `mid` is this 13px,
   * `md` is the app's 14px base — so the two are worth checking before reaching
   * for either.
   */
  --font-size-mid: 13px;
  /* The app's base size, set on `body` in global.css so unstyled text lands
     here rather than falling through to the browser's 16px default. */
  --font-size-md: 14px;
  /*
   * One step above the base, and the only type in the app that takes it: the
   * SANTA wordmark, which Figma 1261:1266 draws at 15px SemiBold against the
   * 14px Regular of the controls beside it. Named rather than restated inline
   * so it reads as a decision instead of a leftover of the old 15px default.
   */
  --font-size-lg: 15px;
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --letter-spacing-tight: -0.01em;

  --ease-fluid: cubic-bezier(0.32, 0.72, 0, 1);
  /*
   * A critically damped spring, sampled — the shape SwiftUI's
   * `spring(duration: 0.37, bounce: 0)` draws, which is what Apple reaches for
   * when something opens and has to look settled rather than sprung. Most of
   * the travel is over in the first third and the rest is a long, quiet
   * approach; a cubic-bezier cannot hold that tail without overshooting.
   *
   * No bounce on purpose: overshoot on a panel of text reads as a toy.
   * Pair it with a 450ms duration, which is where this sampling ends.
   */
  --ease-spring-smooth: linear(
    0,
    0.0409,
    0.1336,
    0.2469,
    0.3629,
    0.4717,
    0.5687,
    0.6523,
    0.7226,
    0.7807,
    0.828,
    0.8661,
    0.8965,
    0.9206,
    0.9395,
    0.9544,
    0.9659,
    0.9749,
    0.9818,
    0.9871,
    0.9912,
    0.9944,
    0.9968,
    0.9986,
    1
  );
}
* {
  box-sizing: border-box;
}

html {
  min-width: 320px;
  background: var(--color-bg);
}

body {
  min-height: var(--app-viewport-height);
  margin: var(--app-viewport-inset);
  color: var(--color-ink);
  cursor: var(--cursor-default);
  background: var(--color-bg);
  font-family: var(--font-sans);
  /*
   * The app's base size. Without it, anything not explicitly sized inherited the
   * browser's 16px default — larger than either step of the scale, so "default"
   * was 16px by omission rather than by decision.
   */
  font-size: var(--font-size-md);
  user-select: none;
  -webkit-user-select: none;
}

button,
textarea {
  font: inherit;
}

:focus {
  outline: none;
}

input,
textarea,
[contenteditable="true"] {
  user-select: text;
  -webkit-user-select: text;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  display: block;
  max-width: 100%;
}

h1,
h2,
h3,
p {
  margin: 0;
}

#root {
  min-height: var(--app-viewport-height);
  border-radius: var(--app-viewport-radius);
}

/*
 * Astryx renders Selector, DropdownMenu, Popover and Tooltip surfaces through
 * the native Popover API. Its placement-aware default animation translates
 * and scales the top-layer wrapper; SANTA's popup language is deliberately
 * non-directional, so the wrapper stays in place and only its opacity changes.
 * The discrete display/overlay transitions keep the fade-out visible before
 * the browser removes the popover from the top layer.
 */
[popover] {
  opacity: 0 !important;
  animation-name: none !important;
  transition:
    opacity var(--duration-popup-exit) var(--ease-popup),
    display var(--duration-popup-exit) allow-discrete,
    overlay var(--duration-popup-exit) allow-discrete !important;
}

[popover]:popover-open {
  opacity: 1 !important;
  transition-duration:
    var(--duration-popup-enter), var(--duration-popup-enter), var(--duration-popup-enter) !important;
}

@starting-style {
  [popover]:popover-open {
    opacity: 0 !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  [popover] {
    transition-duration:
      var(--duration-popup-exit-reduced), var(--duration-popup-exit-reduced),
      var(--duration-popup-exit-reduced) !important;
  }

  [popover]:popover-open {
    transition-duration:
      var(--duration-popup-enter-reduced), var(--duration-popup-enter-reduced),
      var(--duration-popup-enter-reduced) !important;
  }
}

.app-page {
  width: min(1180px, calc(100% - 32px));
  margin: 0 auto;
  padding: 28px 0 48px;
}

.eyebrow {
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: uppercase;
}

.error-text {
  color: var(--color-danger);
  font-weight: 650;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  font-weight: 700;
  gap: 8px;
  line-height: 1;
  white-space: nowrap;
}

.button {
  padding: 0 14px;
}

.button:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.button-primary {
  color: #ffffff;
  background: var(--color-accent);
}

.button-primary:hover:not(:disabled) {
  background: var(--color-accent-strong);
}

.button-secondary {
  color: var(--color-ink);
  background: var(--color-white);
  border-color: var(--color-border);
}

.button-secondary:hover:not(:disabled),
.button-ghost:hover:not(:disabled) {
  border-color: var(--color-border-strong);
  background: var(--color-surface-subtle);
}

.button-ghost {
  color: var(--color-ink);
  background: transparent;
  border-color: transparent;
}

.button-icon {
  display: inline-flex;
  flex: 0 0 auto;
}

.status-badge {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  border-radius: 999px;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
}

.status-active,
.status-succeeded {
  color: var(--color-accent-strong);
  background: var(--color-accent-soft);
}

.status-draft,
.status-idle,
.status-queued {
  color: var(--color-info);
  background: var(--color-info-soft);
}

.status-running {
  color: var(--color-warning);
  background: var(--color-warning-soft);
}

.status-archived,
.status-failed {
  color: var(--color-danger);
  background: var(--color-danger-soft);
}

.workspace-page {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr) 360px;
  min-height: var(--app-viewport-height);
  overflow: clip;
  border-radius: var(--app-viewport-radius);
}

.workspace-sidebar,
.prompt-panel {
  position: sticky;
  top: 0;
  height: var(--app-viewport-height);
  min-height: 620px;
  border-color: var(--color-border);
  background: var(--color-white);
}

.workspace-sidebar {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 20px;
  border-inline-end: 1px solid var(--color-border);
}

.workspace-title {
  display: grid;
  gap: 10px;
}

.workspace-title h1 {
  font-size: 22px;
  line-height: 1.15;
}

.workspace-nav {
  display: grid;
  gap: 6px;
}

.workspace-nav a {
  display: flex;
  align-items: center;
  min-height: 38px;
  border-radius: var(--radius-md);
  padding: 0 10px;
  color: var(--color-ink-muted);
  font-weight: 700;
  gap: 10px;
}

.workspace-nav a:hover {
  background: var(--color-surface-subtle);
  color: var(--color-ink);
}

.workspace-main {
  min-width: 0;
  padding: 20px;
}

.workspace-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 58px;
  margin-bottom: 16px;
}

.workspace-header h2 {
  margin-top: 4px;
  font-size: 22px;
}

.workspace-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  color: var(--color-ink-muted);
  font-size: 13px;
  font-weight: 800;
}

.workspace-meta > span:not(.status-badge) {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 0 9px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-white);
}

.workspace-board {
  display: grid;
  grid-template-rows: minmax(420px, calc(100vh - 272px)) 112px;
  gap: 12px;
  min-height: 544px;
}

.board-stage {
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #24251f;
}

.board-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.selection-box {
  position: absolute;
  border: 2px solid #ffffff;
  background: rgb(34 92 79 / 18%);
  box-shadow: 0 0 0 1px rgb(34 92 79 / 80%);
}

.selection-box span {
  position: absolute;
  top: -30px;
  inset-inline-start: -2px;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  border-radius: 999px;
  padding: 0 9px;
  color: #ffffff;
  background: var(--color-accent);
  font-size: 12px;
  font-weight: 800;
  white-space: nowrap;
}

.image-rail {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  min-height: 112px;
}

.image-tile,
.candidate-card,
.reference-item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-white);
  cursor: pointer;
  text-align: start;
}

.image-tile {
  overflow: hidden;
  display: grid;
  grid-template-columns: 112px 1fr;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 8px;
  color: var(--color-ink);
  font-weight: 800;
}

.image-tile img {
  width: 96px;
  height: 72px;
  border-radius: var(--radius-sm);
  object-fit: cover;
}

.image-tile span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.image-tile-active,
.candidate-active,
.reference-selected {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px rgb(34 92 79 / 18%);
}

.candidate-strip {
  margin-top: 18px;
}

.section-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.section-heading h2,
.section-heading h3 {
  font-size: 16px;
}

.section-heading span {
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 800;
}

.candidate-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.candidate-card {
  overflow: hidden;
  min-width: 0;
  padding: 0;
}

.candidate-card img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.candidate-card div {
  display: grid;
  gap: 8px;
  padding: 10px;
}

.candidate-card p {
  display: -webkit-box;
  overflow: hidden;
  min-height: 38px;
  color: var(--color-ink-muted);
  font-size: 13px;
  line-height: 1.45;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.prompt-panel {
  overflow-y: auto;
  padding: 20px;
  border-inline-start: 1px solid var(--color-border);
}

.panel-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 22px;
}

.panel-header h2 {
  margin-top: 4px;
  font-size: 22px;
}

.field-label {
  display: block;
  margin-bottom: 8px;
  color: var(--color-ink-muted);
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
}

.prompt-textarea {
  width: 100%;
  min-height: 132px;
  resize: vertical;
  border: none;
  border-radius: var(--input-slot-radius);
  padding: 10px var(--input-slot-x-padding);
  color: var(--color-black);
  background: var(--input-slot-bg);
  font-size: var(--input-slot-font-size);
  font-weight: var(--font-weight-regular);
  letter-spacing: 0;
  line-height: normal;
}

.prompt-textarea::placeholder {
  color: inherit;
  opacity: 0.5;
}

.prompt-textarea:focus-visible {
  outline: 2px solid var(--color-black-faint);
  outline-offset: -2px;
}

.selection-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 34px;
  margin: 12px 0 22px;
}

.selection-tag {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  border-radius: 999px;
  padding: 0 10px;
  color: #ffffff;
  background: var(--color-accent);
  font-size: 12px;
  font-weight: 800;
}

.reference-stack {
  display: grid;
  gap: 10px;
}

.reference-item {
  display: grid;
  grid-template-columns: 72px 1fr;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 76px;
  padding: 8px;
}

.reference-item img {
  width: 72px;
  height: 58px;
  border-radius: var(--radius-sm);
  object-fit: cover;
}

.reference-item span {
  display: grid;
  min-width: 0;
  gap: 4px;
}

.reference-item small {
  overflow: hidden;
  color: var(--color-ink-muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.generate-button {
  width: 100%;
  margin-top: 18px;
}

.workspace-loading,
.board-empty {
  display: grid;
  place-items: center;
  min-height: var(--app-viewport-height);
  color: var(--color-ink-muted);
  font-weight: 800;
}

@media (max-width: 1120px) {
  .workspace-page {
    grid-template-columns: 200px minmax(0, 1fr);
  }

  .prompt-panel {
    position: static;
    grid-column: 1 / -1;
    height: auto;
    min-height: 0;
    border-top: 1px solid var(--color-border);
    border-inline-start: 0;
  }
}

@media (max-width: 820px) {
  .app-page {
    width: min(100% - 20px, 1180px);
    padding-top: 16px;
  }

  .workspace-header {
    align-items: stretch;
    grid-template-columns: 1fr;
    flex-direction: column;
  }

  .workspace-page {
    display: block;
  }

  .workspace-sidebar {
    position: static;
    height: auto;
    min-height: 0;
    border-inline-end: 0;
    border-bottom: 1px solid var(--color-border);
  }

  .workspace-board {
    grid-template-rows: minmax(300px, 56vh) auto;
  }

  .image-rail,
  .candidate-list {
    grid-template-columns: 1fr;
  }

  .image-tile {
    grid-template-columns: 96px 1fr;
  }
}
.alert-viewport {
  pointer-events: none;
  position: fixed;
  /* --shadow-pop blurs 25px above the pill, so leave room for the shadow itself. */
  top: 50px;
  inset-inline: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.alert-item {
  pointer-events: auto;
  max-width: min(560px, calc(100vw - 40px));
  padding: 15px 30px;
  border: 1.5px solid var(--color-black-soft);
  border-radius: 50px;
  background: var(--color-black);
  box-shadow: var(--shadow-pop);
  color: var(--color-white);
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-regular);
  line-height: normal;
  letter-spacing: 0;
  text-align: center;
  word-break: break-word;
}

.alert-item-em {
  font-weight: var(--font-weight-medium);
  letter-spacing: -0.15px;
}

.alert-item--on-dark:not(.alert-item--warning):not(.alert-item--error) {
  border-color: var(--color-white-dim);
  background: var(--color-white);
  color: var(--color-black);
}

.alert-item--warning,
.alert-item--error {
  border-color: var(--color-red-strong);
  background: var(--color-red);
  color: var(--color-white);
}
.welcome-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--app-viewport-height);
  overflow: clip;
  border-radius: var(--app-viewport-radius);
  background: var(--color-white);
  color: var(--color-black);
}

.welcome-layout {
  display: flex;
  align-items: center;
  gap: 150px;
  padding-inline-start: 150px;
}

/* Keeps the logo's layout slot while the intro overlay owns the visible logo. */
.welcome-logo-waiting {
  visibility: hidden;
}

.welcome-card {
  overflow: hidden;
  width: 470px;
  max-width: calc(100vw - 40px);
  border-radius: var(--radius-lg);
  background: var(--color-white-soft);
}

/* Stays invisible until the intro logo has landed, then fades in. */
.welcome-card-waiting {
  opacity: 0;
}

.welcome-card-enter {
  animation: welcome-card-in 600ms var(--ease-fluid) both;
}

.welcome-card-content {
  display: flex;
  flex-direction: column;
  gap: 30px;
  padding: 30px;
}

.welcome-switch {
  display: flex;
  justify-content: center;
  gap: 4px;
  color: var(--color-black-faint);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--letter-spacing-tight);
}

.welcome-switch button {
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
  font: inherit;
  letter-spacing: inherit;
  transition: color 200ms ease;
}

.welcome-switch button:hover {
  color: var(--color-black-dim);
}

.welcome-switch button.welcome-switch-active {
  color: var(--color-black);
  cursor: var(--cursor-default);
}

/* Stacks alternative texts in one cell so swapping them is a true cross-fade. */
.welcome-swap {
  display: grid;
  justify-items: center;
}

.welcome-swap > span {
  grid-area: 1 / 1;
  opacity: 0;
  white-space: nowrap;
  transition: opacity 250ms ease;
}

.welcome-swap > .welcome-swap-active {
  opacity: 1;
}

.welcome-auth-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: 100%;
}

.welcome-auth-note {
  max-width: 310px;
  color: var(--color-black-dim);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-regular);
  line-height: 1.45;
  letter-spacing: var(--letter-spacing-tight);
  text-align: center;
}

.welcome-form-error {
  color: var(--color-red);
  font-size: var(--font-size-sm);
}

.welcome-error-card-content {
  align-items: center;
  text-align: center;
}

.welcome-error-title {
  margin: 0;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
}

.welcome-error-code {
  margin: 0;
  color: var(--color-black-faint);
  font-size: var(--font-size-sm);
}

.welcome-error-link {
  text-decoration: none;
}

.welcome-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(var(--input-slot-width), 100%);
  min-height: 45px;
  padding: 0 18px;
  border: none;
  border-radius: var(--radius-lg);
  background: var(--color-black);
  color: var(--color-white);
  cursor: pointer;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--letter-spacing-tight);
  transition: opacity 200ms ease;
}

.welcome-submit:hover:not(:disabled) {
  opacity: 0.82;
}

.welcome-submit:disabled {
  cursor: var(--cursor-default);
  opacity: 0.4;
}

/* Intro overlay: the loading screen that hands the logo off to the page. */
.welcome-intro {
  position: fixed;
  inset: var(--app-viewport-inset);
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 30px;
  overflow: clip;
  border-radius: var(--app-viewport-radius);
  pointer-events: none;
}

.welcome-intro-backdrop {
  position: absolute;
  inset: 0;
  background: var(--color-white);
}

.welcome-intro-logo {
  position: relative;
  transition: transform 700ms var(--ease-fluid);
  will-change: transform;
}

@keyframes welcome-card-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .welcome-swap > span,
  .welcome-intro-logo {
    transition: none;
  }

  .welcome-card-enter {
    animation: none;
  }
}

@media (max-width: 900px) {
  .welcome-layout {
    flex-direction: column;
    gap: 40px;
    padding-inline-start: 0;
  }
}
.santa-logo {
  color: var(--color-black);
}

/* pathLength={1} normalizes the path length, so dasharray/dashoffset work in [0, 1]. */
.santa-logo-path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: santa-logo-draw 2s ease-in-out forwards;
}

.santa-logo-loop .santa-logo-path {
  animation: santa-logo-draw-loop 2s ease-in-out infinite alternate;
}

.santa-logo-static .santa-logo-path {
  animation: none;
  stroke-dashoffset: 0;
}

@keyframes santa-logo-draw {
  from {
    stroke-dashoffset: 1;
  }

  to {
    stroke-dashoffset: 0;
  }
}

/* The loop alternates draw and reverse-draw so each cycle boundary has matching dashoffset. */
@keyframes santa-logo-draw-loop {
  from {
    stroke-dashoffset: 1;
  }

  to {
    stroke-dashoffset: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .santa-logo-path,
  .santa-logo-loop .santa-logo-path {
    animation: none;
    stroke-dashoffset: 0;
  }
}
.loading-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 30px;
  min-height: var(--app-viewport-height);
  overflow: clip;
  border-radius: var(--app-viewport-radius);
  background: var(--color-white);
  color: var(--color-black);
}
.analytics-consent-banner {
  position: fixed;
  inset-inline-end: var(--spacing-4);
  bottom: var(--spacing-4);
  z-index: 100;
  width: calc(var(--spacing-8) * 13);
  max-width: calc(100vw - var(--spacing-8));
  box-shadow: var(--shadow-high);
  border-radius: var(--radius-container);
  transition:
    opacity var(--duration-fast) var(--ease-standard),
    transform var(--duration-fast) var(--ease-standard);

  @starting-style {
    opacity: 0;
    transform: translateY(var(--spacing-2));
  }
}

.analytics-consent-actions .astryx-button {
  width: 100%;
}

@media (prefers-reduced-motion: reduce) {
  .analytics-consent-banner {
    transition: opacity var(--duration-fast) var(--ease-standard);
  }
}
