#############################################################################
# Templates for various files written by the phyloacc interface
#############################################################################

def phyloaccConfig():

    phyloacc_template = """PHYTREE_FILE {mod_file}
SEG_FILE {bed_file}{id_line}
ALIGN_FILE {aln_file}
RESULT_FOLDER {outdir}{coal_tree_line}
PREFIX {batch}
THIN {thin}
BURNIN {burnin}
MCMC {mcmc}
CHAIN {chain}
TARGETSPECIES {targets}
{outgroup}
CONSERVE {conserved}
NUM_THREAD {procs_per_job}
{phyloacc_opts}
{dollo_str}
"""

    return phyloacc_template;

#############################################################################

def snakemake():

    smk_template = """#############################################################################
# Pipeline for running phyloacc batches
# Generated from: {cmd}
# On: {dt}
#############################################################################

#############################################################################

import os 

#############################################################################

IQTREEDIR = config["iqtree_directory"];
ASTRALDIR = config["astral_directory"];

INDIR = config["input_directory"];
OUTDIR = config["output_directory"];
ST_BATCHES = config["st_batch_list"];
GT_BATCHES = config["gt_batch_list"];
# Inputs for the snakemake pipeline are read from the config file generated by
# the interface

#############################################################################

iqtree_loci = [];
{theta_char}iqtree_loci = [ f.replace(".fa", "") for f in os.listdir(os.path.join(IQTREEDIR, "alns")) if f.endswith(".fa") ];
# Reads the alignments to make trees from if --theta is specified

#############################################################################
# Final rule - rule that depends on final expected output file and initiates all
# the other rules

localrules: all

rule all:
    input:
        {theta_char}expand(os.path.join(IQTREEDIR, "gene-trees", "{{locus}}", "{{locus}}.treefile"), locus=iqtree_loci),
        {theta_char}os.path.join(IQTREEDIR, "gene-trees", "all-gene-trees.treefile"),
        {theta_char}"{unlabeled_coal_tree_path}",
        {theta_char}"{coal_tree_path}",
        {phyloacc_char}expand(os.path.join(OUTDIR, "{{st_batch}}-phyloacc-st-out", "{{st_batch}}_elem_lik.txt"), st_batch=ST_BATCHES),
        {phyloacc_char}expand(os.path.join(OUTDIR, "{{gt_batch}}-phyloacc-gt-out", "{{gt_batch}}_elem_lik.txt"), gt_batch=GT_BATCHES)
# This rule checks for expected outputs from the rules
# With --theta, a coalescent tree will be estimated with IQTree and ASTRAL, but without --theta these outputs
# are commented and those rules will not be run.

#############################################################################
# Pipeline rules

rule run_iqtree:
    input:
        os.path.join(IQTREEDIR, "alns", "{{locus}}.fa")
    output:
       os.path.join(IQTREEDIR, "gene-trees", "{{locus}}", "{{locus}}.treefile")
    params:
        locus=os.path.abspath(os.path.join(IQTREEDIR, "gene-trees", "{{locus}}", "{{locus}}"))
    log:
        os.path.join(IQTREEDIR, "gene-trees", "{{locus}}", "{{locus}}.log")
    resources:
        cpus=1    
    shell:
        \"\"\"
        {iqtree_path} -s {{input}} --prefix {{params.locus}} -T {{resources.cpus}} -redo &> {{log}}
        \"\"\"    

rule combine_gene_trees:
    input:
        gene_trees = expand(os.path.join(IQTREEDIR, "gene-trees", "{{locus}}", "{{locus}}.treefile"), locus=iqtree_loci),
        gene_tree_dir = os.path.join(IQTREEDIR, "gene-trees")
    output:
        os.path.join(IQTREEDIR, "gene-trees", "all-gene-trees.treefile")
    shell:
        \"\"\"
        cat {{input.gene_tree_dir}}/*/*.treefile > {{output}}
        \"\"\"

rule run_astral:
    input:
        gene_trees = os.path.join(IQTREEDIR, "gene-trees", "all-gene-trees.treefile"),
        species_tree = os.path.join(ASTRALDIR, "input-species-tree.treefile")
    output:
        "{unlabeled_coal_tree_path}"
    log:
        os.path.join(ASTRALDIR, "astral-species-tree.log")
    shell:
        \"\"\"
        {astral_path} -q {{input.species_tree}} -i {{input.gene_trees}} -o {{output}} &> {{log}}
        \"\"\"

rule label_astral_tree:
    input:
        species_tree = os.path.join(ASTRALDIR, "input-species-tree.treefile"),
        astral_tree = "{unlabeled_coal_tree_path}"
    output:
        "{coal_tree_path}"
    log:
        os.path.join(ASTRALDIR, "astral-label-tree.log")
    shell:
        \"\"\"
        chmod +x {label_script}
        {label_script}
        \"\"\"
        
# The above rules estimate a tree with branch lengths in coalescent units if the --theta option
# is used. Without --theta, the expected outputs from these in rule all are commented out and they will not be run.
####################

rule run_phyloacc:
    input:
        os.path.join(INDIR, "{{st_batch}}-st.cfg")
    output:
        os.path.join(OUTDIR, "{{st_batch}}-phyloacc-st-out", "{{st_batch}}_elem_lik.txt")
    log:
        os.path.join(OUTDIR, "{{st_batch}}-phyloacc-st-out", "{{st_batch}}-phyloacc.log")
    shell:
        \"\"\"
        {st_path} {{input}} &> {{log}}
        \"\"\"
        
rule run_phyloacc_gt:
    input:
        config = os.path.join(INDIR, "{{gt_batch}}-gt.cfg"),
        coal_tree = "{coal_tree_path}"
    output:
        os.path.join(OUTDIR, "{{gt_batch}}-phyloacc-gt-out", "{{gt_batch}}_elem_lik.txt")
    log:
        os.path.join(OUTDIR, "{{gt_batch}}-phyloacc-gt-out", "{{gt_batch}}-phyloacc.log")
    shell:
        \"\"\"
        {gt_path} {{input.config}} &> {{log}}
        \"\"\"

# This rule runs phyloacc on each batch individually. With a cluster profile
# each batch will be submitted as a job.

#############################################################################
"""

    return smk_template;

