<script lang="ts">
  import { api } from '$lib/api';
  import Skeleton from '$lib/components/Skeleton.svelte';
  import { toast } from '$lib/toast';
  import type { ProductCostingInputs, ProductCostingItem, ProductCostingItemUpdateInput } from '$lib/types';
  import {
    AlertTriangle,
    RefreshCcw,
    Save,
    Search,
    X
  } from 'lucide-svelte';

  type ProductCostingData = {
    items: ProductCostingItem[];
    inputs: ProductCostingInputs | null;
  };

  let { data }: { data: ProductCostingData } = $props();

  function initialItems() {
    return data.items ?? [];
  }

  function initialInputs() {
    return data.inputs ? structuredClone(data.inputs) : null;
  }

  function initialSelectedItem() {
    return data.items?.[0] ?? null;
  }

  function initialEditDraft() {
    const item = initialSelectedItem();
    return item ? buildDraft(item) : null;
  }

  let items = $state<ProductCostingItem[]>(initialItems());
  let inputs = $state<ProductCostingInputs | null>(initialInputs());
  let query = $state('');
  let clientFilter = $state('');
  let unitFilter = $state('');
  let statusFilter = $state<'all' | 'ready' | 'warnings'>('all');
  let activeView = $state<'items' | 'inputs'>('items');
  let selectedItem = $state<ProductCostingItem | null>(initialSelectedItem());
  let editDraft = $state<ProductCostingItemUpdateInput | null>(initialEditDraft());
  let recalculating = $state(false);
  let savingInputs = $state(false);
  let savingItem = $state(false);
  let inputsDirty = $state(false);
  let page = $state(1);
  let pageSize = $state(25);
  let tableLoading = $state(false);

  const unitTypes = ['Standard', 'Bulka', '1.5 kg', 'Per Unit'];
  const ownBagOptions = ['', 'Yes', 'No Bag'];
  const clients = $derived(Array.from(new Set(items.map((item) => item.client_category))).sort());
  const processOptions = $derived(Array.from(new Set([
    ...(inputs?.processes.map((process) => process.key) ?? []),
    ...items.map((item) => item.bagging_process).filter((value): value is string => Boolean(value))
  ])).sort());
  const warningCount = $derived(items.filter((item) => item.warnings.length).length);
  const readyCount = $derived(items.length - warningCount);
  const averageDelivered = $derived(
    average(items.map((item) => item.finished_product_delivered_cost).filter((value): value is number => value != null))
  );
  const missingLookupCount = $derived(items.filter((item) => hasWarning(item, 'lookup')).length);
  const visibleItems = $derived(
    items.filter((item) => {
      const haystack =
        `${item.client_category} ${item.item_id ?? ''} ${item.product_name} ${item.mix_product_name} ${item.unit_type}`.toLowerCase();
      const matchesSearch = haystack.includes(query.trim().toLowerCase());
      const matchesClient = !clientFilter || item.client_category === clientFilter;
      const matchesUnit = !unitFilter || item.unit_type === unitFilter;
      const matchesStatus =
        statusFilter === 'all' ||
        (statusFilter === 'ready' && !item.warnings.length) ||
        (statusFilter === 'warnings' && item.warnings.length > 0);

      return matchesSearch && matchesClient && matchesUnit && matchesStatus;
    })
  );
  const totalPages = $derived(Math.max(1, Math.ceil(visibleItems.length / pageSize)));
  const pageStart = $derived(visibleItems.length ? (page - 1) * pageSize + 1 : 0);
  const pageEnd = $derived(Math.min(page * pageSize, visibleItems.length));
  const pagedItems = $derived(visibleItems.slice((page - 1) * pageSize, page * pageSize));

  $effect(() => {
    query;
    clientFilter;
    unitFilter;
    statusFilter;
    pageSize;
    page = 1;
  });

  $effect(() => {
    if (page > totalPages) page = totalPages;
  });

  function average(values: number[]) {
    return values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
  }

  function hasWarning(item: ProductCostingItem, pattern: string) {
    return item.warnings.some((warning) => warning.toLowerCase().includes(pattern));
  }

  function money(value: number | null | undefined, digits = 2) {
    return value == null ? 'N/A' : `$${value.toFixed(digits)}`;
  }

  function number(value: number | null | undefined, digits = 4) {
    return value == null ? 'N/A' : value.toFixed(digits);
  }

  function cents(value: number | null | undefined) {
    return value == null ? 'No value' : `${money(value, 4)} = ${(value * 100).toFixed(2)} cents`;
  }

  function margin(value: number | null | undefined) {
    return value == null ? 'Default' : `${(value * 100).toFixed(2)}%`;
  }

  function marginHelp(value: number | null | undefined) {
    return value == null ? 'Default margin' : `${value.toFixed(4)} = ${(value * 100).toFixed(2)}%`;
  }

  function initials(name: string) {
    return name
      .split(/\s+/)
      .filter(Boolean)
      .map((piece) => piece[0])
      .join('')
      .slice(0, 2)
      .toUpperCase();
  }

  function buildDraft(item: ProductCostingItem): ProductCostingItemUpdateInput {
    return {
      client_category: item.client_category,
      item_id: item.item_id,
      product_name: item.product_name,
      mix_product_name: item.mix_product_name,
      unit_type: item.unit_type,
      own_bag: item.own_bag,
      unit_kg: item.unit_kg,
      items_per_pallet: item.items_per_pallet,
      bagging_process: item.bagging_process,
      manual_distributor_margin: item.manual_distributor_margin,
      manual_wholesale_margin: item.manual_wholesale_margin
    };
  }

  function selectItem(item: ProductCostingItem) {
    selectedItem = item;
    editDraft = buildDraft(item);
  }

  function clearNullableText(value: string | null | undefined) {
    const trimmed = value?.trim();
    return trimmed ? trimmed : null;
  }

  function normalizeNumber(value: number | null | undefined) {
    return value === undefined || value === null || Number.isNaN(Number(value)) ? null : Number(value);
  }

  function syncPerKgFromTonne(kind: 'grading' | 'cracking') {
    if (!inputs) return;
    inputsDirty = true;
    if (kind === 'grading') {
      inputs.base.grading_per_kg = Number((inputs.base.grading_per_tonne / 1000).toFixed(6));
    } else {
      inputs.base.cracking_per_kg = Number((inputs.base.cracking_per_tonne / 1000).toFixed(6));
    }
  }

  function markInputsDirty() {
    inputsDirty = true;
  }

  function goToPage(nextPage: number) {
    page = Math.min(Math.max(nextPage, 1), totalPages);
  }

  async function saveInputs() {
    if (!inputs) return;
    savingInputs = true;
    tableLoading = true;
    const tid = toast.loading('Saving Product Costing inputs...');
    try {
      inputs = await api.updateProductCostingInputs(inputs);
      items = await api.productCostingItemsFresh();
      if (selectedItem) {
        selectedItem = items.find((item) => item.id === selectedItem?.id) ?? selectedItem;
        editDraft = buildDraft(selectedItem);
      }
      inputsDirty = false;
      toast.dismiss(tid);
      toast.success('Inputs saved and product costs recalculated.');
    } catch (error) {
      toast.dismiss(tid);
      toast.error(error instanceof Error ? error.message : 'Unable to save Product Costing inputs.');
    } finally {
      savingInputs = false;
      tableLoading = false;
    }
  }

  async function saveSelectedItem() {
    if (!selectedItem || !editDraft) return;
    savingItem = true;
    tableLoading = true;
    const tid = toast.loading('Saving costing row...');
    try {
      const updated = await api.updateProductCostingItem(selectedItem.id, {
        ...editDraft,
        item_id: clearNullableText(editDraft.item_id),
        own_bag: clearNullableText(editDraft.own_bag),
        bagging_process: clearNullableText(editDraft.bagging_process),
        unit_kg: normalizeNumber(editDraft.unit_kg),
        items_per_pallet: normalizeNumber(editDraft.items_per_pallet),
        manual_distributor_margin: normalizeNumber(editDraft.manual_distributor_margin),
        manual_wholesale_margin: normalizeNumber(editDraft.manual_wholesale_margin)
      });
      items = items.map((item) => (item.id === updated.id ? updated : item));
      selectedItem = updated;
      editDraft = buildDraft(updated);
      toast.dismiss(tid);
      toast.success('Costing row saved and recalculated.');
    } catch (error) {
      toast.dismiss(tid);
      toast.error(error instanceof Error ? error.message : 'Unable to save costing row.');
    } finally {
      savingItem = false;
      tableLoading = false;
    }
  }

  async function recalculateAll() {
    recalculating = true;
    tableLoading = true;
    const tid = toast.loading('Recalculating product costs...');
    try {
      await api.recalculateProductCosting();
      items = await api.productCostingItemsFresh();
      if (selectedItem) {
        selectedItem = items.find((item) => item.id === selectedItem?.id) ?? null;
        editDraft = selectedItem ? buildDraft(selectedItem) : null;
      }
      toast.dismiss(tid);
      toast.success('Product costing recalculated.');
    } catch (error) {
      toast.dismiss(tid);
      toast.error(error instanceof Error ? error.message : 'Unable to recalculate product costing.');
    } finally {
      recalculating = false;
      tableLoading = false;
    }
  }
