@php $money = fn ($v) => number_format((float) $v, 2); $signed = fn ($v) => (float) $v >= 0 ? 'text-emerald-600' : 'text-rose-600'; // Status pill palette (On Track / At Risk / Behind). $toneChip = [ 'good' => 'bg-emerald-50 text-emerald-700 ring-emerald-600/15', 'warn' => 'bg-amber-50 text-amber-700 ring-amber-600/15', 'bad' => 'bg-rose-50 text-rose-700 ring-rose-600/15', 'neutral' => 'bg-slate-100 text-slate-600 ring-slate-500/15', ]; // Heatmap cell palette by band. $heat = [ 'high' => 'bg-emerald-100 text-emerald-800', 'med' => 'bg-amber-100 text-amber-800', 'low' => 'bg-rose-100 text-rose-800', ]; // Build an SVG polyline from a value series (auto-scaled to the box). $spark = function (array $vals, int $w = 120, int $h = 34): string { $vals = array_values(array_map('floatval', $vals)); if (count($vals) < 2) { return ''; } $min = min($vals); $max = max($vals); $range = ($max - $min) ?: 1; $n = count($vals) - 1; $pts = []; foreach ($vals as $i => $v) { $x = $i / $n * $w; $y = $h - (($v - $min) / $range) * ($h - 4) - 2; $pts[] = round($x, 1) . ',' . round($y, 1); } return implode(' ', $pts); }; // Donut-gauge arc path (r chosen so circumference ≈ 100 → dasharray = pct). $arc = 'M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831'; $payColors = ['paid' => 'emerald', 'partial' => 'sky', 'overdue' => 'rose', 'unpaid' => 'slate', 'void' => 'slate']; $commColors = ['fully_paid' => 'emerald', 'deposit_paid' => 'sky', 'not_funded' => 'slate']; // The three page sections. $tabMeta = [ 'summary' => ['label' => __('Profit Summary'), 'icon' => 'chart-bar'], 'jobs' => ['label' => __('Job Profitability'), 'icon' => 'briefcase'], 'costs' => ['label' => __('Cost & Margin'), 'icon' => 'calculator'], ]; // Month-by-month table: how each line of the statement is drawn. $rowStyle = [ 'plain' => ['label' => 'text-slate-600', 'value' => 'text-slate-600', 'row' => '', 'bg' => 'bg-white'], 'deduct' => ['label' => 'pl-5 text-slate-500', 'value' => 'text-slate-500', 'row' => '', 'bg' => 'bg-white'], 'subtotal' => ['label' => 'font-semibold text-slate-800', 'value' => 'font-semibold text-slate-900', 'row' => 'border-t border-slate-200', 'bg' => 'bg-white'], 'total' => ['label' => 'font-bold text-slate-900', 'value' => 'font-bold', 'row' => 'border-t-2 border-slate-300 bg-slate-50/70', 'bg' => 'bg-slate-50'], 'memo' => ['label' => 'text-slate-400', 'value' => 'text-slate-400', 'row' => '', 'bg' => 'bg-white'], ]; @endphp
{{-- ===================================================================== Header + period ===================================================================== --}} {{ __('Export') }} {{-- Filters (custom range + drill-down) --}}
{{ __('Reset') }}
{{-- ===================================================================== Headline cards, ACCRUAL basis. Cash collected is not among them by design: it is a receivables event, not an earnings one. ===================================================================== --}}

{{ __('Profit Headlines') }}

{{ __('Accrual basis · revenue recognised') }}
{{ $periodLabel }} {{ $company['health_label'] }}
@foreach ($summaryCards as $card) @if ($card['type'] === 'money')

{{ $card['label'] }}

@if ($card['sub'])

{{ $card['sub'] }}

@endif

{{ $card['value'] }}

@if ($card['target'])

{{ $card['target'] }} · {{ $card['pct'] }}% {{ $card['pct_caption'] }}

@endif @if ($card['delta'] !== null) {{ number_format(abs($card['delta']), 1) }}% {{ __('vs last month') }} @endif @if (! empty($card['spark'])) @endif @if ($card['status']) {{ $card['status']['label'] }} @endif @else {{-- margin card: radial gauge --}}

{{ $card['label'] }}

{{ $card['value'] }}
@if ($card['delta_pp'] !== null)

{{ $card['delta_pp'] >= 0 ? '+' : '−' }}{{ number_format(abs($card['delta_pp']), 1) }}pp {{ __('vs last month') }}

