]> lifelog.hopto.org Git - PerlCNFWEBServer.git/commitdiff
init
authorWill Budic <redacted>
Thu, 15 May 2025 08:26:03 +0000 (18:26 +1000)
committerWill Budic <redacted>
Thu, 15 May 2025 08:26:03 +0000 (18:26 +1000)
29 files changed:
.gitignore [new file with mode: 0644]
server.pl [new file with mode: 0755]
specs.md [new file with mode: 0644]
web_sources/app.css [new file with mode: 0644]
web_sources/fonts/DMSams/DMSans-Italic-VariableFont_opsz,wght.ttf [new file with mode: 0644]
web_sources/fonts/DMSams/DMSans-VariableFont_opsz,wght.ttf [new file with mode: 0644]
web_sources/fonts/DMSams/OFL.txt [new file with mode: 0644]
web_sources/fonts/DMSams/README.txt [new file with mode: 0644]
web_sources/fonts/DMSams/static/DMSans-Medium.ttf [new file with mode: 0644]
web_sources/fonts/DMSams/static/DMSans-MediumItalic.ttf [new file with mode: 0644]
web_sources/fonts/DMSams/static/DMSans-Regular.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Black.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-BlackItalic.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Bold.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-BoldItalic.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Hairline.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-HairlineItalic.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Italic.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Light.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-LightItalic.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Regular.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-Thin.ttf [new file with mode: 0644]
web_sources/fonts/Lato/Lato-ThinItalic.ttf [new file with mode: 0644]
web_sources/fonts/Lato/OFL.txt [new file with mode: 0644]
web_sources/fonts/Lato/STYLES.css [new file with mode: 0644]
web_sources/fonts/LeagueMono-VF.woff2 [new file with mode: 0644]
web_sources/fonts/fontawesome-webfont.woff2 [new file with mode: 0644]
web_sources/root.css [new file with mode: 0644]
web_sources/style-kevin-powell.css [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3e4abb5
--- /dev/null
@@ -0,0 +1,3 @@
+.vscode
+system
+wsrc
\ No newline at end of file
diff --git a/server.pl b/server.pl
new file mode 100755 (executable)
index 0000000..161dfaf
--- /dev/null
+++ b/server.pl
@@ -0,0 +1,418 @@
+#!/usr/bin/perl
+package PerlCNFWebServer;
+use lib::relative 'system/modules';
+use lib::relative 'apps';
+use PerlCNFWebServerBase;
+
+use IO::Socket::SSL;
+use HTTP::Server::Simple::CGI;
+use base qw(HTTP::Server::Simple::CGI);
+
+use Gzip::Faster; no warnings qw(experimental::signatures);
+
+our   ($START_UP_ERRORS, $START_UP_PROPS, $SERVER_DIR);
+our    $GLOB_HTML_SERVE = "'{}/*.cgi' '{}/*.htm' '{}/*.html' '{}/*.md' '{}/*.txt'";
+BEGIN {use Cwd; $SERVER_DIR = cwd}
+use lib $SERVER_DIR.'/apps'; use lib $SERVER_DIR.'/apps';
+
+our $cnf_index;
+our %locals;
+our %includes;
+our $INDEX_FILE = CNFGlobalFile -> new('index.cnf');
+our $LOCAL_PATH = $0;
+our %TYPE_HANDLER = (
+    css => \&asTxtFile,
+    txt => \&asTxtFile,
+    js  => \&asTxtFile,
+    png => \&asBinFile, jpg => \&asBinFile, jpeg => \&asBinFile,
+    gif => \&asBinFile,
+    ttf => \&asBinFile,  woff2=> \&asBinFile
+);
+our %dispatch = (
+    '/'  => \&index,
+    '/wsrc' => \&wsrc,
+);
+our %SSL;
+my $cnf_server = CNFParser::_configure({DEBUG=>1,DO_ENABLED => 1,SERVER_DIR=>$SERVER_DIR},$0);
+my @globs      = $cnf_server -> property('@GLOB_HTML_SERVE');
+if(@globs){
+   my $gs;
+   foreach(@globs) {
+      $gs .= "{}/*.$_ " if $_
+   }
+   if ($gs){
+       $GLOB_HTML_SERVE = $gs;
+       $START_UP_PROPS  = "\@GLOB_HTML_SERVE => $GLOB_HTML_SERVE";
+   }
+}else{
+   my $err ="\@GLOB_HTML_SERVE property not found in config, using default.";
+   warn($err); $START_UP_ERRORS .= "$err\n \@GLOB_HTML_SERVE => $GLOB_HTML_SERVE";
+}
+no warnings qw(experimental::signatures);#Placed here as earlier versions of Perl shoot warnings.
+sub asTxtFile  ($cgi, $request_header, $type, $full_path) {
+    my $file = CNFGlobalFile->new($full_path);
+    my $last_modified = CNFDateTime->now({epoch=>$file->{last_modified}, TZ => $cnf_server->{TZ}});
+    my $now  = CNFDateTime->now({TZ => $cnf_server->{TZ}});
+    my $content = ${$file->content()};
+    my $gzip = CNFParser::_isTrue($cnf_server -> const('compress_particulars'));
+    if($gzip){ #Check if browser supports gzip?
+        my $accept_encoding = %$request_header{HTTP_ACCEPT_ENCODING};
+        $gzip = 0  if $accept_encoding !~ m/gzip/;
+    }
+    print "HTTP/1.0 200 OK\n",
+          "content-type: text/$type; charset=utf-8\n";
+    print "content-encoding: gzip\n" if $gzip;
+    print "content-length: ",$file -> {content_length},"\n",
+          "last-modified: ",$last_modified->toSchlong(),"\n",
+          "date: ",$now->toSchlong(),"\n",
+          "cache-control: public\n",
+          "server: ".__PACKAGE__."/".CNFParser::VERSION(),"\n\n";
+    print  $gzip?gzip($content):$content;
+}
+
+sub asBinFile ($cgi, $request_headers, $type, $full_path){
+    my $file = CNFGlobalFile->new($full_path);
+    my $last_modified = CNFDateTime->now({epoch=>$file->{last_modified}, TZ => $cnf_server->{TZ}});
+    my $now = CNFDateTime->now({TZ => $cnf_server->{TZ}});
+    print "HTTP/1.0 200 OK\n",
+            "content-type: image/$type;\n",
+            "content-length: ", $file -> {content_length},"\n",
+            "last-modified: ",$last_modified->toSchlong(),"\n",
+            "date: ",$now->toSchlong(),"\n",
+            "cache-control: public","\n",
+            "server: ".__PACKAGE__."/".CNFParser::VERSION(),"\n\n";
+    $file -> binary();
+}
+
+sub error_to_browser ($cgi, $err){
+    my $now = CNFDateTime->now({TZ => $cnf_server->{TZ}});
+    my $page_link = $cgi->protocol().'//'.$cgi->remote_host().':'.$cgi->server_port().$cgi->request_uri();
+    print "HTTP/1.0 500 Internal Server Error\n",
+            "content-type: text/html; charset=utf-8\n",
+            "date: ",$now->toSchlong(),"\n",
+            "server: ".__PACKAGE__."/".CNFParser::VERSION(),"\n\n",
+          $cgi->start_html(">>Server Error!<"),
+               $cgi ->h2("<font color='maroon'>ServerError@ &#x21d2; </font> $page_link"),
+               $cgi->pre($err),
+          $cgi->end_html;
+}
+
+sub deliverByParticulars ($cgi, $request_header, $dir, $full_path) {
+       $full_path =~ m/\.(\w+)$/; my $type = $1;
+    my $handler  = $TYPE_HANDLER{$type};
+    if($handler && -e $full_path){
+       $handler -> ($cgi, $request_header, $type, $full_path);
+    }else{
+       print "HTTP/1.0 404 Not found\r\n";
+       print $cgi->header,
+             $cgi->start_html('Not found :'.$cgi->path_info()),
+             $cgi->h1('Not found -> '.$cgi->path_info()),
+             $cgi->end_html;
+    }
+}
+
+sub obtainDirListingHTML ($dir) {
+    my $ret;
+    my $html = listFiles($dir);
+    if($html){
+       $ret .="<ul><b>$dir &#8594;</b>\n";
+       $ret .= $html;
+       opendir (my $handle, $dir) or die "Couldn't open directory, $!";
+       while (my $node = readdir $handle) {
+              my $file_full_path = "$dir/$node";
+              if($node !~ /^\./ && -d $file_full_path){
+                 $html = obtainDirListingHTML($dir.'/'.$node);
+                 $ret .= $html if $html
+              }
+       }
+       closedir $handle;
+       $ret .= "</ul>";
+    }
+    return $ret;
+}
+
+sub listFiles ($dir){
+    my $ret;
+    my $path = $dir;
+    my $spec = $GLOB_HTML_SERVE; $spec =~ s/{}/$path/gp;
+    my @files = glob ($spec);
+       @files =  sort {
+            ( $a=~m/\w+[_-]*/ eq $b=~m/\w+[_-]*/ && length $a > length $b) ||
+              $a <=> $b
+    }  @files;
+    foreach my $file(@files){
+            ($file =~ m/(\w+\.\w*)$/g);
+            my $name = $1;
+            if($file =~ /\.md$/){
+                my @title = getDocTitle($file);
+                $ret .= qq(\t\t\t<li><a href="$dir/$title[0]">$title[1]</a> &dash; $name</li>\n);
+            }else{
+                $ret .= qq(\t\t\t<li><a href="$dir/$name">$name</a></li>\n);
+            }
+    }
+
+    return $ret;
+}
+
+sub wsrc($cgi,$hdrs) {
+my $ret = obtainDirListingHTML($SERVER_DIR.'/wsrc');
+print $cgi->header,
+        $cgi->start_html,
+        $cgi->div($ret),
+        $cgi->end_html;
+
+}
+sub index($cgi,$hdrs) {
+    if (check_if_has_changed($INDEX_FILE)){
+        try{
+
+        $cnf_index  = CNFParser -> new (
+                            $INDEX_FILE,{
+                                DO_ENABLED => 1, HAS_EXTENSIONS=>1,
+                                ANONS_ARE_PUBLIC => 1,
+                                DEBUG => 1,
+                                TZ => $cnf_server->{TZ},
+                                PAGE_HEAD     => "<h1 id=\"index_head\">Index Page of Docs Directory</h1>",
+                                PAGE_CONTENT  => "<h2>Hello World</h2>",
+                                PAGE_FOOT     => "<!--Not Defined-->"
+                            }
+                        );
+        $locals{$INDEX_FILE} = \$cnf_index;
+
+        }catch($e){
+                  $cnf_server -> error($e);
+                  error_to_browser($cgi, $e);
+                  return
+        }
+    }
+    my $ptr = $cnf_index->data();
+    $ptr = $ptr->{'PAGE'};
+    print $$ptr if $ptr;
+}
+
+sub check_if_has_changed ($config_file){
+    my $entry = $locals{$config_file->{path}};
+    if($entry){$entry = $$entry;
+       if($config_file -> changed()){
+          $cnf_server  -> log("Config has changed for: ". $entry->{CNF_CONTENT});
+          return 1
+       }else{
+          my $ptr =  $includes{$config_file->{path}};
+          if($ptr){
+             foreach my $cnf_glob_file(@$ptr){
+                if($cnf_glob_file->changed()){
+                   $cnf_server -> log("Config include changed: ". $cnf_glob_file->{path});
+                   return 1
+                }
+             }
+          }
+       }
+       return 0
+    }else{
+          $cnf_server -> log("Config load initiated for: ". $config_file->{path});
+       return 1
+    }
+}
+
+
+sub page($cgi, $request_header, $prp_name, $cnf_app) {
+    my $property  =  $cnf_app -> property($prp_name);
+    my ($html_head,$html_body,$html_foot);
+    my $ref = ref($property);
+    if(not $property){
+       $property =  $cnf_app->writeOut();
+       $property =~ s/</&lt;/gs;
+       $property =~ s/>/&gt;/gs;
+       $html_body   = \$property
+    }elsif($ref eq 'Pagelet'){
+       $property -> {plugin} -> setParameters($cnf_app, $prp_name, $cgi->{param}) if (keys %{$cgi->{param}} > 0);
+       $html_head = $property -> {html_head};
+       $html_body = $property -> {html_body};
+       $html_foot = $property -> {html_foot};
+    }else{
+       $html_body =  $cnf_app -> data() -> {$property->{property}}
+    }
+    my $now = CNFDateTime->now({TZ => $cnf_server->{TZ}});
+    my $last_modified = CNFDateTime->now({TZ => $cnf_server->{TZ}, epoch=> @{$cnf_app->{CNF_STAT}}[9]});
+    my $gzip = CNFParser::_isTrue($cnf_server -> const('compress_particulars'));
+    if($gzip){ #Check if browser supports gzip?
+        my $accept_encoding = %$request_header{HTTP_ACCEPT_ENCODING};
+        $gzip = 0  if $accept_encoding !~ m/gzip/;
+    }
+
+    # Modern browser html specs have changed, support but do not like/need
+    # header doc type xml/html declarations, that perl's cgi lib builds and delivers for old browser compatibility.
+    # This suits us well, as can configure head parameters start up directly or via CNF from here.
+    print "content-type: text/html; charset=utf-8\n";
+    print "content-encoding: gzip\n" if $gzip;
+    print "last-modified: ",$last_modified->toSchlong(),"\n",
+           "date: ",$now->toSchlong(),"\n",
+           "cache-control: public","\n",
+           "server: ".__PACKAGE__."/".CNFParser::VERSION(),"\n\n";
+    my $content;
+    if(not $html_head){
+       $content = qq(<!DOCTYPE html>\n<html lang="en"><body>\n<pre>\n)
+    }else{
+       $content = $$html_head
+    }
+    $content .= $$html_body;
+    if(not $html_foot ){
+       $content .=  qq(\n</pre></body></html>);
+    }else{
+       $content .=  $$html_foot;
+    }
+    print $gzip ? gzip($content):$content;
+}
+
+
+sub handle_request ($self, $cgi){
+
+    my $path = $cgi->path_info();
+    my $handler = $dispatch{$path};
+
+    if($path && not $handler){
+      # We might got file particulars access,
+      # or direct links for files that have content-type.
+      my @pa = ($path =~ m/(.*)\/(.*\..*)/);
+      my $path_particular =   $pa[0];
+      my $path_file       =   $pa[1];
+      $path = $SERVER_DIR.$path_particular;
+      if(-d $path){
+         my %request_header = map { $_ => $cgi->http($_) } $cgi->http();
+         deliverByParticulars($cgi, \%request_header,$path, $path.'/'.$path_file);
+         return;
+      }
+    }
+
+    if (ref($handler) eq "CODE") {
+        my %request_header = map { $_ => $cgi->http($_) } $cgi->http();
+        print "HTTP/1.0 200 OK\r\n";
+        $handler->($cgi, \%request_header);
+    } else {
+        print "HTTP/1.0 404 Not found\r\n";
+        print $cgi->header,
+              $cgi->start_html('Not found'),
+              $cgi->h1("Not found: $path"),
+              $cgi->end_html;
+    }
+}
+
+sub accept_hook {
+    if(isTrue($SSL{enabled})){
+        my $self = shift; $self->SUPER::accept_hook(@_);
+        my $fh   = $self->stdio_handle;
+        my $newfh =
+        IO::Socket::SSL->start_SSL( $fh,
+            SSL_server    => $SSL{server},
+            SSL_use_cert  => $SSL{use_cert},
+            SSL_cert_file => $SSL{cert_file},
+            SSL_key_file  => $SSL{key_file},
+        )
+        or warn "problem setting up SSL socket: " . IO::Socket::SSL::errstr();
+        $self->stdio_handle($newfh) if $newfh;
+    }
+}
+
+sub include_hook {
+    my ($config_file, $include_file) = @_;
+    if ($config_file && $include_file) {
+        my @arr;  my $ptr = $includes{$config_file};
+           @arr = @$ptr if $ptr;
+        foreach(@arr){
+           return 0 if $_->{path} eq $include_file;
+        }
+        $arr[@arr] = CNFGlobalFile->new($include_file);
+        $includes{$config_file} = \@arr;
+    }
+    return 0;
+}
+
+ sub MAIN
+{
+    our %SSL = $cnf_server -> property('%SSL');
+    my  %log = $cnf_server -> property('%LOG');
+    my  %registry = $cnf_server -> property('%REGISTRY');
+    if (%registry){
+        foreach  my $path (keys(%registry)){
+          my ($prp_name, $config, $cnf_app)  = $registry{$path};
+          my @pair= ($prp_name =~ m/([\w\.\_\-\/]+)\s*,\s*(\w*)/g);
+                     $config   = $pair[0];
+                     $prp_name = $pair[1];
+          my $cnf_file  = CNFGlobalFile->new($config);
+          # Anonymous handler passing our $cgi.
+          $dispatch {"/$path"} = sub ($cgi, $request_header) {
+
+              if(!$cnf_app or check_if_has_changed($cnf_file)){
+               try{
+                  $cnf_app = CNFParser -> new($cnf_file, {
+                                                          DO_ENABLED => 1,
+                                                          '%LOG'     => \%log,
+                                                          TZ         => $cnf_server->{TZ},
+                                                          INCLUDES_LISTENER => *include_hook
+                                                         }
+                                          );
+                  $locals{$config} = \$cnf_app;
+               }catch($e){
+                  $cnf_server -> error($e);
+                  error_to_browser($cgi, $e);
+                  return
+               }
+              }
+               page($cgi, $request_header, $prp_name, $cnf_app);
+               $cnf_server -> log("Delivered -> ".$registry{$path});
+           }
+        }
+    }else{
+        $cnf_server -> warn("A \%REGISTRY property was not located in server config.");
+    }
+
+    my $settings = "Starting -> [". __PACKAGE__ ."]\n";
+    foreach my $k (keys(%$cnf_server)){
+        $settings .= "$k=\'$cnf_server->{$k}\'\n" if $k !~ /^__/;
+    }
+
+    if(%log){
+       $settings .= 'my %LOG = {';
+        foreach my $k (keys(%log)){
+            $settings .= "$k=>\'".$log{$k}."\', "
+        }
+       $settings =~ s/, $//;    $settings .= "}\n";
+    }
+
+    $cnf_server -> log($settings);  print $settings;  print $START_UP_PROPS, "\n", '-'x80, "\n";
+    $cnf_server -> warn($START_UP_ERRORS) if $START_UP_ERRORS;
+
+    my $pid = isTrue($cnf_server->const('run_as_background_process')) ?
+              PerlCNFWebServer->new($cnf_server->{port})->background() :
+              PerlCNFWebServer->new($cnf_server->{port})->run();
+    print `lsof -i tcp:$cnf_server->{port}`;
+    my $run = `lsof -i tcp:$cnf_server->{port} | sed -n '2p' | awk '{print \$2}'`; $run =~s/\s*$//;
+    if($run eq $pid){
+        print "Use kill $pid to stop this server.\n";
+    }else{
+        print "Use kill $run to stop that server.\n";
+    }
+}
+
+sub print_banner {
+    my $self = shift;
+    my $proto = isTrue($SSL{enabled})?"https":"http";
+    my $host  =  `hostname`; $host =~s/\s*$//;
+    print( ref($self) . ": You can connect to your server at " . "$proto://$host:".$self->{port}."/\n" );
+}
+
+&MAIN;
+1;
+
+=begin copyright
+Programed by  : Will Budić
+EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source        : git clone git://lifelog.hopto.org/PerlCNFWebServer
+              : git clone git://lifelog.hopto.org/PerlCNF
+              : https://github.com/wbudic/PerlCNF.git
+Documentation : Specifications_For_CNF_ReadMe.md
+    This source file is copied and usually placed in a local directory, outside of its repository project.
+    So it could not be the actual or current version, can vary or has been modified for what ever purpose in another project.
+    Please leave source of origin in this file for future references.
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright
\ No newline at end of file
diff --git a/specs.md b/specs.md
new file mode 100644 (file)
index 0000000..e3340d2
--- /dev/null
+++ b/specs.md
@@ -0,0 +1,15 @@
+# PerlCNFWebServer
+
+   PerlCNF Standalone HTML Web Server implementation.
+
+## Features
+
+* Can run in a full background process.
+* On server startup provides in memory resident staying of the perl compilations of modules.
+* Auto reloads CNF files and contents if have changed. No server restart required.
+* Web server CNF global app settings for features like: logging, time zones and data resource connections.
+* To remind CNF also provides own data properties and format, besides that can be used for SQL data schemas and operations.
+* Connection pools for datasource management. No waiting for a data connection, as it is in a pool.
+* Forked client request or access management.
+* Server side page caching and resolve on dynamic content for immediate dispatch. Useful if builders and other processors generate outputs, but only if it has changed between requests. Giving a faster response therefore.
+* Static HTML direct output, but also decorated MD files translation to HTML output (cashed as well).
diff --git a/web_sources/app.css b/web_sources/app.css
new file mode 100644 (file)
index 0000000..dd80d15
--- /dev/null
@@ -0,0 +1,119 @@
+
+/** Layers are in root.css **/
+@layer reset, base;
+
+html{
+    height: 100%;
+    display: flex;
+}
+
+body {
+
+    padding: 0.5em;
+    display: grid;
+    overflow: scroll;
+
+    .content {
+        display: inline-flex;
+        /* border: 5px dotted rgb(168, 120, 96);  */
+        max-width: 100%;
+        height: 98%;
+        align-items: stretch;
+        flex-direction: row;
+    }
+    p{
+        padding-left: 1ch;
+        padding-bottom: 1ch;
+    }
+    .indent{
+        padding-left: 3ch;
+        p{
+            padding-left: 2ch;
+        }
+    }
+}
+
+.page_title {
+    font-style: italic;
+    font-weight: bold;
+    box-shadow: 2px 2px 2px black;
+    margin-bottom: 1em;
+}
+
+.col {
+    /* border: 1px solid  rgb(133, 133, 233); */
+    text-wrap: wrap;
+    text-align: center;
+    position: sticky;
+}
+
+
+.col_main {
+    border: 1px solid rgb(133, 133, 233);
+    min-width: 70%;
+    padding: 1em;
+    margin-top: 1ch;
+
+    h1 {
+        margin-top:1ch;
+        color:blueviolet;
+    }
+    div{
+        padding-left: 3ch;
+        p{
+            padding-left: 2ch;
+        }
+    }
+}
+
+.toc {
+    position: fixed;
+    background-color: #00a087;
+    padding: 1ch;
+    border: 2px solid rgb(133, 133, 233);
+    border-radius: 10px 100px / 120px;
+    box-shadow: 10px 5px 5px lightslategrey;
+    cursor: se-resize;
+}
+.toc:hover .scrolling{
+    display: block;
+    cursor: pointer;
+}
+
+ul .scrolling{
+    margin-block-start: 0;
+    margin-block-end: 1em;
+    padding-inline-start: 20px;
+}
+
+.scrolling{
+    position: fixed;
+
+    text-wrap: wrap;     text-align: left;
+
+
+    padding: 1ch;
+    background-color: #00a087;
+    border: 2px solid #42a9b8;
+
+    display: none;
+    box-shadow: 5px 5px 5px lightslategrey;
+    opacity: 80%;
+
+    ul {
+        margin-block-start: 0;
+        margin-block-end: 1em;
+        padding-left: 20px;
+    }
+    a:active{
+        font-size: larger;
+        color: cadetblue;
+    }
+    a:visited{
+        font-size: larger;
+        color: black;
+    }
+
+}
+
+
diff --git a/web_sources/fonts/DMSams/DMSans-Italic-VariableFont_opsz,wght.ttf b/web_sources/fonts/DMSams/DMSans-Italic-VariableFont_opsz,wght.ttf
new file mode 100644 (file)
index 0000000..a7ee5c9
Binary files /dev/null and b/web_sources/fonts/DMSams/DMSans-Italic-VariableFont_opsz,wght.ttf differ
diff --git a/web_sources/fonts/DMSams/DMSans-VariableFont_opsz,wght.ttf b/web_sources/fonts/DMSams/DMSans-VariableFont_opsz,wght.ttf
new file mode 100644 (file)
index 0000000..3d81b31
Binary files /dev/null and b/web_sources/fonts/DMSams/DMSans-VariableFont_opsz,wght.ttf differ
diff --git a/web_sources/fonts/DMSams/OFL.txt b/web_sources/fonts/DMSams/OFL.txt
new file mode 100644 (file)
index 0000000..bd7058f
--- /dev/null
@@ -0,0 +1,93 @@
+Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/web_sources/fonts/DMSams/README.txt b/web_sources/fonts/DMSams/README.txt
new file mode 100644 (file)
index 0000000..4725723
--- /dev/null
@@ -0,0 +1,67 @@
+DM Sans Variable Font
+=====================
+
+This download contains DM Sans as both variable fonts and static fonts.
+
+DM Sans is a variable font with these axes:
+  opsz
+  wght
+
+This means all the styles are contained in these files:
+  DMSans-VariableFont_opsz,wght.ttf
+  DMSans-Italic-VariableFont_opsz,wght.ttf
+
+If your app fully supports variable fonts, you can now pick intermediate styles
+that aren’t available as static fonts. Not all apps support variable fonts, and
+in those cases you can use the static font files for DM Sans:
+  static/DMSans-Regular.ttf
+  static/DMSans-Medium.ttf
+  static/DMSans-MediumItalic.ttf
+
+Get started
+-----------
+
+1. Install the font files you want to use
+
+2. Use your app's font picker to view the font family and all the
+available styles
+
+Learn more about variable fonts
+-------------------------------
+
+  https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
+  https://variablefonts.typenetwork.com
+  https://medium.com/variable-fonts
+
+In desktop apps
+
+  https://theblog.adobe.com/can-variable-fonts-illustrator-cc
+  https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
+
+Online
+
+  https://developers.google.com/fonts/docs/getting_started
+  https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
+  https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
+
+Installing fonts
+
+  MacOS: https://support.apple.com/en-us/HT201749
+  Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
+  Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
+
+Android Apps
+
+  https://developers.google.com/fonts/docs/android
+  https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
+
+License
+-------
+Please read the full license text (OFL.txt) to understand the permissions,
+restrictions and requirements for usage, redistribution, and modification.
+
+You can use them in your products & projects – print or digital,
+commercial or otherwise.
+
+This isn't legal advice, please consider consulting a lawyer and see the full
+license for all details.
diff --git a/web_sources/fonts/DMSams/static/DMSans-Medium.ttf b/web_sources/fonts/DMSams/static/DMSans-Medium.ttf
new file mode 100644 (file)
index 0000000..841d31d
Binary files /dev/null and b/web_sources/fonts/DMSams/static/DMSans-Medium.ttf differ
diff --git a/web_sources/fonts/DMSams/static/DMSans-MediumItalic.ttf b/web_sources/fonts/DMSams/static/DMSans-MediumItalic.ttf
new file mode 100644 (file)
index 0000000..343122f
Binary files /dev/null and b/web_sources/fonts/DMSams/static/DMSans-MediumItalic.ttf differ
diff --git a/web_sources/fonts/DMSams/static/DMSans-Regular.ttf b/web_sources/fonts/DMSams/static/DMSans-Regular.ttf
new file mode 100644 (file)
index 0000000..07266ae
Binary files /dev/null and b/web_sources/fonts/DMSams/static/DMSans-Regular.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Black.ttf b/web_sources/fonts/Lato/Lato-Black.ttf
new file mode 100644 (file)
index 0000000..6848db0
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Black.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-BlackItalic.ttf b/web_sources/fonts/Lato/Lato-BlackItalic.ttf
new file mode 100644 (file)
index 0000000..5decf12
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-BlackItalic.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Bold.ttf b/web_sources/fonts/Lato/Lato-Bold.ttf
new file mode 100644 (file)
index 0000000..7434369
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Bold.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-BoldItalic.ttf b/web_sources/fonts/Lato/Lato-BoldItalic.ttf
new file mode 100644 (file)
index 0000000..684aacf
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-BoldItalic.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Hairline.ttf b/web_sources/fonts/Lato/Lato-Hairline.ttf
new file mode 100644 (file)
index 0000000..288be29
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Hairline.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-HairlineItalic.ttf b/web_sources/fonts/Lato/Lato-HairlineItalic.ttf
new file mode 100644 (file)
index 0000000..c2bfd33
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-HairlineItalic.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Italic.ttf b/web_sources/fonts/Lato/Lato-Italic.ttf
new file mode 100644 (file)
index 0000000..3d3b7a2
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Italic.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Light.ttf b/web_sources/fonts/Lato/Lato-Light.ttf
new file mode 100644 (file)
index 0000000..a958067
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Light.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-LightItalic.ttf b/web_sources/fonts/Lato/Lato-LightItalic.ttf
new file mode 100644 (file)
index 0000000..5e45ad9
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-LightItalic.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Regular.ttf b/web_sources/fonts/Lato/Lato-Regular.ttf
new file mode 100644 (file)
index 0000000..04ea8ef
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Regular.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-Thin.ttf b/web_sources/fonts/Lato/Lato-Thin.ttf
new file mode 100644 (file)
index 0000000..ba58da1
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-Thin.ttf differ
diff --git a/web_sources/fonts/Lato/Lato-ThinItalic.ttf b/web_sources/fonts/Lato/Lato-ThinItalic.ttf
new file mode 100644 (file)
index 0000000..4d82766
Binary files /dev/null and b/web_sources/fonts/Lato/Lato-ThinItalic.ttf differ
diff --git a/web_sources/fonts/Lato/OFL.txt b/web_sources/fonts/Lato/OFL.txt
new file mode 100644 (file)
index 0000000..1d7bf3b
--- /dev/null
@@ -0,0 +1,93 @@
+Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name "Lato"\r
+\r
+This Font Software is licensed under the SIL Open Font License, Version 1.1.\r
+This license is copied below, and is also available with a FAQ at:\r
+https://openfontlicense.org\r
+\r
+\r
+-----------------------------------------------------------\r
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\r
+-----------------------------------------------------------\r
+\r
+PREAMBLE\r
+The goals of the Open Font License (OFL) are to stimulate worldwide\r
+development of collaborative font projects, to support the font creation\r
+efforts of academic and linguistic communities, and to provide a free and\r
+open framework in which fonts may be shared and improved in partnership\r
+with others.\r
+\r
+The OFL allows the licensed fonts to be used, studied, modified and\r
+redistributed freely as long as they are not sold by themselves. The\r
+fonts, including any derivative works, can be bundled, embedded, \r
+redistributed and/or sold with any software provided that any reserved\r
+names are not used by derivative works. The fonts and derivatives,\r
+however, cannot be released under any other type of license. The\r
+requirement for fonts to remain under this license does not apply\r
+to any document created using the fonts or their derivatives.\r
+\r
+DEFINITIONS\r
+"Font Software" refers to the set of files released by the Copyright\r
+Holder(s) under this license and clearly marked as such. This may\r
+include source files, build scripts and documentation.\r
+\r
+"Reserved Font Name" refers to any names specified as such after the\r
+copyright statement(s).\r
+\r
+"Original Version" refers to the collection of Font Software components as\r
+distributed by the Copyright Holder(s).\r
+\r
+"Modified Version" refers to any derivative made by adding to, deleting,\r
+or substituting -- in part or in whole -- any of the components of the\r
+Original Version, by changing formats or by porting the Font Software to a\r
+new environment.\r
+\r
+"Author" refers to any designer, engineer, programmer, technical\r
+writer or other person who contributed to the Font Software.\r
+\r
+PERMISSION & CONDITIONS\r
+Permission is hereby granted, free of charge, to any person obtaining\r
+a copy of the Font Software, to use, study, copy, merge, embed, modify,\r
+redistribute, and sell modified and unmodified copies of the Font\r
+Software, subject to the following conditions:\r
+\r
+1) Neither the Font Software nor any of its individual components,\r
+in Original or Modified Versions, may be sold by itself.\r
+\r
+2) Original or Modified Versions of the Font Software may be bundled,\r
+redistributed and/or sold with any software, provided that each copy\r
+contains the above copyright notice and this license. These can be\r
+included either as stand-alone text files, human-readable headers or\r
+in the appropriate machine-readable metadata fields within text or\r
+binary files as long as those fields can be easily viewed by the user.\r
+\r
+3) No Modified Version of the Font Software may use the Reserved Font\r
+Name(s) unless explicit written permission is granted by the corresponding\r
+Copyright Holder. This restriction only applies to the primary font name as\r
+presented to the users.\r
+\r
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\r
+Software shall not be used to promote, endorse or advertise any\r
+Modified Version, except to acknowledge the contribution(s) of the\r
+Copyright Holder(s) and the Author(s) or with their explicit written\r
+permission.\r
+\r
+5) The Font Software, modified or unmodified, in part or in whole,\r
+must be distributed entirely under this license, and must not be\r
+distributed under any other license. The requirement for fonts to\r
+remain under this license does not apply to any document created\r
+using the Font Software.\r
+\r
+TERMINATION\r
+This license becomes null and void if any of the above conditions are\r
+not met.\r
+\r
+DISCLAIMER\r
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\r
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\r
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\r
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\r
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\r
+OTHER DEALINGS IN THE FONT SOFTWARE.\r
diff --git a/web_sources/fonts/Lato/STYLES.css b/web_sources/fonts/Lato/STYLES.css
new file mode 100644 (file)
index 0000000..21d8c8d
--- /dev/null
@@ -0,0 +1,60 @@
+ .lato-thin {
+    font-family: "Lato", sans-serif;
+    font-weight: 100;
+    font-style: normal;
+  }
+  
+  .lato-light {
+    font-family: "Lato", sans-serif;
+    font-weight: 300;
+    font-style: normal;
+  }
+  
+  .lato-regular {
+    font-family: "Lato", sans-serif;
+    font-weight: 400;
+    font-style: normal;
+  }
+  
+  .lato-bold {
+    font-family: "Lato", sans-serif;
+    font-weight: 700;
+    font-style: normal;
+  }
+  
+  .lato-black {
+    font-family: "Lato", sans-serif;
+    font-weight: 900;
+    font-style: normal;
+  }
+  
+  .lato-thin-italic {
+    font-family: "Lato", sans-serif;
+    font-weight: 100;
+    font-style: italic;
+  }
+  
+  .lato-light-italic {
+    font-family: "Lato", sans-serif;
+    font-weight: 300;
+    font-style: italic;
+  }
+  
+  .lato-regular-italic {
+    font-family: "Lato", sans-serif;
+    font-weight: 400;
+    font-style: italic;
+  }
+  
+  .lato-bold-italic {
+    font-family: "Lato", sans-serif;
+    font-weight: 700;
+    font-style: italic;
+  }
+  
+  .lato-black-italic {
+    font-family: "Lato", sans-serif;
+    font-weight: 900;
+    font-style: italic;
+  }
+  
\ No newline at end of file
diff --git a/web_sources/fonts/LeagueMono-VF.woff2 b/web_sources/fonts/LeagueMono-VF.woff2
new file mode 100644 (file)
index 0000000..c6504ce
Binary files /dev/null and b/web_sources/fonts/LeagueMono-VF.woff2 differ
diff --git a/web_sources/fonts/fontawesome-webfont.woff2 b/web_sources/fonts/fontawesome-webfont.woff2
new file mode 100644 (file)
index 0000000..4d13fc6
Binary files /dev/null and b/web_sources/fonts/fontawesome-webfont.woff2 differ
diff --git a/web_sources/root.css b/web_sources/root.css
new file mode 100644 (file)
index 0000000..f237c9a
--- /dev/null
@@ -0,0 +1,68 @@
+@font-face {
+    font-family: "Lato";
+    src: url(fonts/Lato/Lato-Regular.ttf);
+}
+
+:root {
+    --primary-subdued: hsl(254, 88%, 90%);
+    --primary-base: hsl(256, 67%, 59%);
+    --accent-subdued: hsl(31, 66%, 93%);
+    --accent-base: hsl(39, 100%, 71%);
+    --white: hsl(0, 0%, 100%);
+    --off-white: hsl(0, 0%, 96%);
+    --black: hsl(0, 0%, 7%);
+    --bck-col: #8dd8e7;
+    
+    --f-def: "Lato";
+    --fs-reg: 1.25rem;
+    --fs-md: 2.25rem;
+    --fs-lg: 3rem;
+    --fs-xl: 4rem;
+  }
+
+  @layer reset {
+
+    *,
+    *::before,
+    *::after {
+      box-sizing: border-box;
+    }
+
+    h1,
+    h2,
+    h3,
+    h4,
+    h5,
+    h6,
+    p,
+    ul,
+    ol,
+    figure {
+      margin: 0;
+    }
+
+    h1,
+    h2,
+    h3,
+    h4,
+    h5,
+    h6 {
+      font-weight: 500;
+    }
+
+    img {
+      max-width: 100%;
+      display: block;
+    }
+  }
+
+  @layer base {
+    body, html {   
+        font-family: "Lato", sans-serif;
+        line-height: 1.3;    
+        padding: 0.5em;
+        color: var(--black,black);
+        background-color: var(--bck-col, #8dd8e7);    
+        margin: 0;
+    }
+  }
\ No newline at end of file
diff --git a/web_sources/style-kevin-powell.css b/web_sources/style-kevin-powell.css
new file mode 100644 (file)
index 0000000..a2da04a
--- /dev/null
@@ -0,0 +1,285 @@
+@font-face {
+  font-family: "DM Sans";
+  font-weight: 400 500;
+  src: url("fonts/DMSans/DMSans-VariableFont_opsz,wght.ttf");
+}
+
+@font-face {
+  font-family: "DM Sans";
+  font-style: italic;
+  font-weight: 400 500;
+  src: url("fonts/DMSans/DMSans-Italic-VariableFont_opsz,wght.ttf");
+}
+
+:root {
+  --primary-subdued: hsl(254, 88%, 90%);
+  --primary-base: hsl(256, 67%, 59%);
+  --accent-subdued: hsl(31, 66%, 93%);
+  --accent-base: hsl(39, 100%, 71%);
+  --white: hsl(0, 0%, 100%);
+  --off-white: hsl(0, 0%, 96%);
+  --black: hsl(0, 0%, 7%);
+
+  --fs-reg: 1.25rem;
+
+  --fs-md: 2.25rem;
+  --fs-lg: 3rem;
+  --fs-xl: 4rem;
+}
+
+@layer reset {
+
+  *,
+  *::before,
+  *::after {
+    box-sizing: border-box;
+  }
+
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6,
+  p,
+  ul,
+  ol,
+  figure {
+    margin: 0;
+  }
+
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6 {
+    font-weight: 500;
+  }
+
+  img {
+    max-width: 100%;
+    display: block;
+  }
+}
+
+@layer base {
+  html {
+    font-family: "DM Sans", sans-serif;
+    line-height: 1.3;
+  }
+
+  body {
+    margin: 32px;
+    color: var(--black);
+    font-size: var(--fs-reg);
+    background: var(--off-white);
+  }
+
+  h1,
+  h2 {
+    color: var(--heading-foreground, inherit);
+    font-size: var(--heading-font-size, var(--fs-md));
+    line-height: 1.1;
+    text-wrap: balance;
+
+    span {
+      display: var(--heading-span-display, inline);
+      color: var(--heading-span-foreground, var(--black));
+      font-size: var(--heading-span-font-size, inherit);
+      font-style: var(--heading-span-style, normal);
+    }
+  }
+}
+
+@layer layout {
+  .bento-grid {
+    display: grid;
+    gap: 24px;
+    max-inline-size: 1200px;
+    margin-inline: auto;
+    grid-template-areas:
+      'one'
+      'two'
+      'three'
+      'four'
+      'five'
+      'six'
+      'seven'
+      'eight';
+
+    @media (width > 660px) {
+      grid-template-areas:
+        "one one"
+        "two three"
+        "four six"
+        "four seven"
+        "five eight"
+      ;
+    }
+
+    @media (width > 960px) {
+      grid-template-areas:
+        "seven one one four"
+        "seven two three four"
+        "eight two three four"
+        "eight six five five"
+      ;
+    }
+  }
+
+  .bento-grid>* {
+    color: var(--bento-card-foreground, var(--black));
+    background-color: var(--bento-card-surface, var(--white));
+    padding: var(--bento-card-padding, 32px);
+    border-radius: var(--bento-card-border-radius, 21px);
+
+    overflow: clip;
+
+    display: grid;
+    gap: var(--bento-card-gap, 32px);
+    align-content: var(--bento-card-vertical-alignment, start);
+    align-items: var(--bento-card-vertical-alignment, start);
+    justify-items: var(--bento-card-horizontal-alignment, start);
+    text-align: var(--bento-card-horizontal-alignment, start);
+  }
+
+  .bento-grid img {
+    max-width: var(--bento-card-image-width, 100%);
+    width: var(--bento-card-image-width, 100%);
+    order: var(--bento-card-image-order);
+  }
+
+  .bento-grid> :nth-child(1) {
+    --heading-font-size: var(--fs-xl);
+    --heading-span-foreground: var(--accent-base);
+    --bento-card-foreground: var(--white);
+    --bento-card-surface: var(--primary-base);
+    --bento-card-padding: 48px;
+    --bento-card-horizontal-alignment: center;
+    --bento-card-image-width: 70%;
+    --bento-card-gap: 16px;
+
+    @media (width > 960px) {
+      --bento-card-image-width: 45%;
+    }
+
+    grid-area: one;
+  }
+
+  .bento-grid> :nth-child(2) {
+    --bento-card-image-order: -1;
+
+    grid-area: two;
+
+    @media (width > 960px) {
+      --bento-card-image-width: 150%;
+    }
+
+    /* fixing shadow issue in asset */
+    >img {
+      filter: drop-shadow(0 0 1rem hsl(0 0% 0% / .25));
+      border-radius: 100vw;
+      /* box-shadow: 0 0 1rem hsl(0 0% 0%); */
+    }
+  }
+
+  .bento-grid> :nth-child(3) {
+    --bento-card-surface: var(--accent-base);
+
+    grid-area: three;
+
+
+    >img {
+      --bento-card-image-width: 75%;
+
+      margin-bottom: -55px;
+
+      @media (width > 960px) {
+        --bento-card-image-width: 100%;
+        margin-bottom: -125px;
+      }
+    }
+  }
+
+  .bento-grid> :nth-child(4) {
+    --bento-card-horizontal-alignment: center;
+    --bento-card-surface: var(--primary-subdued);
+
+    grid-area: four;
+
+    @media (width > 960px) {
+      --bento-card-image-width: 180%;
+      --bento-card-horizontal-alignment: start;
+      --bento-card-vertical-alignment: center;
+    }
+
+  }
+
+  .bento-grid> :nth-child(5) {
+    --bento-card-horizontal-alignment: center;
+    --bento-card-foreground: var(--white);
+    --bento-card-surface: var(--primary-base);
+    --bento-card-image-width: 75%;
+    --bento-card-image-order: -1;
+
+    grid-area: five;
+
+    @media (width > 960px) {
+      --bento-card-gap: 16px;
+      --bento-card-image-width: 100%;
+      --bento-card-vertical-alignment: center;
+      --bento-card-horizontal-alignment: start;
+      grid-template-columns: 1fr 1fr;
+    }
+  }
+
+  .bento-grid> :nth-child(6) {
+    --heading-font-size: var(--fs-xl);
+    --heading-span-display: block;
+    --heading-span-font-size: var(--fs-reg);
+
+    --bento-card-image-width: 60%;
+
+    grid-area: six;
+
+    @media (width > 960px) {
+      --bento-card-image-width: 80%;
+    }
+
+  }
+
+  .bento-grid> :nth-child(7) {
+    --heading-span-foreground: var(--primary-base);
+    --heading-span-style: italic;
+
+    --bento-card-surface: var(--accent-subdued);
+    --bento-card-image-width: 60%;
+
+
+    grid-area: seven;
+
+    @media (width > 960px) {
+      --bento-card-image-width: 100%;
+      --bento-card-vertical-alignment: center;
+    }
+  }
+
+  .bento-grid> :nth-child(8) {
+    --bento-card-surface: var(--accent-base);
+    --bento-card-image-width: 60%;
+
+    grid-area: eight;
+
+    @media (width > 960px) {
+      --bento-card-image-width: 105%;
+      --bento-card-vertical-alignment: center;
+    }
+  }
+}
+
+@layer utilities {
+  .visually-first {
+    order: -1;
+  }
+}
\ No newline at end of file