#############################################################################

def snakemakeConfig():
    
    config_template = """input_directory: {indir}
output_directory: {outdir}
st_batch_list: {st_batches}
gt_batch_list: {gt_batches}
iqtree_directory: {iqtree}
astral_directory: {astral}
"""

    return config_template;

#############################################################################

def snakemakeProfile():
    
    profile_template = """jobs: {num_jobs}
cluster-sync:
  mkdir -p {cluster_logdir}/{{rule}}/ &&
  sbatch
  --wait
  --partition={{resources.partition}}
  --nodes={{resources.nodes}}
  --cpus-per-task={{resources.cpus}}
  --job-name={{rule}}-{{wildcards}}
  --mem={{resources.mem}}
  --time={{resources.time}}
  --output={cluster_logdir}/{{rule}}/{{rule}}-{{wildcards}}-%j.out
default-resources:
  - partition='{part}'
  - nodes='{num_nodes}'
  - mem='{mem}g'
  - time='{time}'
  - cpus={procs_per_job}
latency-wait: 45
verbose: true
"""

    return profile_template;

#############################################################################

def labelCoalTreeScript():
    
    label_script_template = """#!/bin/bash

## Read the labels from the input species tree (not astral tree)
# Initialize an empty array
labels1=()

# Read the input string character by character
while IFS= read -r -n1 char
do
    # If the character is a ), start capturing until :
    if [[ $char == ")" ]]
    then
        label=""
        while IFS= read -r -n1 char && [[ $char != ":" ]]
        do
            label+="$char"
        done
        labels1+=("$label")
    fi
done < {astral_input_tree_path}

## Replace the labels in the astral tree
# Initialize an index for labels1
index=0

# Read the input string character by character
while IFS= read -r -n1 char
do
    # If the character is a ), start replacing until :
    if [[ $char == ")" ]]
    then
        # Print the ) and the label, and increment the index
        printf ")${{labels1[$index]}}"

        # Skip characters until :
        while IFS= read -r -n1 char && [[ $char != ":" ]]
        do
            continue
        done

        # Increment the index
        ((index++))
    fi

    # Print the character
    printf "$char"
done < {unlabeled_coal_tree_path} > {coal_tree_path}
"""
    return label_script_template;