@endif @endif
@endforeach
{{-- ===================================================================== Section tabs ===================================================================== --}}
@foreach ($tabMeta as $key => $meta) @endforeach
{{-- ===================================================================== TAB 1 · PROFIT SUMMARY ===================================================================== --}} @if ($tab === 'summary') {{-- Revenue basis: billed → earned → banked → owed. The one panel that keeps the four figures from being read as the same number. --}}

{{ __('Revenue Basis & Receivables') }}

{{ __('What was billed, what was earned, what was banked and what is still owed.') }}

{{ __('Only recognised revenue drives profit') }}
{{-- The bridge --}}
@php $bridge = [ ['label' => __('Amount Invoiced'), 'note' => __('billed in the period'), 'value' => $revenueBasis['invoiced'], 'display' => $revenueBasis['invoiced_label'], 'bar' => 'bg-violet-400', 'strong' => false], ['label' => __('less Credits & Refunds'), 'note' => __('sales reversed'), 'value' => $revenueBasis['contra'], 'display' => '(' . $money($revenueBasis['contra']) . ')', 'bar' => 'bg-rose-300', 'strong' => false], ['label' => __('Revenue Recognised'), 'note' => __('earned in the period'), 'value' => $revenueBasis['recognised'], 'display' => $revenueBasis['recognised_label'], 'bar' => 'bg-brand-500', 'strong' => true], ]; @endphp @foreach ($bridge as $step)
{{ $step['label'] }} {{ $step['note'] }} {{ $step['display'] }}
{{-- A negative step (a month whose credits outran its invoicing) goes rose, or a full-width bar would read as a big positive. --}}
@endforeach

{{ __('Gross and net profit on this page are recognised revenue less costs.') }} {{ __('Cash collected measures collections, not trading, so it sits on the right with the other receivables figures. Amount invoiced is what was billed and is not revenue until credits and refunds come off it.') }} {{ __('The GP hurdle and commission pool below deliberately stay on collected cash, which is the basis the workspace pays commission on.') }}

{{-- Cash & receivables (moved off the profit headline) --}}

{{ __('Cash & Receivables') }}

@foreach ($cashCards as $c)

{{ $c['label'] }}

{{ $c['sub'] }}

{{ $c['value'] }}

@if ($c['delta'] !== null)

{{ $c['delta'] >= 0 ? '+' : '−' }}{{ number_format(abs($c['delta']), 1) }}%

@endif
@endforeach
{{-- Profit variance: growth vs prior periods + attainment vs target --}} @php $hasVarianceTargets = collect($variance)->contains(fn (array $r): bool => $r['target_display'] !== null); @endphp
@unless ($hasVarianceTargets)

{{ __('The vs Target columns are empty because no monthly target is set for these metrics.') }} {{ __('Set one on Targets') }} {{ __('and they fill in here automatically.') }}

@endunless
{{-- Month-by-month comparison (the spreadsheet view) --}}

{{ __('Month-by-Month Profit Statement') }}

{{ __('Every line of the statement, one column per month, on the recognised-revenue basis.') }}

@foreach ($monthlyCompare['options'] as $opt) @endforeach
@foreach ($monthlyCompare['months'] as $m) @endforeach @foreach ($monthlyCompare['rows'] as $r) @php $st = $rowStyle[$r['style']] ?? $rowStyle['plain']; $isDeduct = $r['style'] === 'deduct'; $fmt = function ($v) use ($r, $isDeduct, $money) { if ($r['kind'] === 'percent') { return number_format((float) $v, 1) . '%'; } return $isDeduct && (float) $v >= 0 ? '(' . $money($v) . ')' : $money($v); }; // Money subtotals/totals go green/red with their sign; everything // else keeps the row's own muted tone. $tone = fn ($v) => in_array($r['style'], ['subtotal', 'total'], true) && $r['kind'] === 'money' ? $signed($v) : ($r['kind'] === 'percent' && in_array($r['style'], ['subtotal', 'total'], true) ? $signed($v) : ''); @endphp @foreach ($r['values'] as $v) @endforeach @endforeach
{{ __('Line') }}{{ $m['label'] }}{{ __('Total') }} {{ __('Avg/mo') }}
{{ $r['label'] }} @if ($r['note']) @endif {{ $fmt($v) }}{{ $fmt($r['total']) }} {{ $fmt($r['avg']) }}