</script>

<section class="costing-shell">
  <div class="head-actions">
    <button class="primary-button" disabled={recalculating} type="button" onclick={recalculateAll}>
      <span class:spin={recalculating} aria-hidden="true"><RefreshCcw size={17} /></span>
      {recalculating ? 'Updating' : 'Update Prices'}
    </button>
  </div>

  <section class="health-strip" aria-label="Product costing health summary">
    <article class="health-card">
      <span>Products</span>
      <strong>{items.length}</strong>
      <p>{readyCount} ready</p>
    </article>
    <article class="health-card warning">
      <span>Need Review</span>
      <strong>{warningCount}</strong>
      <p>{missingLookupCount} missing cost{missingLookupCount === 1 ? '' : 's'}</p>
    </article>
    <article class="health-card">
      <span>Average Cost</span>
      <strong>{money(averageDelivered)}</strong>
      <p>Delivered</p>
    </article>
  </section>

  <section class="workspace-grid">
    <div class="main-column">
      <nav class="view-tabs" aria-label="Product Costing views">
        <button class:active={activeView === 'items'} type="button" onclick={() => (activeView = 'items')}>
          Products
        </button>
        <button class:active={activeView === 'inputs'} type="button" onclick={() => (activeView = 'inputs')}>
          Settings
        </button>
      </nav>

      {#if activeView === 'inputs'}
        <section class="panel inputs-panel">
          <div class="section-toolbar">
            <div>
              <h3>Settings</h3>
              <p>Change the standard costs used to calculate product prices.</p>
            </div>
            <div class="toolbar-actions">
              {#if inputsDirty}
                <span class="dirty-pill">Unsaved changes</span>
              {/if}
              <button class="primary-button compact" disabled={!inputs || savingInputs} type="button" onclick={saveInputs}>
                <Save size={16} />
                {savingInputs ? 'Saving' : 'Save Settings'}
              </button>
            </div>
          </div>

          {#if inputs}
            <div class="input-block base-costs">
              <div class="block-heading">
                <strong>Work Costs</strong>
                <span>Enter dollars for grading and cracking.</span>
              </div>
              <div class="input-grid four">
                <label>
                  <span>Grading ($/tonne)</span>
                  <div class="money-field">
                    <i>$</i>
                    <input type="number" step="0.0001" bind:value={inputs.base.grading_per_tonne} oninput={() => syncPerKgFromTonne('grading')} />
                  </div>
                  <small>{money(inputs.base.grading_per_tonne, 2)} per tonne</small>
                </label>
                <label>
                  <span>Grading ($/kg)</span>
                  <div class="money-field">
                    <i>$</i>
                    <input type="number" step="0.000001" bind:value={inputs.base.grading_per_kg} oninput={markInputsDirty} />
                  </div>
                  <small>{cents(inputs.base.grading_per_kg)} per kg</small>
                </label>
                <label>
                  <span>Cracking ($/tonne)</span>
                  <div class="money-field">
                    <i>$</i>
                    <input type="number" step="0.0001" bind:value={inputs.base.cracking_per_tonne} oninput={() => syncPerKgFromTonne('cracking')} />
                  </div>
                  <small>{money(inputs.base.cracking_per_tonne, 2)} per tonne</small>
                </label>
                <label>
                  <span>Cracking ($/kg)</span>
                  <div class="money-field">
                    <i>$</i>
                    <input type="number" step="0.000001" bind:value={inputs.base.cracking_per_kg} oninput={markInputsDirty} />
                  </div>
                  <small>{cents(inputs.base.cracking_per_kg)} per kg</small>
                </label>
              </div>
            </div>

            <div class="input-columns">
              <div class="input-block">
                <div class="block-heading">
                  <strong>Bagging Processes</strong>
                  <span>Dollars per kg. Example: 0.0400 is 4 cents.</span>
                </div>
                <div class="input-list">
                  {#each inputs.processes as process}
                    <label class="inline-field">
                      <span>{process.label}<small>{cents(process.cost)} / kg</small></span>
                      <div class="money-field compact-field">
                        <i>$</i>
                        <input type="number" step="0.0001" bind:value={process.cost} oninput={markInputsDirty} />
                      </div>
                    </label>
                  {/each}
                </div>
              </div>

              <div class="input-block">
                <div class="block-heading">
                  <strong>Bag Costs</strong>
                  <span>Dollars per bag or unit. Example: 2.0000 is two dollars.</span>
                </div>
                <div class="input-list">
                  {#each inputs.bags as bag}
                    <label class="inline-field">
                      <span>{bag.label}<small>{money(bag.cost, 4)} per bag/unit</small></span>
                      <div class="money-field compact-field">
                        <i>$</i>
                        <input type="number" step="0.0001" bind:value={bag.cost} oninput={markInputsDirty} />
                      </div>
                    </label>
                  {/each}
                </div>
              </div>

              <div class="input-block">
                <div class="block-heading">
                  <strong>Freight</strong>
                  <span>Dollars per pallet.</span>
                </div>
                <div class="input-list">
                  {#each inputs.freight as freight}
                    <label class="inline-field">
                      <span>{freight.label}<small>{money(freight.cost, 2)} per pallet</small></span>
                      <div class="money-field compact-field">
                        <i>$</i>
                        <input type="number" step="0.0001" bind:value={freight.cost} oninput={markInputsDirty} />
                      </div>
                    </label>
                  {/each}
                </div>
              </div>
            </div>

            <div class="input-block">
              <div class="block-heading">
                <strong>Client Margins</strong>
                <span>Enter decimals. Example: 0.2000 is 20%.</span>
              </div>
              <div class="margin-table">
                {#each inputs.clients as client}
                  <div class="margin-row">
                    <strong>{client.client_category}</strong>
                    <label>
                      <span>Distributor</span>
                      <input type="number" min="0" max="0.9999" step="0.000001" bind:value={client.distributor_margin} oninput={markInputsDirty} />
                      <small>{marginHelp(client.distributor_margin)}</small>
                    </label>
                    <label>
                      <span>Wholesale</span>
                      <input type="number" min="0" max="0.9999" step="0.000001" bind:value={client.wholesale_margin} oninput={markInputsDirty} />
                      <small>{marginHelp(client.wholesale_margin)}</small>
                    </label>
                  </div>
                {/each}
              </div>
            </div>
          {:else}
            <div class="empty-state">
              <strong>No input records loaded</strong>
              <span>Refresh after the backend has seeded Product Costing inputs.</span>
            </div>
          {/if}
        </section>
      {:else}
        <section class="panel">
          <div class="section-toolbar">
            <div>
              <h3>Products</h3>
              <p>Select a product to see or change its details.</p>
            </div>
          </div>

          <div class="filter-bar">
            <label class="search-field">
              <span>Search</span>
              <Search size={17} />
              <input bind:value={query} placeholder="Search product, mix, client, item id" />
            </label>
            <label>
              <span>Client</span>
              <select bind:value={clientFilter}>
                <option value="">All clients</option>
                {#each clients as client}
                  <option value={client}>{client}</option>
                {/each}
              </select>
            </label>
            <label>
              <span>Show</span>
              <select bind:value={statusFilter}>
                <option value="all">All products</option>
                <option value="warnings">Need review</option>
                <option value="ready">Ready</option>
              </select>
            </label>
            <label class="page-size-field">
              <span>Rows per page</span>
              <select bind:value={pageSize}>
                <option value={15}>15</option>
                <option value={25}>25</option>
                <option value={50}>50</option>
                <option value={100}>100</option>
              </select>
            </label>
          </div>

          <div class="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Product</th>
                  <th>Delivered</th>
                  <th>Distributor</th>
                  <th>Wholesale</th>
                  <th>Review</th>
                </tr>
              </thead>
              <tbody>
                {#if tableLoading}
                  {#each Array(8) as _}
                    <tr class="skeleton-row">
                      <td class="product-cell" data-label="Product">
                        <div class="product-token">
                          <Skeleton variant="circle" width="1.9rem" height="1.9rem" radius="0.65rem" />
                          <div class="skeleton-lines">
                            <Skeleton width="11rem" height="0.72rem" />
                            <Skeleton width="7rem" height="0.58rem" />
                          </div>
                        </div>
                      </td>
                      <td data-label="Delivered"><Skeleton width="5.5rem" height="0.72rem" /></td>
                      <td data-label="Distributor"><Skeleton width="5.5rem" height="0.72rem" /></td>
                      <td data-label="Wholesale"><Skeleton width="5.5rem" height="0.72rem" /></td>
                      <td data-label="Review"><Skeleton variant="pill" width="4.8rem" height="1.25rem" /></td>
                    </tr>
                  {/each}
                {:else if pagedItems.length}
                {#each pagedItems as item}
                  <tr class:active={selectedItem?.id === item.id} class:warn={item.warnings.length > 0} onclick={() => selectItem(item)}>
                    <td class="product-cell" data-label="Product">
                      <div class="product-token">
                        <span>{initials(item.product_name)}</span>
                        <div>
                          <strong>{item.product_name}</strong>
                          <small>{item.client_category} · {item.mix_product_name}</small>
                        </div>
                      </div>
                    </td>
                    <td data-label="Delivered">
                      <strong class="money">{money(item.finished_product_delivered_cost)}</strong>
                    </td>
                    <td data-label="Distributor">
                      <strong>{money(item.distributor_price)}</strong>
                    </td>
                    <td data-label="Wholesale">
                      <strong>{money(item.wholesale_price, 1)}</strong>
                    </td>
                    <td data-label="Review">
                      <span class={`status-pill ${item.warnings.length ? 'warning' : 'positive'}`}>
                        {item.warnings.length ? 'Needs review' : 'Ready'}
                      </span>
                    </td>
                  </tr>
                {/each}
                {:else}
                  <tr class="empty-row">
                    <td colspan="7">
                      <strong>No costing rows found</strong>
                      <small>Adjust the filters or search term.</small>
                    </td>
                  </tr>
                {/if}
              </tbody>
            </table>
          </div>
          <div class="pagination-bar">
            <span>{pageStart}-{pageEnd} of {visibleItems.length}</span>
            <div class="pagination-controls">
              <button type="button" disabled={page <= 1 || tableLoading} onclick={() => goToPage(1)}>First</button>
              <button type="button" disabled={page <= 1 || tableLoading} onclick={() => goToPage(page - 1)}>Prev</button>
              <strong>Page {page} of {totalPages}</strong>
              <button type="button" disabled={page >= totalPages || tableLoading} onclick={() => goToPage(page + 1)}>Next</button>
              <button type="button" disabled={page >= totalPages || tableLoading} onclick={() => goToPage(totalPages)}>Last</button>
            </div>
          </div>
        </section>
      {/if}
    </div>

    <aside class="inspector" aria-label="Selected product costing detail">
      {#if selectedItem && editDraft}
        <div class="inspector-head">
          <div>
            <span>{selectedItem.client_category}</span>
            <h3>{selectedItem.product_name}</h3>
          </div>
          <button class="icon-button" type="button" aria-label="Clear selected product" onclick={() => (selectedItem = null)}>
            <X size={17} />
          </button>
        </div>

        {#if selectedItem.warnings.length}
          <div class="warning-box">
            <AlertTriangle size={17} />
            <div>
              {#each selectedItem.warnings as warning}
                <span>{warning}</span>
              {/each}
            </div>
          </div>
        {/if}

        <div class="price-stack">
          <div>
            <span>Delivered</span>
            <strong>{money(selectedItem.finished_product_delivered_cost)}</strong>
          </div>
          <div>
            <span>Distributor</span>
            <strong>{money(selectedItem.distributor_price)}</strong>
          </div>
          <div>
            <span>Wholesale</span>
            <strong>{money(selectedItem.wholesale_price, 1)}</strong>
          </div>
        </div>

        <div class="inspector-section">
          <div class="block-heading">
            <strong>Product Details</strong>
            <span>Change these when the product setup is wrong.</span>
          </div>
          <div class="drawer-form">
            <label>
              <span>Client</span>
              <input bind:value={editDraft.client_category} />
            </label>
            <label>
              <span>Item ID</span>
              <input bind:value={editDraft.item_id} />
            </label>
            <label class="wide">
              <span>Product name</span>
              <input bind:value={editDraft.product_name} />
            </label>
            <label class="wide">
              <span>Mix name</span>
              <input bind:value={editDraft.mix_product_name} />
            </label>
            <label>
              <span>Unit type</span>
              <select bind:value={editDraft.unit_type}>
                {#each unitTypes as unit}
                  <option value={unit}>{unit}</option>
                {/each}
              </select>
            </label>
            <label>
              <span>Own bag</span>
              <select bind:value={editDraft.own_bag}>
                {#each ownBagOptions as option}
                  <option value={option}>{option || 'Default'}</option>
                {/each}
              </select>
            </label>
            <label>
              <span>Bag size kg</span>
              <input type="number" min="0" step="0.001" bind:value={editDraft.unit_kg} />
            </label>
            <label>
              <span>Bags per pallet</span>
              <input type="number" min="0" step="1" bind:value={editDraft.items_per_pallet} />
            </label>
            <label class="wide">
              <span>Bagging process</span>
              <select bind:value={editDraft.bagging_process}>
                <option value="">No process</option>
                {#each processOptions as process}
                  <option value={process}>{process}</option>
                {/each}
              </select>
            </label>
            <label>
              <span>Distributor margin override</span>
              <input type="number" min="0" max="0.9999" step="0.000001" bind:value={editDraft.manual_distributor_margin} />
            </label>
            <label>
              <span>Wholesale margin override</span>
              <input type="number" min="0" max="0.9999" step="0.000001" bind:value={editDraft.manual_wholesale_margin} />
            </label>
          </div>
          <button class="primary-button full" disabled={savingItem} type="button" onclick={saveSelectedItem}>
            <Save size={16} />
            {savingItem ? 'Saving' : 'Save Product'}
          </button>
        </div>

        <div class="inspector-section">
          <div class="block-heading">
            <strong>Cost Details</strong>
            <span>These numbers make up the delivered cost.</span>
          </div>
          <div class="breakdown-grid">
            <div><span>Cleaned</span><strong>{number(selectedItem.cleaned_product_cost_per_kg)}</strong></div>
            <div><span>Grading</span><strong>{number(selectedItem.grading_cost_per_kg)}</strong></div>
            <div><span>Bagging</span><strong>{number(selectedItem.bagging_cost_per_kg)}</strong></div>
            <div><span>Cracking</span><strong>{number(selectedItem.cracking_cost_per_kg)}</strong></div>
            <div><span>Bag</span><strong>{money(selectedItem.bag_cost_per_unit)}</strong></div>
            <div><span>Freight</span><strong>{money(selectedItem.freight_cost_per_unit)}</strong></div>
          </div>
        </div>
      {:else}
        <div class="empty-inspector">
          <Calculator size={24} />
          <strong>Select a costing row</strong>
          <span>Use the table to inspect pricing and edit assumptions.</span>
        </div>
      {/if}
    </aside>
  </section>
</section>

<style>
  :global(.spin) {
    animation: spin 900ms linear infinite;
  }

  h3,
  p {
    margin: 0;
  }

  button,
  input,
  select {
    font: inherit;
  }

  .costing-shell {
    --costing-ink: oklch(25% 0.018 155);
    --costing-muted: oklch(52% 0.022 155);
    --costing-panel: oklch(99% 0.004 145);
    --costing-soft: oklch(96.8% 0.008 145);
    --costing-line: oklch(88% 0.014 145);
    --costing-line-strong: oklch(78% 0.02 145);
    --costing-warn: oklch(58% 0.14 72);
    --costing-input-bg: oklch(99% 0.004 145);
    --costing-warn-soft: oklch(95% 0.055 82);
    --costing-warn-box: oklch(96% 0.045 84);
    --costing-warn-border: oklch(84% 0.085 78);
    --costing-warn-row: oklch(92% 0.08 81);
    display: grid;
    gap: 1.05rem;
    color: var(--costing-ink);
  }

  /* Dark mode: remap the costing palette onto the neutral dark theme tokens so
     the worksheet themes alongside the rest of the app instead of staying a
     bright light card. The warn tints lean on the global warning tokens. */
  :global([data-theme='dark']) .costing-shell {
    --costing-ink: var(--color-text-primary);
    --costing-muted: var(--color-text-muted);
    --costing-panel: var(--color-bg-surface);
    --costing-soft: var(--color-bg-app);
    --costing-line: var(--color-border);
    --costing-line-strong: var(--color-border);
    --costing-warn: var(--color-warning-text);
    --costing-input-bg: var(--color-input-bg);
    --costing-warn-soft: var(--color-warning-tint);
    --costing-warn-box: var(--color-warning-tint);
    --costing-warn-border: color-mix(in srgb, var(--color-warning) 45%, var(--color-border));
    --costing-warn-row: var(--color-warning);
  }

  .health-strip,
  .workspace-grid,
  .section-toolbar,
  .filter-bar,
  .head-actions,
  .pagination-bar,
  .pagination-controls,
  .warning-box {
    display: flex;
    gap: 1rem;
  }

  .section-toolbar p,
  .block-heading span,
  small,
  .health-card p,
  .health-card span,
  .inspector-head span,
  .breakdown-grid span,
  .price-stack span,
  .empty-inspector span {
    color: var(--costing-muted);
  }

  .head-actions {
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
  }

  .toolbar-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.6rem;
    flex-wrap: wrap;
  }

  .dirty-pill {
    display: inline-flex;
    align-items: center;
    min-height: 2rem;
    padding: 0.38rem 0.62rem;
    border-radius: 999px;
    color: var(--costing-warn);
    background: var(--costing-warn-soft);
    font-size: 0.8rem;
    font-weight: 800;
  }

  .primary-button,
  .icon-button,
  .view-tabs button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    min-height: 2.55rem;
    border-radius: 0.72rem;
    font-weight: 750;
    cursor: pointer;
    transition:
      background-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
      border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
      transform 160ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .primary-button {
    padding: 0.72rem 0.9rem;
  }

  .primary-button {
    border: 1px solid var(--green-deep);
    background: var(--color-brand);
    color: oklch(99% 0.004 145);
  }

  .primary-button:hover:not(:disabled) {
    background: var(--green-deep);
  }

  .primary-button:disabled {
    opacity: 0.62;
    cursor: progress;
  }

  .primary-button.compact {
    min-height: 2.35rem;
    padding: 0.62rem 0.78rem;
  }

  .primary-button.full {
    width: 100%;
    margin-top: 0.8rem;
  }

  .health-strip {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.8rem;
  }

  .health-card,
  .panel,
  .inspector {
    border: 1px solid var(--costing-line);
    background: var(--costing-panel);
    box-shadow: var(--shadow);
  }

  .health-card {
    min-height: 7.2rem;
    padding: 1rem;
    border-radius: 1rem;
  }

  .health-card.warning {
    background: color-mix(in srgb, var(--costing-warn-row) 34%, var(--costing-panel));
  }

  .health-card strong {
    display: block;
    margin: 0.35rem 0 0.12rem;
    font-size: 1.7rem;
    line-height: 1;
  }

  .workspace-grid {
    align-items: start;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(22rem, 0.34fr);
  }

  .main-column {
    min-width: 0;
  }

  .view-tabs {
    display: inline-flex;
    gap: 0.25rem;
    padding: 0.28rem;
    margin-bottom: 0.85rem;
    border: 1px solid var(--costing-line);
    border-radius: 0.9rem;
    background: var(--costing-soft);
  }

  .view-tabs button,
  .icon-button {
    border: none;
    background: transparent;
    color: var(--costing-muted);
  }

  .view-tabs button {
    padding: 0.58rem 0.8rem;
  }

  .view-tabs button.active {
    background: var(--costing-panel);
    color: var(--green-deep);
    box-shadow: inset 0 0 0 1px var(--costing-line);
  }

  .panel,
  .inspector {
    border-radius: 1rem;
  }

  .panel {
    padding: 1rem;
  }

  .section-toolbar {
    align-items: flex-start;
    justify-content: space-between;
    margin-bottom: 0.95rem;
  }

  .section-toolbar h3,
  .inspector-head h3 {
    font-size: 1.08rem;
    font-weight: 750;
  }

  .filter-bar {
    align-items: end;
    flex-wrap: wrap;
    padding: 0.62rem;
    margin-bottom: 0.6rem;
    border: 1px solid var(--costing-line);
    border-radius: 0.9rem;
    background: var(--costing-soft);
  }

  label {
    display: grid;
    gap: 0.32rem;
    min-width: 10rem;
    font-size: 0.84rem;
    font-weight: 750;
  }

  label span {
    color: var(--costing-muted);
  }

  input,
  select {
    min-height: 2.4rem;
    width: 100%;
    padding: 0.55rem 0.65rem;
    border: 1px solid var(--costing-line-strong);
    border-radius: 0.66rem;
    background: var(--costing-input-bg);
    color: var(--costing-ink);
  }

  input:focus,
  select:focus {
    outline: none;
    border-color: var(--color-brand);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 18%, transparent);
  }

  .money-field {
    display: grid;
    grid-template-columns: 1.65rem minmax(0, 1fr);
    align-items: center;
    border: 1px solid var(--costing-line-strong);
    border-radius: 0.66rem;
    background: var(--costing-input-bg);
    overflow: hidden;
  }

  .money-field i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.4rem;
    color: var(--green-deep);
    background: color-mix(in srgb, var(--color-brand) 8%, var(--costing-panel));
    font-style: normal;
    font-weight: 850;
  }

  .money-field input {
    border: none;
    border-radius: 0;
    background: transparent;
  }

  .money-field:focus-within {
    border-color: var(--color-brand);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 18%, transparent);
  }

  .compact-field {
    min-width: 8.5rem;
  }

  .search-field {
    position: relative;
    flex: 1 1 18rem;
    min-width: min(100%, 18rem);
  }

  .search-field :global(svg) {
    position: absolute;
    left: 0.68rem;
    bottom: 0.68rem;
    color: var(--costing-muted);
  }

  .search-field input {
    padding-left: 2.05rem;
  }

  .page-size-field {
    min-width: 5.4rem;
  }

  .table-wrap {
    overflow-x: auto;
  }

  table {
    width: 100%;
    min-width: 72rem;
    border-collapse: separate;
    border-spacing: 0 0.36rem;
  }

  th,
  td {
    padding: 0.54rem 0.68rem;
    text-align: left;
    white-space: nowrap;
  }

  th {
    color: var(--costing-muted);
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  tbody tr {
    cursor: pointer;
  }

  tbody tr:hover td {
    background: color-mix(in srgb, var(--color-brand) 5%, var(--costing-soft));
  }

  tbody tr.active td {
    background: color-mix(in srgb, var(--color-brand) 9%, var(--costing-panel));
  }

  tbody tr.warn td {
    background: color-mix(in srgb, var(--costing-warn-row) 45%, var(--costing-panel));
  }

  tbody td {
    border-top: 1px solid var(--costing-line);
    border-bottom: 1px solid var(--costing-line);
    background: var(--costing-soft);
  }

  tbody td:first-child {
    border-left: 1px solid var(--costing-line);
    border-radius: 0.62rem 0 0 0.62rem;
  }

  tbody td:last-child {
    border-right: 1px solid var(--costing-line);
    border-radius: 0 0.62rem 0.62rem 0;
  }

  td strong,
  td small {
    display: block;
  }

  td strong {
    max-width: 18rem;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 0.88rem;
  }

  td small {
    margin-top: 0.08rem;
    font-size: 0.72rem;
  }

  .product-cell {
    min-width: 17rem;
  }

  .product-token {
    display: flex;
    align-items: center;
    gap: 0.58rem;
  }

  .product-token > span {
    width: 1.9rem;
    height: 1.9rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border-radius: 0.62rem;
    color: var(--green-deep);
    background: color-mix(in srgb, var(--color-brand) 13%, var(--costing-panel));
    font-size: 0.68rem;
    font-weight: 850;
  }

  .money {
    color: var(--green-deep);
  }

  .status-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.28rem 0.5rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 800;
  }

  .status-pill.positive {
    color: var(--green-deep);
    background: var(--green-soft);
  }

  .status-pill.warning {
    color: var(--costing-warn);
    background: var(--costing-warn-soft);
  }

  .skeleton-row td {
    cursor: progress;
  }

  .skeleton-lines {
    display: grid;
    gap: 0.24rem;
  }

  .empty-row td,
  .empty-row:hover td {
    padding: 1.4rem;
    text-align: center;
    background: var(--costing-soft);
  }

  .empty-row strong,
  .empty-row small {
    display: block;
  }

  .pagination-bar {
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.75rem;
    color: var(--costing-muted);
    font-size: 0.82rem;
    font-weight: 700;
  }

  .pagination-controls {
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.35rem;
  }

  .pagination-controls button {
    min-height: 2rem;
    padding: 0.38rem 0.58rem;
    border: 1px solid var(--costing-line);
    border-radius: 0.55rem;
    background: var(--costing-panel);
    color: var(--costing-ink);
    font-size: 0.78rem;
    font-weight: 800;
    cursor: pointer;
  }

  .pagination-controls button:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .pagination-controls strong {
    padding: 0 0.35rem;
    color: var(--costing-ink);
    font-size: 0.78rem;
  }

  .inspector {
    position: sticky;
    top: 1rem;
    max-height: calc(100vh - 2rem);
    overflow: auto;
    padding: 1rem;
  }

  .inspector-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.85rem;
    margin-bottom: 0.85rem;
  }

  .icon-button {
    width: 2.25rem;
    min-height: 2.25rem;
    border: 1px solid var(--costing-line);
    background: var(--costing-soft);
  }

  .warning-box {
    align-items: flex-start;
    padding: 0.78rem;
    margin-bottom: 0.85rem;
    border: 1px solid var(--costing-warn-border);
    border-radius: 0.82rem;
    color: var(--costing-warn);
    background: var(--costing-warn-box);
    font-size: 0.85rem;
    font-weight: 700;
  }

  .warning-box div {
    display: grid;
    gap: 0.25rem;
  }

  .price-stack {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.55rem;
    margin-bottom: 0.95rem;
  }

  .price-stack div,
  .breakdown-grid div,
  .empty-inspector {
    border: 1px solid var(--costing-line);
    border-radius: 0.78rem;
    background: var(--costing-soft);
  }

  .price-stack div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.7rem;
    padding: 0.7rem 0.78rem;
  }

  .price-stack strong {
    font-size: 1.12rem;
  }

  .inspector-section {
    padding-top: 0.9rem;
    margin-top: 0.9rem;
    border-top: 1px solid var(--costing-line);
  }

  .block-heading {
    display: grid;
    gap: 0.18rem;
    margin-bottom: 0.72rem;
  }

  .drawer-form,
  .input-grid,
  .input-columns,
  .breakdown-grid {
    display: grid;
    gap: 0.65rem;
  }

  .drawer-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .drawer-form .wide {
    grid-column: 1 / -1;
  }

  .breakdown-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .breakdown-grid div {
    padding: 0.68rem;
  }

  .breakdown-grid strong {
    margin-top: 0.12rem;
  }

  .empty-inspector {
    display: grid;
    justify-items: center;
    gap: 0.38rem;
    padding: 2rem 1rem;
    text-align: center;
  }

  .empty-inspector :global(svg) {
    color: var(--green-deep);
  }

  .inputs-panel {
    display: grid;
    gap: 0.9rem;
  }

  .input-block {
    padding: 0.92rem;
    border: 1px solid var(--costing-line);
    border-radius: 0.9rem;
    background: var(--costing-soft);
  }

  .input-grid.four {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .input-columns {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .input-list {
    display: grid;
    gap: 0.5rem;
  }

  .inline-field,
  .margin-row {
    display: grid;
    align-items: center;
    gap: 0.55rem;
  }

  .inline-field {
    grid-template-columns: minmax(0, 1fr) 8.5rem;
  }

  .inline-field input {
    text-align: right;
  }

  .inline-field > span {
    display: grid;
    gap: 0.12rem;
  }

  .inline-field small,
  label small {
    color: var(--costing-muted);
    font-size: 0.74rem;
    font-weight: 650;
  }

  .margin-table {
    display: grid;
    gap: 0.55rem;
  }

  .margin-row {
    grid-template-columns: minmax(12rem, 1fr) minmax(9rem, 0.7fr) minmax(9rem, 0.7fr);
    padding: 0.68rem;
    border: 1px solid var(--costing-line);
    border-radius: 0.76rem;
    background: var(--costing-panel);
  }

  .empty-state {
    display: grid;
    gap: 0.25rem;
    padding: 1rem;
    border: 1px solid var(--costing-line);
    border-radius: 0.82rem;
    background: var(--costing-soft);
  }

  @keyframes spin {
    to {
      transform: rotate(360deg);
    }
  }

  @media (max-width: 1240px) {
    .workspace-grid {
      grid-template-columns: 1fr;
    }

    .inspector {
      position: static;
      max-height: none;
    }
  }

  @media (max-width: 980px) {
    .page-head,
    .section-toolbar {
      flex-direction: column;
      align-items: flex-start;
    }

    .health-strip,
    .input-grid.four,
    .input-columns {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (max-width: 760px) {
    .health-strip,
    .input-grid.four,
    .input-columns,
    .drawer-form,
    .margin-row,
    .breakdown-grid {
      grid-template-columns: 1fr;
    }

    .head-actions,
    .filter-bar,
    .pagination-bar {
      width: 100%;
    }

    .head-actions .primary-button,
    .filter-bar label {
      width: 100%;
    }

    .pagination-bar,
    .pagination-controls {
      align-items: stretch;
      flex-direction: column;
    }

    .pagination-controls {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .pagination-controls strong {
      grid-column: 1 / -1;
      text-align: center;
    }

    table,
    thead,
    tbody,
    tr,
    td {
      display: block;
      width: 100%;
    }

    table {
      min-width: 0;
      border-spacing: 0;
    }

    thead {
      display: none;
    }

    tbody {
      display: grid;
      gap: 0.78rem;
    }

    tbody tr {
      padding: 0.35rem;
      border: 1px solid var(--costing-line);
      border-radius: 0.9rem;
      background: var(--costing-soft);
    }

    tbody td,
    tbody td:first-child,
    tbody td:last-child {
      padding: 0.74rem 0.78rem;
      white-space: normal;
      border: none;
      border-radius: 0;
      background: transparent;
    }

    tbody td + td {
      border-top: 1px solid var(--costing-line);
    }

    tbody td::before {
      content: attr(data-label);
      display: block;
      margin-bottom: 0.34rem;
      color: var(--costing-muted);
      font-size: 0.72rem;
      font-weight: 800;
      letter-spacing: 0.06em;
      text-transform: uppercase;
    }

    td strong {
      max-width: none;
    }

    .product-cell {
      min-width: 0;
    }
  }
</style>
