--- /dev/null
+.vscode
+system
+wsrc
\ No newline at end of file
#!/usr/bin/perl
package PerlCNFWebServer;
use lib::relative 'system/modules';
-use lib::relative 'apps';no warnings qw(experimental::signatures);
+use lib::relative 'apps';
use PerlCNFWebServerBase;
-use lib '/home/will/PerlCNFWEBServer/system/modules';
use IO::Socket::SSL;
use HTTP::Server::Simple::CGI;
use base qw(HTTP::Server::Simple::CGI);
-use Gzip::Faster;
+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'";
our $cnf_index;
our %locals;
+our %includes;
our $INDEX_FILE = CNFGlobalFile -> new('index.cnf');
our $LOCAL_PATH = $0;
our %TYPE_HANDLER = (
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);
+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 $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 $gzip?gzip($content):$content;
}
-sub asBinFile ($cgi, $request_headers, $type, $full_path){
+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}});
$file -> binary();
}
-sub error_to_browser ($cgi, $err){
+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",
+ "server: ".__PACKAGE__."/".CNFParser::VERSION(),"\n\n",
$cgi->start_html(">>Server Error!<"),
$cgi ->h2("<font color='maroon'>ServerError@ ⇒ </font> $page_link"),
$cgi->pre($err),
sub deliverByParticulars ($cgi, $request_header, $dir, $full_path) {
$full_path =~ m/\.(\w+)$/; my $type = $1;
- my $handler = $TYPE_HANDLER{$type};
+ my $handler = $TYPE_HANDLER{$type};
if($handler && -e $full_path){
$handler -> ($cgi, $request_header, $type, $full_path);
}else{
}
}
-
sub obtainDirListingHTML ($dir) {
my $ret;
my $html = listFiles($dir);
sub index($cgi,$hdrs) {
if (check_if_has_changed($INDEX_FILE)){
try{
-
$cnf_index = CNFParser -> new (
$INDEX_FILE,{
DO_ENABLED => 1, HAS_EXTENSIONS=>1,
}
);
$locals{$INDEX_FILE} = \$cnf_index;
-
+
}catch($e){
- $cnf_server -> error($e);
+ $cnf_server -> error($e);
error_to_browser($cgi, $e);
return
}
}
sub check_if_has_changed ($config_file){
- my $entry = $locals{$config_file};
- if($entry){
+ my $entry = $locals{$config_file->{path}};
+ if($entry){$entry = $$entry;
if($config_file -> changed()){
- $cnf_server -> log("Config has changed for: ". $$entry->{CNF_CONTENT});
+ $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});
+ $cnf_server -> log("Config load initiated for: ". $config_file->{path});
return 1
}
}
$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};
+ $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",
- "last-modified: ",$last_modified->toSchlong(),"\n",
+ 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){
- print qq(<!DOCTYPE html>\n<html lang="en"><body>\n<pre>\n)
+ $content = qq(<!DOCTYPE html>\n<html lang="en"><body>\n<pre>\n)
}else{
- print $$html_head
+ $content = $$html_head
}
- print $$html_body;
+ $content .= $$html_body;
if(not $html_foot ){
- print qq(\n</pre></body></html>);
+ $content .= qq(\n</pre></body></html>);
}else{
- print $$html_foot;
+ $content .= $$html_foot;
}
+ print $gzip ? gzip($content):$content;
}
sub accept_hook {
if(isTrue($SSL{enabled})){
- my $self = shift; $self->SUPER::accept_hook(@_);
+ my $self = shift; $self->SUPER::accept_hook(@_);
my $fh = $self->stdio_handle;
my $newfh =
- IO::Socket::SSL->start_SSL( $fh,
+ IO::Socket::SSL->start_SSL( $fh,
SSL_server => $SSL{server},
SSL_use_cert => $SSL{use_cert},
SSL_cert_file => $SSL{cert_file},
}
}
+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');
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]; $config = CNFGlobalFile->new($config);
- $prp_name = $pair[1];
+ $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($config)){
+
+ if(!$cnf_app or check_if_has_changed($cnf_file)){
try{
- $cnf_app = CNFParser->new($config, {DO_ENABLED => 1, '%LOG' => \%log, TZ => $cnf_server->{TZ}});
+ $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);
+ $cnf_server -> error($e);
+ error_to_browser($cgi, $e);
return
}
}
my $pid = isTrue($cnf_server->const('run_as_background_process')) ?
PerlCNFWebServer->new($cnf_server->{port})->background() :
PerlCNFWebServer->new($cnf_server->{port})->run();
- print "Use 'kill $pid' to stop server.\n";
+ 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;
--- /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