{{ __('All amounts in :code. Deductions are shown in brackets.', ['code' => $monthlyCompare['base']]) }} {{ __('For the percentage lines, Total is the weighted figure for the whole span (e.g. total gross profit ÷ total recognised revenue) while Avg/mo is the plain average of the monthly percentages — the two differ whenever the months are of different sizes.') }} {{ __('Memo lines are cash-flow measures shown for reference; they take no part in the profit above them.') }}

{{-- Health score + GP hurdle / commission status --}}

{{ __('Profit Health Score') }}

{{ $healthScore['score'] }} /100

{{ $healthScore['label'] }}

{{ $healthScore['note'] }}

{{ __('GP Hurdle & Commission Status') }}

{{ __('Cash basis · the basis commission is paid on') }}
{{-- Track: 0 → break-even → hurdle, with the actual-GP fill --}}
{{ __('Break-even') }}
{{ $baseCode }} {{ $money($gpStatus['break_even']) }}
{{ __('GP Hurdle') }}
{{ $baseCode }} {{ $money($gpStatus['hurdle']) }}
{{ __('Actual GP (cash)') }}: {{ $baseCode }} {{ $money($gpStatus['actual_gp']) }} {{ $gpStatus['progress'] }}%
@foreach ([ ['l' => __('Break-even GP'), 'v' => $gpStatus['break_even'], 's' => false], ['l' => __('GP Hurdle'), 'v' => $gpStatus['hurdle'], 's' => false], ['l' => __('Actual GP'), 'v' => $gpStatus['actual_gp'], 's' => false], ['l' => __('Excess GP'), 'v' => $gpStatus['excess_gp'], 's' => true], ] as $mini)

{{ $mini['l'] }}

{{ $baseCode }} {{ $money($mini['v']) }}

@endforeach

{{ $gpStatus['above_break_even'] ? __('Above Break-even') : __('Below Break-even') }} · {{ $gpStatus['commission_active'] ? __('Commission Eligible') : __('Not Yet Commission Eligible') }}

{{ __('Commission Status') }}

{{ $gpStatus['commission_active'] ? __('Eligible') : __('Not Eligible') }}

{{ __('Commission Pool') }}

{{ $baseCode }} {{ $money($gpStatus['commission_pool']) }}

{{ __('Pool Rate') }} {{ rtrim(rtrim(number_format($gpStatus['pool_rate_pct'], 1), '0'), '.') }}%
@if ($gpStatus['commission_pool'] > 0)
{{ __('Sales / Prod') }} {{ $money($gpStatus['sales_pool']) }} / {{ $money($gpStatus['production_pool']) }}
@endif
{{-- Waterfall + the merged profit & margin trend --}}

{{ __('Profit Waterfall') }} ({{ $baseCode }})

{{ __('How the amount invoiced becomes net profit.') }}

{{-- One chart: money on the left axis, margins on the right. --}}

{{ __('Profit & Margin Trend') }}

{{ __('Recognised revenue, gross and net profit against the margins they produced (12 months).') }}

{{-- Forecast + data quality --}}

{{ __('Profit Forecast') }}

{{ __('Run-rate · :p% elapsed', ['p' => $forecast['elapsed_pct']]) }}

{{ __('Projected to period end at the current pace.') }}

@foreach ([ ['l' => __('Projected Revenue Recognised'), 'v' => $forecast['revenue'], 'memo' => false], ['l' => __('Projected Gross Profit'), 'v' => $forecast['gross_profit'], 'memo' => false], ['l' => __('Projected Net Profit'), 'v' => $forecast['net_profit'], 'memo' => false], ['l' => __('Projected Cash Collected'), 'v' => $forecast['cash'], 'memo' => true], ['l' => __('Projected Commission Pool'), 'v' => $forecast['commission_pool'], 'memo' => true], ] as $f)
{{ $f['l'] }} @if ($f['memo']) {{ __('cash') }} @endif {{ $baseCode }} {{ $money($f['v']) }}
@endforeach
{{ __('Forecast Confidence') }} {{ $forecast['confidence_label'] }} ({{ $forecast['confidence'] }}%)

{{ __('Data Quality') }}

{{ __('Gaps that would make the figures above understate the truth.') }}

