JSFiddle - React, Tailwind, and code Playground

HTML

<div ng-app>
    <h2>Delegate Salary Calculator</h2>

    <div ng-controller="DelegateCtrl" ng-init="reload()">
        <form ng-submit="reload()">
            <input type="submit" value="Reload fresh data" />
        </form>
        <div>
            <table>
                <tr>
                    <td>BitUSD price feed:</td>
                    <td>{{feedPrice}} USD/BTS</td>
                </tr>
                <tr>
                    <td>Basic delegate salary:</td>
                    <td>
                        <input type="text" size="3" ng-model="basicSalary" ng-blur="updateSalary()" />USD/round (${{salaryRoundToWeek(basicSalary)}}/week)</td>
                </tr>
                <tr>
                    <td>Maximum inflation per round:</td>
                    <td>
                        <input type="text" size="3" ng-model="maxRewardPerRound" ng-blur="updateSalary()" />BTS</td>
                </tr>
                <tr>
                    <td>Maximum budget per round:</td>
                    <td>${{maxRoundBudget()}} (${{salaryRoundToWeek(maxRoundBudget())}}/week)</td>
                </tr>
                <tr>
                    <td>Median approval:</td>
                    <td>{{medianApproval}}%</td>
                </tr>
                <tr>
                    <td>Salary limit on bottom half delegates:</td>
                    <td>${{salaryLimit}}/round (${{salaryRoundToWeek(salaryLimit)}}/week)</td>
                </tr>
            </table>
        </div>
        <p>
            Actual salary is colored black if the delegate's full requested salary will be received. It is colored <span class="limitedSalary">orange</span> if the full requested salary will not be received, and it is colored <span class="basicSalary">red</span> if the actual salary to be received is no greater than the basic salary. Also, the values have a &#x26a0; icon appended if the requested salary is limited because of the salary restrictions (which are a function of the...

CSS

.standard-table {
    margin:0px;
    padding:0px;
    width:100%;
    border:1px solid #000000;
}
.standard-table table {
    border-collapse: collapse;
    border-spacing: 0;
    width:100%;
    height:100%;
    margin:0px;
    padding:0px;
}
.standard-table tr:nth-child(odd) {
    background-color:#aad4ff;
}
.standard-table tr:nth-child(even) {
    background-color:#ffffff;
}
.standard-table td {
    vertical-align:middle;
    border:1px solid #000000;
    border-width:0px 1px 1px 0px;
    text-align:left;
    padding:7px;
    font-size:10px;
    font-family:Arial;
    font-weight:normal;
    color:#000000;
}
.standard-table tr:last-child td {
    border-width:0px 1px 0px 0px;
}
.standard-table tr td:last-child {
    border-width:0px 0px 1px 0px;
}
.standard-table tr:last-child td:last-child {
    border-width:0px 0px 0px 0px;
}
.standard-table tr:first-child th {
    background:-o-linear-gradient(bottom, #005fbf 5%, #003f7f 100%);
    background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #005fbf), color-stop(1, #003f7f));
    background:-moz-linear-gradient(center top, #005fbf 5%, #003f7f 100%);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#005fbf", endColorstr="#003f7f");
    background: -o-linear-gradient(top, #005fbf, 003f7f);
    background-color:#005fbf;
    border:0px solid #000000;
    text-align:center;
    border-width:0px 0px 1px 1px;
    font-size:14px;
    font-family:Arial;
    font-weight:bold;
    color:#ffffff;
}
.standard-table tr:first-child:hover th {
    background:-o-linear-gradient(bottom, #005fbf 5%, #003f7f 100%);
    background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #005fbf), color-stop(1, #003f7f));
    background:-moz-linear-gradient(center top, #005fbf 5%, #003f7f 100%);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#005fbf", endColorstr="#003f7f");
    background: -o-linear-gradient(top, #005fbf, 003f7f);
   ...

JavaScript

function DelegateCtrl($scope, $http) {
    var delegateAPI = "http://www.bitsharesblocks.com:2095/api/activedelegates?callback=JSON_CALLBACK";
    var USDAPI = "http://www.bitsharesblocks.com:2095/api/assets/USD?callback=JSON_CALLBACK";
    var roundsPerWeek = 60480.0 / 101;

    $scope.feedPrice = 0.0;
    $scope.medianApproval = 0.0;
    $scope.salaryLimit = 0.0;
    $scope.delegates = [];
    $scope.basicSalary = 0.03;
    $scope.maxRewardPerRound = 5050.0;

    $scope.updateSalary = function () {
        var maxBudget = parseFloat($scope.maxRoundBudget());
        var workingBudget = 0.0;
        var topHalfRequestedSalaries = [];
        var extraSalaries = [];
        var basicSalary = parseFloat($scope.basicSalary);
        
        for (i = 0; i < Math.floor($scope.delegates.length/2); ++i) {
            var sal = parseFloat($scope.delegates[i].requestedSalary);
            topHalfRequestedSalaries.push(sal);
            extraSalaries.push(Math.max(0.0, sal - basicSalary));
            sal = Math.min(sal, basicSalary);
            workingBudget += sal;
            $scope.delegates[i].actualSalary = sal;
            $scope.delegates[i].salaryClass = "basicSalary";
        }
        
        topHalfRequestedSalaries.sort( function(a,b) {return a - b;} );
        var medianIndx = Math.floor(topHalfRequestedSalaries.length/2);
        if(topHalfRequestedSalaries.length % 2 != 0) {
            $scope.salaryLimit = (topHalfRequestedSalaries[medianIndx]).toFixed(2);
        } else {
            $scope.salaryLimit = ((topHalfRequestedSalaries[medianIndx-1] + topHalfRequestedSalaries[medianIndx]) / 2.0).toFixed(2);
        }
        
        for (i = Math.floor($scope.delegates.length/2); i < $scope.delegates.length; i++) {
            var sal = parseFloat($scope.delegates[i].requestedSalary);
            var limit = $scope.f(parseFloat($scope.delegates[i].approval) / parseFloat($scope.medianApproval)) * parseFloat($scope.salaryLimit);
            if (sal > limit)...