#############################################################################

def htmlSummary():

    html_template = """
<!doctype html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">	
<link href="https://fonts.googleapis.com/css?family=Lato:300" rel="stylesheet"> 
<title>PhyloAcc pre-run stats</title>
</head>

<body>
    <div class="row" id="top_grid">
        <div class="col-2-24" id="margin"></div>
        <div class="col-20-24" id="main_header">PhyloAcc pre-run stats</div>
        <div class="col-2-24" id="margin"></div>
    </div>

    <div class="row" id="main-container">
        <div class="row" id="side-nav-row">
            <div class="col-24-24" id="side-nav-container">
                <div class="row" id="nav-header-container">
                    <div class="col-24-24" id="nav-header">Navigation</div>
                </div>
            
                <div class="row" id="nav-content-container">
                    <div class="col-2-24" id="side-nav-margin"></div>
                    <div class="col-22-24" id="nav-links">
                        <a class="nav-link" href="#run-info">1. Run info</a>
                        <a class="nav-link" href="#input-tree">2. Input species tree</a>
                        <a class="nav-link" href="#locus-lens">3. Distribution of locus lengths</a>
                        <a class="nav-link" href="#informative-sites">4. Distribution of informative sites per locus</a>
                        <a class="nav-link" href="#variable-informative-sites">5. Correlation between variable and informative sites</a>
                        {comment_start}
                        <a class="nav-link" href="#scf">6. Site concordance factors (sCF) per locus</a>
                        <a class="nav-link" href="#scf-tree">7. sCF across all loci</a>
                        <a class="nav-link" href="#bl-scf">8. Branch length vs. sCF for the species tree</a> 
                        {comment_end}
                    </div>
                </div>
            </div>
        </div>

        <div class="col-20-24" id="main-content">

            <div class="row content-row" id="run-info-row">
                <div class="col-24-24 content-col" id="run-info">
                    <div class="section-header">1. Run info ({run_name})</div>
                    <p>The PhyloAcc interface was run on <code>{run_time}</code> on <code>{host_name}</code> as follows:</p>
                    
                    <div class="code-focus">
                        <pre>
{script_call}
                        </pre>
                    </div>

                    <div class="line"></div>

                    <div class="sub-header">Alignment and batch info</div>
                    <div class="table-container">
                        <table class="table-content">
                            <tr>
                                <td>Input alignments</td>
                                <td>{num_aln}</td>
                            </tr>

                            <tr>
                                <td>Alignments with 0 informative sites (removed)</td>
                                <td>{num_no_inf_loci}</td>
                            </tr>

                            {filter_comment_start}
                            <tr>
                                <td>Low quality alignments (removed)</td>
                                <td>{num_filtered_loci}</td>
                            </tr>      
                            {filter_comment_end}                      

                            <tr>
                                <td>Alignments for species tree model</td>
                                <td>{num_st_loci}</td>
                            </tr>

                            <tr>
                                <td>Alignments for gene tree model</td>
                                <td>{num_gt_loci}</td>
                            </tr>

                            <tr>
                                <td>Batches</td>
                                <td>{num_batches}</td>
                            </tr>                        

                            <tr>
                                <td>Alignments per batch</td>
                                <td>{batch_size}</td>
                            </tr>   

                            <tr>
                                <td>Processes to use per batch</td>
                                <td>{procs_per_batch}</td>
                            </tr>

                            <tr>
                                <td>Batches using species tree model</td>
                                <td>{num_st_batches}</td>
                            </tr>   

                            <tr>
                                <td>Batches using gene tree model</td>
                                <td>{num_gt_batches}</td>
                            </tr>

                            <tr>
                                <td>Batches to submit to cluster simultaneously</td>
                                <td>{num_jobs}</td>
                            </tr>
                        </table>
                    </div>

                    <p>
                        See the <a href="{log_file}">full log file</a> for more info.
                    </p>

                    <p>
                        Below are some summary plots. Raw data is also available in CSV format in the <a href="{aln_stats_file}">alignment stats file</a>.
                    </p>

                    <div class="line"></div>
                    <div class="sub-header">Run batches</div>

                    {batch_comment_start}
                    <p class="emphasis">
                        This was a --plotonly run! No job files were generated or overwritten. To generate these files or overwrite them, re-run without 
                        the --plotonly option and with the --overwrite option. Once you have these files, follow the instructions below to run them.
                    </p>
                    {batch_comment_end}

                    <p>
                        The generated batches can be run with Snakemake with the following command:
                    </p>

                    <div class="code-focus">
                        <pre>
{snakemake_cmd}
                        </pre>
                    </div>

                    <p>
                        Note that this includes the <code>--dryrun</code> option to check for possible errors before submitting jobs. If everything looks good
                        after running that, feel free to remove the <code>--dryrun</code> option to submit the jobs to your cluster. You may also want to run
                        this in the background using <a href="https://linuxize.com/post/how-to-use-linux-screen/" target="_blank">screen</a>, 
                        <a href="https://linuxize.com/post/getting-started-with-tmux/" target="_blank">tmux</a> or some other terminal multiplexer 
                        to avoid disruptions due to server disconnects.
                    </p>

                    <div class="line"></div>

                    {theta_comment_start}
                    <div class="sub-header">Coalescent tree inference for theta estimation</div>
                    <p>
                        Since some or all of the loci will be processed with the gene tree model and the interface was run with the <code>--theta</code> 
                        option, this Snakemake pipeline includes rules to generate gene trees with<a href="http://www.iqtree.org/" target="_blank">IQ-Tree</a> 
                        and a species tree with branch lengths in coalescent units using <a href="https://github.com/smirarab/ASTRAL" target="_blank">ASTRAL</a>. 
                        The branch lengths from this tree will be used in conjunction with the branch lengths in the input tree (which should be in units 
                        of relative number of substitutions) to estimate the theta parameter used in the gene tree model.
                    </p>
                    {theta_comment_end}

                    {coal_tree_comment_start}
                    <div class="sub-header">Coalescent tree provided for theta estimation</div>
                    <p>
                        Since some or all of the loci will be processed with the gene tree model, a species tree with branch lengths in coalescent 
                        units was provided: <code>{coal_tree_file}</code>
                    </p>

                    <p>
                        The branch lengths from this tree will be used in conjunction with the branch lengths in the input tree (which should be in units of 
                        relative number of substitutions) to estimate the theta parameter used in the gene tree model.
                    </p>
                    {coal_tree_comment_end}

                </div>
            </div>

            <div class="sep-div"></div>


            <div class="row content-row" id="input-tree-row">
                <div class="col-24-24 content-col" id="input-tree">
                    <div class="section-header">2. Input species tree</div>

                    <div class="table-container">
                        <table class="table-content">
                            <tr>
                                <td>Species</td>
                                <td>{num_spec}</td>
                            </tr>

                            <tr>
                                <td>Target species</td>
                                <td>{num_targets}</td>
                            </tr>                        

                            <tr>
                                <td>Conserved species</td>
                                <td>{num_conserved}</td>
                            </tr>   

                            <tr>
                                <td>Outgroup species</td>
                                <td>{num_outgroups}</td>
                            </tr>  
                        </table>
                    </div>

                    <div class="row img-row" id="input-tree-container-row">
                        <div class="col-4-24 margin"></div>
                        <div class="col-16-24 img-container" id="input-tree-container">
                            <img id="input-tree-img" src="{input_tree_plot}">
                        </div>
                        <div class="col-4-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            <div class="row content-row" id="run-info-row">
                <div class="col-24-24 content-col" id="locus-lens">
                    <div class="section-header">3. Distribution of locus lengths</div>

                    <div class="table-container">
                        <table class="table-content">
                            <tr>
                                <td>Average alignment length</td>
                                <td>{avg_aln_len}</td>
                            </tr>

                            <tr>
                                <td>Median alignment length</td>
                                <td>{median_aln_len}</td>
                            </tr>                        

                            <tr>
                                <td>Average sequence length (no gaps) per alignment</td>
                                <td>{avg_seq_len_nogap}</td>
                            </tr>   

                           <tr>
                                <td>Median sequence length (no gaps) per alignment</td>
                                <td>{med_seq_len_nogap}</td>
                            </tr>   

                        </table>
                    </div>

                    <div class="row img-row" id="locus-lens-container-row">
                        <div class="col-2-24 margin"></div>
                        <div class="col-9-24 img-container" id="aln-lens-container">
                            <img id="aln-lens-img" src="{aln_len_hist}">
                        </div>
                        <div class="col-2-24 margin"></div>
                        <div class="col-9-24 img-container" id="seq-lens-container">
                            <img id="seq-lens-img" src="{seq_len_hist}">
                        </div>
                        <div class="col-2-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            <div class="row content-row" id="run-info-row">
                <div class="col-24-24 content-col" id="informative-sites">
                    <div class="section-header">4. Distribution of informative sites per locus</div>

                    <div class="row img-row" id="informative-sites-container-row">
                        <div class="col-2-24 margin"></div>
                        <div class="col-9-24 img-container" id="informative-sites-container">
                            <img id="informative-sites-img" src="{informative_sites_hist}">
                        </div>
                        <div class="col-2-24 margin"></div>
                        <div class="col-9-24 img-container" id="proportion-informative-sites-container">
                            <img id="proportion-informative-sites-img" src="{informative_sites_frac_hist}">
                        </div>
                        <div class="col-2-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            <div class="row content-row" id="variable-informative-sites-row">
                <div class="col-24-24 content-col" id="variable-informative-sites">
                    <div class="section-header">5. Correlation between variable and informative sites</div>

                    <div class="row img-row" id="variable-informative-sites-container-row">
                        <div class="col-6-24 margin"></div>
                        <div class="col-12-24 img-container" id="variable-informative-sites-container">
                            <img id="variable-informative-sites-img" src="{variable_informative_sites_plot}">
                        </div>
                        <div class="col-6-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            {comment_start}
            <div class="row content-row" id="scf-row">
                <div class="col-24-24 content-col" id="scf">
                    <div class="section-header">6. sCF distributions per locus</div>

                    <div class="row content-row" id="run-info-row">
                        <div class="col-24-24 content-col" id="scf-info">
                            <p>
                                Site concordance factors (sCF) summarize the number of sites in an alignment that support a branch in a given phylogeny.
                            </p>
                            
                            <p>
                                Briefly, they are computed by sampling quartets of species around each branch in an unrooted tree and counting the number of
                                decisive sites that match the topology of the sampled quartet in the phylogeny. See 
                                <a href="https://doi.org/10.1093/molbev/msaa106" target="_blank">Minh et al. 2020</a> for more information.
                            </p>
                                
                            <p>
                                Here, rather than averaging over branches for all alignments, we calculate sCF for each branch in each alignment separately.
                            </p>
                        </div>
                    </div>

                    <div class="row img-row" id="scf-container-row">
                        <div class="col-2-24 margin"></div>
                        <div class="col-9-24 img-container" id="avg-scf-container">
                            <img id="avg-scf-img" src="{avg_scf_hist}">
                        </div>
                        <div class="col-2-24 margin"></div>
                        <div class="col-9-24 img-container" id="low-scf-container">
                            <img id="low-scf-img" src="{low_scf_hist}">
                        </div>
                        <div class="col-2-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            <div class="row content-row" id="scf-tree-row">
                <div class="col-24-24 content-col" id="scf-tree">
                    <div class="section-header">7. sCF across all loci</div>
                    <div class="row content-row" id="run-info-row">
                        <div class="col-24-24 content-col" id="scf-info">
                            <p>
                                Here, the species tree is shown with branches labeled by sCF across all branches (as described in
                                <a href="https://doi.org/10.1093/molbev/msaa106" target="_blank">Minh et al. 2020</a>).
                            </p>

                            <p>
                                The tree in Newick format is located <a href="phyloacc-scf.tree">here</a>.
                            </p>
                            
                            <p>
                                The sCF stats per branch can be found in CSV format <a href="phyloacc-scf-stats.csv">here</a>.
                            </p>
                        </div>
                    </div>                            

                    <div class="row img-row" id="scf-tree-container-row">
                        <div class="col-4-24 margin"></div>
                        <div class="col-16-24 img-container" id="scf-tree-container">
                            <img id="scf-tree-img" src="{scf_tree_plot}">
                        </div>
                        <div class="col-4-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            <div class="row content-row" id="bl-scf-row">
                <div class="col-24-24 content-col" id="bl-scf">
                    <div class="section-header">8. Branch length vs. sCF for the species tree</div>

                    <div class="row img-row" id="bl-scf-container-row">
                        <div class="col-6-24 margin"></div>
                        <div class="col-12-24 img-container" id="bl-scf-container">
                            <img id="bl-scf-img" src="{bl_scf_plot}">
                        </div>
                        <div class="col-6-24 margin"></div>
                    </div>

                </div>
            </div>

            <div class="sep-div"></div>

            {comment_end}

        </div>

    </div>


    <div class="row" id="footer">
    <div class="col-1">
        <div id="footer_text">
            <center>Page generated by the <a href="https://github.com/harvardinformatics/PhyloAcc-interface" target="_blank">PhyloAcc interface</a> | Page built: {date_time}</center>
        </div>
    </div>

</body>

<style type="text/css" media="screen">
    /*------------------------------------------------------*/
    /* Global page styles */
    body {{
        color:#1a1a1a;
        font-family: 'Helvetica', sans-serif;
        font-size: 1.1em;
        background-color: #ececec;
        overflow-y: scroll;
        margin: 0;
    }}
    a {{
        color:#006ddb;
    }}

    /*------------------------------------------------------*/
    /* Grid styles */

    .row {{ 
        width:100%;
        display: flex;
        justify-content: center;
        align-items: center;
    }}

    .col-1-24 {{ width:4.166667%; display:inline-block; }}
    .col-2-24 {{ width:8.333333%; display:inline-block; }}
    .col-3-24 {{ width:12.5%; display:inline-block; }}
    .col-4-24 {{ width:16.666667%; display:inline-block; }}
    .col-5-24 {{ width:20.833333%; display:inline-block; }}
    .col-6-24 {{ width:25%; display:inline-block; }}
    .col-7-24 {{ width:29.166667%; display:inline-block; }}
    .col-8-24 {{ width:33.333333%; display:inline-block; }}
    .col-9-24 {{ width:37.5%; display:inline-block; }}
    .col-10-24 {{ width:41.666667%; display:inline-block; }}
    .col-11-24 {{ width:45.833333%; display:inline-block; }}
    .col-12-24 {{ width:50%; display:inline-block; }}
    .col-13-24 {{ width:54.166667%; display:inline-block; }}
    .col-14-24 {{ width:58.333333%; display:inline-block; }}
    .col-15-24 {{ width:62.5%; display:inline-block; }}
    .col-16-24 {{ width:66.666667%; display:inline-block; }}
    .col-17-24 {{ width:70.833333%; display:inline-block; }}
    .col-18-24 {{ width:75%; display:inline-block; }}
    .col-19-24 {{ width:79.1666667%; display:inline-block; }}
    .col-20-24 {{ width:83.333333%; display:inline-block; }}
    .col-21-24 {{ width:87.5%; display:inline-block; }}
    .col-22-24 {{ width:91.666667%; display:inline-block; }}
    .col-23-24 {{ width:95.833333%; display:inline-block; }}
    .col-24-24 {{ width:100%; display:inline-block; }}
    /* 24 */

    .col-1-12 {{ width:8.333333%; display:inline-block; }}
    .col-2-12 {{ width:16.666667%; display:inline-block; }}
    .col-3-12 {{ width:25%; display:inline-block; }}
    .col-4-12 {{ width:33.333333%; display:inline-block; }}
    .col-5-12 {{ width:41.666667%; display:inline-block; }}
    .col-6-12 {{ width:50%; display:inline-block; }}
    .col-7-12 {{ width:58.333333%; display:inline-block; }}
    .col-8-12 {{ width:66.666667%; display:inline-block; }}
    .col-9-12 {{ width:75%; display:inline-block; }}
    .col-10-12 {{ width:83.333333%; display:inline-block; }}
    .col-11-12 {{ width:91.666667%; display:inline-block; }}
    .col-12-12 {{ width:100%; display:inline-block; }}
    /* 12 */

    .col-1-8 {{ width:12.5%; display:inline-block; }}
    .col-2-8 {{ width:25%; display:inline-block; }}
    .col-3-8 {{ width:37.5%; display:inline-block; }}
    .col-4-8 {{ width:50%; display:inline-block; }}
    .col-5-8 {{ width:62.5%; display:inline-block; }}
    .col-6-8 {{ width:75%; display:inline-block; }}
    .col-7-8 {{ width:87.5%; display:inline-block; }}
    .col-8-8 {{ width:100%; display:inline-block; }}
    /* 8 */

    .col-1-6 {{ width:16.666667%; display:inline-block; }}
    .col-2-6 {{ width:33.333333%; display:inline-block; }}
    .col-3-6 {{ width:50%; display:inline-block; }}
    .col-4-6 {{ width:66.666667%; display:inline-block; }}
    .col-5-6 {{ width:83.333333%; display:inline-block; }}
    .col-6-6 {{ width:100%; display:inline-block; }}
    /* 6 */

    .col-1-4 {{ width:25%; display:inline-block; }}
    .col-2-4 {{ width:50%; display:inline-block; }}
    .col-3-4 {{ width:75%; display:inline-block; }}
    .col-4-4 {{ width:100%; display:inline-block; }}
    /* 4 */

    .col-1-3 {{ width:33.333333%; display:inline-block; }}
    .col-2-3 {{ width:66.666667%; display:inline-block; }}
    .col-3-3 {{ width:100%; display:inline-block; }}
    /* 3 */

    .col-1-2 {{ width:50%; display:inline-block; }}
    .col-2-2 {{ width:100%; display:inline-block; }}
    /* 2 */

    .col-1-1 {{ width:100%; display:inline-block; }}
    /* 1 */

    /*------------------------------------------------------*/
    /* Banner styles */
    #top_grid {{
        height:15vh;

        /* background-image: url(html/img/bg1.png); */
        /* https://pixabay.com/illustrations/color-triangle-geometric-textured-2174049/ */

        background: linear-gradient(25deg, rgba(244,251,193,1) 0%, rgba(150,211,196,1) 50%, rgba(50,119,174,1) 100%);
        /* https://cssgradient.io/ */
        
        background-repeat: no-repeat;
        background-clip: border-box;
        background-origin: padding-box;
        -moz-background-size: cover;
        background-size: cover;
    }}
    #main_header {{
        color:#999999;
        -webkit-text-stroke-width: 0.5px;
        -webkit-text-stroke-color: black;
        font-size:3em;
        padding-top:10px;
        padding-bottom:10px;
        text-align: left;
        vertical-align: middle;
    }}

    /*------------------------------------------------------*/
    /* Header styles */

    .section-header {{
        background-color: #749abe;
        color: #fff;
        padding: 15px;
        font-size:2em;
        font-weight:bold;
        position: sticky;
        top: 0px;
        /* border-bottom: 2px solid #294157;
        border-left: 2px solid #294157; */
    }}
    @media (max-width: 1025px) {{
        .section-header  {{ 		
            text-align:center; 
        }}
    }}
    .sub-header {{
        /* background-color: #749abe; */
        /* color: #fff; */
        padding: 15px;
        font-size:1.5em;
        font-weight:bold;
    }}
    .sub-header-2 {{
        /* background-color: #749abe; */
        padding: 30px;
        font-size:1.25em;
        font-weight:bold;
    }}

    /*------------------------------------------------------*/
    /* Main container styles */

    #main-container {{
        display: flex;
        align-items: stretch;
        height: auto;
        min-height: 85vh;
    }}

    /*------------------------------------------------------*/
    /* Side nav bar styles */

    #side-nav-row {{
        height:97vh;
        background-color: #ffffff;
        border-right:1px solid black;
        position: sticky;
        top: 0px;
    }}
    #side-nav-container {{
        height:100%;
    }}
    #nav-header {{
        padding: 15px 0px;
        text-indent: 15px;
        font-size: 2em;
        overflow-wrap: break-word;
        background-color: #294157;
        color: #ffffff;
    }}
    .nav-link {{
        display: block;
        padding: 10px 10px 10px 0px;
        font-size: 1em;
        text-decoration: none;
        transition: 0.1s linear;

    }}
    .nav-link:hover {{
        color: #ececec;
        background-color: #56b4e9;
    }}
    @media (max-width: 1025px) {{
        #side-nav {{ height:94vh; }}
    }}

    /*------------------------------------------------------*/
    /* Content styles */

    .content-row p {{
        padding: 0 40px;
    }}
    .list-container {{
        padding-left: 40px;
    }}
    .code-focus {{
        display: flex;
        align-items: center;
        justify-content: center;
        font-family:'Courier New', Courier, monospace;
        font-size: 1.2em;
    }}
    .code-focus pre {{
        width: 75%;
        overflow: auto;
        background-color:#ffffff;
    }}
    .img-container {{
        display: flex;
        align-items: center;
        justify-content: center;
    }}
    .img-container img {{
        display: inline-block;
        width: 100%;
        height: auto;
    }}
    .emphasis {{
        font-size: 1.5em;
        color: #920000;
    }}

    /*------------------------------------------------------*/
    /* Table styles */
    .table-container {{
        padding:20px 50px 20px 50px;
        overflow-y:auto;
        display:flex;
        align-items: center;
        justify-content: center;

    }}
    .table-content {{
        background-color:#ffffff;
        border: 1px solid #333333;
        border-radius: 10px;
        width: 25%;
    }}
    .table-content  th {{
        background-color:#000000;
        /* background-color: #A9C686; */
        /* background-color: #6B8B39; */
        padding:5px;
        width:12.5%;
        color: #ececec;
        /* border:1px solid red; */
    }}
    .table-content  tr:nth-child(even) {{
        background-color:#E0DEDE;
    }}

    /*------------------------------------------------------*/
    /* Footer grid styles */
    #footer {{
        font-family: "Courier New", Courier, monospace;
        background-color: #fff;
        color:#333;
        font-size:0.6em;
        height:3vh;
        display: flex;
        justify-content: center;
        align-content: center;
        flex-direction: column;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        border-top:1px solid #333;
        width:100%;
    }}
    @media (max-width: 1025px) {{
        #footer {{ height:6vh; }}
        #footer_text {{ top: 25%; }}
    }}

    /*------------------------------------------------------*/
    /* Grid spacing styles */
    .sep-div {{
        width: 100%;
        height: 2vh;
    }}
    #vert_line{{
        width:1px;
        height:100%;
        background-color:#d3d3d3;
    }}
    .line {{
        height:1px;
        background-color:#d3d3d3;
        margin:20px;
    }}    
</style>

    """

    return html_template