@if (empty($warnings))
{{ __('No data issues for this period.') }}
@else
@foreach ($warnings as $w)
{{ $w['count'] }} {{ $w['label'] }}
@endforeach
@endif
{{-- ===================================================================== TAB 2 · JOB PROFITABILITY ===================================================================== --}} @elseif ($tab === 'jobs') @unless ($hasData) @else
{{-- Top 10 most profitable jobs --}}

{{ __('Top Profitable Jobs') }}

{{ __('Job-costing basis: each job\'s own line items and actual costs.') }}

@forelse ($topJobs as $i => $row) @empty @endforelse
# {{ __('Job') }} {{ __('Customer') }} {{ __('Invoiced') }} {{ __('GP') }} {{ __('Margin') }}
{{ $i + 1 }} {{ $row['job_number'] }} {{ \Illuminate\Support\Str::limit($row['customer'], 18) }} {{ $baseCode }} {{ $money($row['invoice_value']) }} {{ $baseCode }} {{ $money($row['profit']) }} {{ number_format($row['margin'], 1) }}%
{{ __('No revenue-generating jobs in range.') }}
{{-- Profit leaks --}}

{{ __('Profit Leaks') }}

{{ __('Attention required.') }}

@foreach ($profitLeaks as $leak)
{{ $leak['label'] }} @if (! empty($leak['pending'])) {{ __('Soon') }} @else {{ $leak['jobs'] }} {{ trans_choice('{1}job|[0,2,*]jobs', $leak['jobs']) }} @if ($leak['amount'] != 0.0) {{ $baseCode }} {{ $money($leak['amount']) }} @endif @endif
@endforeach
{{ __('View all profit leaks') }}
{{-- Rework impact (S8, Production metrics) --}}

{{ __('Rework Impact Analysis') }}

@if ($rework['high_rework']) {{ __('High rework') }} @else {{ __('Within threshold') }} @endif

{{ __('Reworked Jobs') }}

{{ $rework['rework_jobs'] }}

{{ __('of :n completed', ['n' => $rework['cohort']]) }}

{{ __('Rework Rate') }}

{{ number_format($rework['rework_pct'], 1) }}%

{{ __('threshold :t%', ['t' => number_format($rework['threshold_pct'], 0)]) }}

{{ __('Total Reworks') }}

{{ $rework['rework_count'] }}

{{ __('reprints logged') }}

{{ __('Cost Overrun') }}

{{ $rework['overrun_label'] }}

{{ __('on reworked jobs') }}

{{-- Overhead absorption → net profit per job (G9, FRS §3) --}}

{{ __('Overhead Absorption → Net Profit per Job') }}

{{ __('The period\'s overhead nut spread over the jobs that consumed it, so every job carries a net profit and not only a gross one.') }}

{{ __('Basis') }}: {{ $absorption['basis_label'] }} @if ($absorption['reconciles']) {{ __('Reconciled') }} @else {{ __('Does not reconcile') }} @endif

{{ __('Period Overheads') }}

{{ $absorption['overheads_label'] }}

{{ __('the nut being absorbed') }}

{{ __('Allocated to Jobs') }}

{{ $absorption['allocated_label'] }}

{{ $absorption['unallocated'] > 0.005 ? __(':amount unallocated (no job activity)', ['amount' => $absorption['unallocated_label']]) : __('adds up to the overhead line exactly') }}

{{ $absorption['is_labour_basis'] ? __('Absorption Rate') : __('Allocation Driver') }}

{{ $absorption['rate_label'] ?? __('Revenue share') }}

@if ($absorption['is_labour_basis']) {{ __(':driver driver hours (:logged logged)', ['driver' => number_format($absorption['driver_hours'], 1), 'logged' => number_format($absorption['logged_hours'], 1)]) }} @elseif ($absorption['degraded_to_revenue']) {{ __('no time logged this period — fell back to sale value') }} @else {{ __('sharing the nut by sale value') }} @endif

{{ __('Jobs Carrying Overhead') }}

{{ $absorption['jobs'] }}

{{ $absorption['imputed_jobs'] > 0 ? __(':n with no timesheet (hours estimated from revenue)', ['n' => $absorption['imputed_jobs']]) : __('all with logged time') }}

{{-- The honesty line. This figure gets used to judge staff and price work, so the screen must never let it be mistaken for cash. --}}

