@import "tailwindcss";
@import "tom-select/dist/css/tom-select.css" layer(base);

/*
 * Design tokens for the whole app: neutral scale is `slate` everywhere (the
 * old admin UI mixed `stone`/`gray` inconsistently). `primary`/`secondary`
 * are the brand accent colors, registered here as real Tailwind color
 * utilities (bg-primary, text-primary, ring-primary, ...) so `/opacity`
 * modifiers work like any other Tailwind color. Each resolves from the
 * --store-primary/--store-secondary custom properties that
 * layouts/_theme_vars.html.erb sets per-request from the current store's
 * StoreSetting — falling back to the original indigo/slate-900 defaults if
 * those vars are ever unset.
 */
@theme {
  --color-primary: var(--store-primary, #4f46e5);
  --color-secondary: var(--store-secondary, #0f172a);

  /*
   * Sutra brand palette (sutra-tokens.css v1.0) — used by the marketing
   * landing page, auth screens, splash and 404. Named so none of them shadow
   * a Tailwind default scale (indigo/amber/violet stay untouched for the app).
   */
  --color-ink: #14120E;

  --color-cotton-50: #FAF8F5;
  --color-cotton-100: #F3F0EA;
  --color-cotton-200: #E6E1D8;
  --color-cotton-300: #D2CBBF;
  --color-cotton-400: #A9A194;
  --color-cotton-500: #807869;
  --color-cotton-600: #5F584C;
  --color-cotton-700: #474137;
  --color-cotton-800: #2F2B24;
  --color-cotton-900: #1F1C17;
  --color-cotton-950: #14120E;

  --color-madder-50: #FBF0F4;
  --color-madder-100: #F6DCE6;
  --color-madder-200: #ECB5C9;
  --color-madder-300: #DD84A4;
  --color-madder-400: #CB5280;
  --color-madder-500: #B83468;
  --color-madder-600: #A3245A;
  --color-madder-700: #861C4A;
  --color-madder-800: #67163A;
  --color-madder-900: #4A1029;

  --color-turmeric-50: #FDF8EA;
  --color-turmeric-100: #FBEFCC;
  --color-turmeric-300: #F0C85A;
  --color-turmeric-400: #E3A81F;
  --color-turmeric-600: #A87406;
  --color-turmeric-800: #5E4105;
  --color-turmeric-900: #3F2C04;

  --color-leaf-100: #E6F4EC;
  --color-leaf-400: #5BC28A;
  --color-leaf-600: #1F7A4D;

  --color-vermilion-100: #FCEBE6;
  --color-vermilion-300: #F2B4A4;
  --color-vermilion-600: #C2361A;

  --color-saffron-100: #FDF1DC;
  --color-saffron-700: #8F5207;

  --color-link: #3A47A6;
  --color-link-hover: #2E3887;
  --color-focus-halo: #DCE0F4;

  /*
   * The marching dashes on the connector leading into a workflow's current
   * step (workflow_diagram_controller.js) — one 12px dash+gap period per
   * loop, matching its "6 6" stroke-dasharray, so the loop is seamless.
   */
  --animate-workflow-flow: workflow-flow 1s linear infinite;

  @keyframes workflow-flow {
    to {
      stroke-dashoffset: -12;
    }
  }

  /*
   * The POS's "rotate your phone" prompt (layouts/pos): the phone turns from
   * upright onto its side, holds there, and turns back.
   */
  --animate-rotate-device: rotate-device 2.4s ease-in-out infinite;

  @keyframes rotate-device {
    0%, 15% {
      transform: rotate(0deg);
    }
    45%, 70% {
      transform: rotate(-90deg);
    }
    100% {
      transform: rotate(0deg);
    }
  }

  /*
   * The Store Assistant's colours — Gemini's sparkle gradient, which runs
   * blue → violet → rose → amber. Drawn on whatever it's answering (.ai-border).
   */
  --color-assistant-blue: #4285f4;
  --color-assistant-violet: #9b72cb;
  --color-assistant-rose: #d96570;
  --color-assistant-amber: #f49c46;

  --font-display: "Bricolage Grotesque", "Anek Devanagari", system-ui, sans-serif;
  --font-body: "Hanken Grotesk", "Anek Devanagari", system-ui, sans-serif;
  --font-code: "JetBrains Mono", ui-monospace, Menlo, monospace;
  --font-devanagari: "Anek Devanagari", "Noto Sans Devanagari", sans-serif;
}

/*
 * The staff sidebar's desktop icon-only rail (layouts/_sidebar): matches the
 * <aside> and everything inside it while sidebar_controller.js has set
 * data-sidebar-collapsed-value="true". lg+ only — the mobile drawer always
 * opens full width. `sidebar-rail:hidden` drops a label on the rail.
 */
@custom-variant sidebar-rail {
  @media (width >= 64rem) {
    &:where([data-sidebar-collapsed-value="true"], [data-sidebar-collapsed-value="true"] *) {
      @slot;
    }
  }
}

/*
 * A phone or tablet held upright: a touchscreen as the main pointer, taller
 * than it is wide. The POS needs its catalog and cart side by side, so
 * layouts/pos swaps itself for a "rotate your phone" prompt here. A desktop
 * browser window that happens to be tall and narrow has a mouse, so it never
 * matches.
 */
@custom-variant touch-portrait (@media (orientation: portrait) and (pointer: coarse));

/*
 * A screen with little height to spare — in practice a phone on its side,
 * where the POS trims its chrome and photos so a catalog card's name, price
 * and Add button still show without scrolling past the photo.
 */
@custom-variant short (@media (height < 32rem));

@layer base {
  ::selection {
    background-color: color-mix(in srgb, var(--color-primary) 20%, white);
  }
}

/*
 * Tom Select (searchable <select>, see select_controller.js) — the import
 * above provides its required structural CSS (dropdown positioning, hiding
 * the native <select>); this just re-skins its default theme to match the
 * app's own field/dropdown look. Layered after `base` so it reliably wins.
 */
@layer components {
  /* Tom Select measures the native <select>'s width at init and locks it in
     inline — that width is unreliable inside a table cell or a flex/grid
     item, so force it to fill its parent instead. */
  .ts-wrapper {
    @apply w-full;
  }

  .ts-wrapper .ts-control {
    @apply rounded-lg border-0 px-3 py-2 text-sm text-slate-900 shadow-sm ring-1 ring-inset ring-slate-300;
  }

  .ts-wrapper.focus .ts-control {
    @apply ring-2 ring-primary;
  }

  .ts-wrapper .ts-control input {
    @apply text-sm text-slate-900;
  }

  /* z-[60]: appended to <body> (dropdownParent: "body" in select_controller.js)
     to escape overflow-clipping ancestors, so it must outrank every fixed
     overlay it can render inside of — the offcanvas panel and main nav
     sidebar both sit at z-50. */
  .ts-dropdown {
    @apply z-[60] mt-1 rounded-lg border border-slate-200 bg-white text-sm shadow-lg;
  }

  .ts-dropdown [data-selectable] {
    @apply cursor-pointer px-3 py-2 text-slate-700;
  }

  .ts-dropdown .active {
    @apply bg-primary/10 text-primary;
  }

  .ts-dropdown .no-results {
    @apply px-3 py-2 text-slate-400;
  }
}

/*
 * DataTables (server-side tables — see datatable_controller.js). Only the
 * core library is installed, no DataTables theme, so this is its whole look:
 * the app's own card bands, field, button and table styles applied to the
 * markup DataTables generates. The icons are the app's heroicons, drawn as
 * masks so they take the header's text color.
 */
@layer components {
  .dt-container {
    --dt-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='%2394a3b8'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z'/%3E%3C/svg%3E");
    --dt-icon-sortable: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='black'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M8.25 15 12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9'/%3E%3C/svg%3E");
    --dt-icon-ascending: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='black'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m4.5 15.75 7.5-7.5 7.5 7.5'/%3E%3C/svg%3E");
    --dt-icon-descending: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='black'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m19.5 8.25-7.5 7.5-7.5-7.5'/%3E%3C/svg%3E");
    @apply text-sm;
  }

  /* The bands around the table: search and toolbar above, the count and
     pager below — wrapping onto two lines on a phone. */
  .dt-container .dt-layout-row {
    @apply flex flex-wrap items-center justify-between gap-3 px-4 py-3;
  }

  .dt-container .dt-layout-row:first-child {
    @apply border-b border-slate-100 p-4;
  }

  .dt-container .dt-layout-row:last-child {
    @apply border-t border-slate-100;
  }

  .dt-container .dt-layout-row.dt-layout-table {
    @apply block overflow-x-auto border-0 p-0;
  }

  .dt-container .dt-layout-start {
    @apply flex min-w-64 flex-1 items-center gap-3;
  }

  .dt-container .dt-layout-end {
    @apply flex flex-wrap items-center gap-3;
  }

  .dt-container .dt-toolbar {
    @apply flex items-center gap-2;
  }

  .dt-container .dt-input {
    @apply rounded-lg border-0 px-3 py-2 text-sm text-slate-900 shadow-sm ring-1 ring-inset ring-slate-300 placeholder:text-slate-400 focus:ring-2 focus:ring-inset focus:ring-primary;
  }

  .dt-container .dt-search {
    @apply w-full;
  }

  .dt-container .dt-search .dt-input {
    @apply block w-full pl-9;
    background: var(--dt-icon-search) no-repeat left 0.75rem center / 1rem;
  }

  .dt-container .dt-search label {
    @apply sr-only;
  }

  .dt-container .dt-length {
    @apply flex items-center gap-2 whitespace-nowrap text-slate-500;
  }

  .dt-container .dt-length .dt-input {
    @apply py-1.5;
  }

  .dt-container .dt-info {
    @apply text-slate-500;
  }

  .dt-container .dt-paging nav {
    @apply flex items-center gap-1;
  }

  /* btn_class(variant: :secondary, size: :sm), with the current page in
     the primary color. */
  .dt-container .dt-paging-button {
    @apply inline-flex min-w-8 items-center justify-center rounded-lg bg-white px-2.5 py-1.5 text-xs font-medium text-slate-700 shadow-sm ring-1 ring-slate-300 ring-inset hover:bg-slate-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary;
  }

  .dt-container .dt-paging-button.current {
    @apply bg-primary text-white ring-primary hover:bg-primary/90;
  }

  .dt-container .dt-paging-button.disabled {
    @apply pointer-events-none opacity-40;
  }

  .dt-container .dt-paging .ellipsis {
    @apply px-1 text-slate-400;
  }

  table.dataTable thead th {
    @apply border-b border-slate-100 px-4 py-2 text-xs font-medium tracking-wide text-slate-500 uppercase;
  }

  table.dataTable .dt-column-header {
    @apply inline-flex items-center gap-1;
  }

  table.dataTable thead th.dt-orderable-asc,
  table.dataTable thead th.dt-orderable-desc {
    @apply cursor-pointer select-none hover:text-slate-900;
  }

  table.dataTable thead th.dt-ordering-asc,
  table.dataTable thead th.dt-ordering-desc {
    @apply text-slate-900;
  }

  table.dataTable .dt-column-order {
    @apply size-3.5 shrink-0 bg-current;
    mask: var(--dt-icon-sortable) center / contain no-repeat;
  }

  table.dataTable th.dt-ordering-asc .dt-column-order {
    mask-image: var(--dt-icon-ascending);
  }

  table.dataTable th.dt-ordering-desc .dt-column-order {
    mask-image: var(--dt-icon-descending);
  }

  table.dataTable th.dt-orderable-none .dt-column-order {
    @apply hidden;
  }

  table.dataTable tbody tr {
    @apply border-b border-slate-100 last:border-b-0;
  }

  table.dataTable tbody td {
    @apply px-4 py-3 text-slate-600;
  }

  table.dataTable tbody td.dt-empty {
    @apply py-10 text-center text-slate-500;
  }

  /* The rows on screen while their replacement is on its way — the POS
     catalog's aria-busy treatment. */
  table.dataTable tbody {
    @apply transition-opacity;
  }

  table.dataTable[aria-busy="true"] tbody {
    @apply opacity-60;
  }

  /* The loading indicator — DataTables' processing element, set beside the
     table and shown (an inline display: block) for every request, the
     first load included. A pill over the middle of the table, fading in
     only once a request has run long enough to notice, so a quick redraw
     doesn't flash it. */
  .dt-container .dt-layout-table .dt-layout-cell {
    @apply relative;
  }

  .dt-container .dt-processing {
    @apply pointer-events-none absolute top-1/2 left-1/2 z-10 hidden -translate-x-1/2 -translate-y-1/2;
    animation: dt-processing-in 150ms ease-out 150ms both;
  }

  /* DataTables' own animated dots — this skin draws a spinner instead. */
  .dt-container .dt-processing > div {
    @apply hidden;
  }

  .dt-container .dt-loading {
    @apply inline-flex items-center gap-2 whitespace-nowrap rounded-full bg-white px-3 py-1.5 text-xs font-medium text-slate-600 shadow-md ring-1 ring-slate-200;
  }

  .dt-container .dt-spinner {
    @apply size-3.5 rounded-full border-2 border-slate-200 border-t-primary motion-safe:animate-spin;
  }
}

@keyframes dt-processing-in {
  from {
    opacity: 0;
  }
}

/*
 * DataTables on a phone (below md): no sideways-scrolling table. The header
 * becomes a wrapping row of sort chips (keeping select-all), and each row a
 * card — the primary column (ApplicationDatatable's `primary: true`) and any
 * untitled one, like a checkbox, along the top; every other column a
 * "Label  value" line beneath, labelled from its header (data-label, set by
 * datatable_controller.js). The pager keeps Previous / current / Next.
 */
@layer components {
  @media (width < 48rem) {
    .dt-container .dt-layout-end {
      @apply w-full justify-between;
    }

    .dt-container .dt-toolbar {
      @apply w-full;
    }

    .dt-container .dt-toolbar > * {
      @apply flex-1;
    }

    .dt-container .dt-paging-button:not(.current, [data-dt-idx="previous"], [data-dt-idx="next"]),
    .dt-container .dt-paging .ellipsis {
      @apply hidden;
    }

    table.dataTable,
    table.dataTable thead,
    table.dataTable tbody {
      @apply block;
    }

    table.dataTable thead tr {
      @apply flex flex-wrap items-center gap-2 border-b border-slate-100 px-4 py-3;
    }

    table.dataTable thead th {
      @apply block rounded-full border-0 px-2.5 py-1 ring-1 ring-slate-200 ring-inset;
    }

    table.dataTable thead th.dt-orderable-none {
      @apply hidden;
    }

    table.dataTable thead th.dt-orderable-none:has(input) {
      @apply block px-1 ring-0;
    }

    table.dataTable tbody tr {
      @apply flex flex-wrap items-center gap-x-3 gap-y-1.5 px-4 py-3;
    }

    table.dataTable tbody td {
      @apply block p-0;
    }

    table.dataTable tbody td.dt-primary {
      @apply min-w-0 flex-1;
    }

    table.dataTable tbody td[data-label]:not(.dt-primary) {
      @apply flex w-full items-center justify-between gap-4;
    }

    table.dataTable tbody td[data-label]:not(.dt-primary)::before {
      content: attr(data-label);
      @apply text-xs font-medium tracking-wide text-slate-400 uppercase;
    }

    table.dataTable tbody td.dt-empty {
      @apply w-full py-10;
    }
  }
}

/*
 * A conversation the Store Assistant is answering
 * (Conversation.handled_by_assistant) — a border in its gradient that keeps
 * turning, like Gemini's sparkle. It's a ::before masked down to a ring, so
 * the element's own background (hover, selected) still shows through, and
 * only its angle animates (@property). With reduced motion it holds still.
 *
 * .ai-border-inset draws it a little inside a square-edged list row, rounded.
 */
@property --ai-border-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@layer components {
  .ai-border {
    position: relative;
  }

  .ai-border::before {
    content: "";
    position: absolute;
    inset: 0;
    padding: 1.5px;
    border-radius: inherit;
    background: conic-gradient(from var(--ai-border-angle), var(--color-assistant-blue), var(--color-assistant-violet),
                               var(--color-assistant-rose), var(--color-assistant-amber), var(--color-assistant-blue));
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    pointer-events: none;
    animation: ai-border-turn 4s linear infinite;
  }

  .ai-border-inset::before {
    inset: 3px;
    border-radius: 0.5rem;
  }

  @media (prefers-reduced-motion: reduce) {
    .ai-border::before {
      animation: none;
    }
  }
}

@keyframes ai-border-turn {
  to {
    --ai-border-angle: 360deg;
  }
}
