--- /dev/null
+.vscode
+system
+wsrc
\ No newline at end of file
--- /dev/null
+#!/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@ ⇒ </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 →</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> ‐ $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/</</gs;
+ $property =~ s/>/>/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
--- /dev/null
+# 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).
--- /dev/null
+
+/** 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;
+ }
+
+}
+
+
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+ .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
--- /dev/null
+@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
--- /dev/null
+@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