{{ __('Per-job net profit is a management allocation, not a cash fact.') }} {{ __('A job\'s absorbed overhead is its share of a company-wide nut (rent, salaries, depreciation) that would have been paid whether the job existed or not. No money left the business "for this job". Read it as: of the capacity we paid for this period, this job used roughly this much.') }}

@if ($absorption['is_partial'])

{{ __('The :n job(s) listed below carry :visible of the :total allocated.', [ 'n' => $absorption['visible_jobs'], 'visible' => $absorption['visible_label'], 'total' => $absorption['allocated_label'], ]) }} {{ $absorption['is_filtered'] ? __('A filter is active, so the rest sits on jobs outside it.') : __('The rest sits on jobs opened in an earlier period that were still being worked on during this one — the table lists jobs by the date they were opened.') }}

@endif
{{-- Full per-job table (§16) --}} @php $isJobGroup = $groupBy === 'job'; @endphp

{{ $isJobGroup ? __('All Jobs, Profit Detail') : __('Profitability by Category') }}

{{ __('Job-costing basis (own line items + actual costs).') }}

@foreach (['job' => __('By job'), 'category' => __('By category')] as $key => $label) @endforeach
@if ($isJobGroup)
@endif
@if ($isJobGroup) {{-- G9: allocated, not spent. The caption under the table says so. --}} @foreach ($jobRows as $row) {{-- Job-level P&L drill-down (G9). Same ladder the job's Costs & Materials tab shows, from the same service. --}} @endforeach
{{ __('Job') }} {{ __('Status') }} {{ __('Payment') }} {{ __('Invoiced') }} {{ __('Paid') }} {{ __('Cash') }} {{ __('Est. Cost') }} {{ __('Actual Cost') }} {{ __('Gross Profit') }} {{ __('Margin') }}{{ __('Overhead') }} {{ __('Net Profit') }} {{ __('Comm.') }} {{ __('Flags') }}
{{-- Expands the job-level P&L ladder: revenue → direct costs → gross profit → absorbed overhead → net profit. --}}
{{ $row['job_number'] }}
{{ \Illuminate\Support\Str::limit($row['customer'].' · '.$row['title'], 36) }}
{{ $row['status_label'] }} {{ $row['commercial_label'] }}
@if ($row['payment_status']) {{ ucfirst($row['payment_status']) }} @else — @endif {{ $row['invoice_value'] > 0 ? $baseCode.' '.$money($row['invoice_value']) : '—' }} {{ $baseCode }} {{ $money($row['amount_paid']) }} {{ $baseCode }} {{ $money($row['cash_collected']) }} {{ $row['has_estimate'] ? $baseCode.' '.$money($row['estimated_cost']) : '—' }} {{ $baseCode }} {{ $money($row['actual_cost']) }} {{ $baseCode }} {{ $money($row['profit']) }} {{ number_format($row['margin'], 1) }}% @if ($row['absorbed_overhead'] > 0) {{ $baseCode }} {{ $money($row['absorbed_overhead']) }} @if ($row['overhead_imputed']) {{ __('est. hours') }} @endif @else — @endif {{ $baseCode }} {{ $money($row['net_profit']) }} {{ number_format($row['net_margin'], 1) }}% @if ($row['commission_eligible'] === true) {{ __('Eligible') }} @elseif ($row['commission_eligible'] === false) {{ __('No') }} @else — @endif @if (empty($row['flags'])) — @else
@foreach ($row['flags'] as $flag) {{ $flag['label'] }} @endforeach
@endif

{{ __('Job P&L') }} · {{ $row['job_number'] }}

{{ __('Revenue (attributable)') }}
{{ $baseCode }} {{ $money($row['revenue']) }}
{{ __('less Materials & other direct costs') }}
({{ $money($row['materials']) }})
{{ __('less Direct labour') }}
({{ $money($row['labour']) }})
{{ __('Gross Profit') }}
{{ $baseCode }} {{ $money($row['profit']) }}
{{ __('less Absorbed overhead') }} {{ $absorption['basis_label'] }}@if ($absorption['is_labour_basis'] && $row['overhead_hours'] > 0) · {{ number_format($row['overhead_hours'], 1) }} {{ __('hrs') }} × {{ $absorption['rate_label'] }}@endif
({{ $money($row['absorbed_overhead']) }})
{{ __('Net Profit') }}
{{ $baseCode }} {{ $money($row['net_profit']) }}

{{ __('Absorbed overhead is a management allocation, not a cash fact.') }} {{ __('It is this job\'s share of the period nut, not money the job spent.') }}

@if ($row['overhead_imputed'])

{{ __('No time was logged on this job, so its hours were estimated from its revenue. Logging time makes the share accurate.') }}

@endif @if ($row['provisional'])

{{ __('This job is still live work — its share will move as more time and cost land on it.') }}

@endif

{{ __('Per-job figures use each job\'s own line items + actual costs (job-costing basis), separate from the company summary above. Invoiced / paid / cash are invoice-level, so jobs sharing one invoice show that invoice\'s figures.') }} {{ __('Overhead is allocated, not spent: it is the job\'s share of the period nut, so Net Profit is a management allocation rather than a cash fact. Expand a row for the full ladder.') }} @if ($hasActivePlans) {{ __('Commission eligibility reflects the workspace\'s active commission model.') }} @endif

@else @foreach ($byCategory as $row) @endforeach
{{ __('Category') }} {{ __('Jobs') }} {{ __('Revenue') }} {{ __('Cost') }} {{ __('Profit') }} {{ __('Margin') }}
{{ $row['category'] }} {{ $row['jobs'] }} {{ $baseCode }} {{ $money($row['revenue']) }} {{ $baseCode }} {{ $money($row['cost']) }} {{ $baseCode }} {{ $money($row['profit']) }} {{ number_format($row['margin'], 1) }}%
@endif
{{-- Top customers by GP --}}

{{ __('Top Customers by Gross Profit') }}

@forelse ($topCustomers as $c) @empty @endforelse
{{ __('Customer') }} {{ __('Revenue') }} {{ __('GP') }} {{ __('Margin') }} {{ __('Jobs') }}
{{ \Illuminate\Support\Str::limit($c['customer'], 28) }} {{ $baseCode }} {{ $money($c['revenue']) }} {{ $baseCode }} {{ $money($c['gp']) }} {{ number_format($c['margin'], 1) }}% {{ $c['jobs'] }}
{{ __('No customer profit in range.') }}
@endunless {{-- ===================================================================== TAB 3 · COST & MARGIN ===================================================================== --}} @else
{{-- Cost breakdown donut --}}

{{ __('Cost Breakdown') }}

@if ($costDonut->isEmpty())

{{ __('No costs in range.') }}

@else
@foreach ($costDonut as $slice)
{{ $slice['label'] }} {{ $slice['pct'] }}%
@endforeach
@endif
{{-- Cost trend --}}

{{ __('Cost Trend Over Time') }} ({{ $baseCode }})

{{ __('Direct costs against the overhead nut, 12 months.') }}

{{-- Cost variance --}}

{{ __('Cost Variance') }}

@if ($costVariance['has_data'])
{{ __('Estimated') }} {{ $baseCode }} {{ $money($costVariance['estimated']) }}
{{ __('Actual') }} {{ $baseCode }} {{ $money($costVariance['actual']) }}
{{ __('Variance') }} {{ $baseCode }} {{ $money($costVariance['variance']) }}

{{ $costVariance['pct'] > 0 ? '+' : '' }}{{ number_format($costVariance['pct'], 1) }}%

{{ $costVariance['pct'] <= 0 ? __('Under budget') : __('Over budget') }} · {{ $costVariance['jobs'] }} {{ __('jobs') }}

@else

{{ __('No jobs with a cost estimate in range.') }}

@endif
{{-- Category profitability heatmap --}}

{{ __('Category Profitability Heatmap') }}

{{ __('Where the profit is, banded against the rest of the set.') }}

@if (empty($heatmap))

{{ __('No category data in range.') }}

@else
@foreach ($heatmap as $h) @foreach (['revenue', 'cost', 'gp', 'margin'] as $col) @endforeach @endforeach
{{ __('Category') }} {{ __('Revenue') }} {{ __('Cost') }} {{ __('GP') }} {{ __('Margin') }}
{{ $h['category'] }} {{ $col === 'margin' ? number_format($h['margin_pct'], 0) . '%' : __(ucfirst($h[$col])) }}
{{ __('High') }} {{ __('Medium') }} {{ __('Low') }}
@endif
@endif

{{ __('All amounts are in :code and converted to your base currency. Gross and net profit are on the accrual basis (revenue recognised less costs); cash collected, receivables and the commission ladder are cash-basis and labelled where they appear. Per-job figures use job costing.', ['code' => $baseCode]) }}