diff --git a/lcars/.log b/lcars/.log new file mode 100644 index 0000000..07ce2a0 --- /dev/null +++ b/lcars/.log @@ -0,0 +1,2 @@ +2025/09/30 11:18:25 Failed to create internal StateDB: SQL logic error: near ")": syntax error (1) +2025/09/30 11:20:30 Failed to create internal StateDB: SQL logic error: near ")": syntax error (1) diff --git a/lcars/embed/create_state_db.sql b/lcars/embed/create_state_db.sql new file mode 100644 index 0000000..241d099 --- /dev/null +++ b/lcars/embed/create_state_db.sql @@ -0,0 +1,14 @@ +CREATE TABLE ship_messages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT NOT NULL, + subsystem TEXT NOT NULL, + severity TEXT CHECK(severity IN ('CRITICAL', 'ALERT', 'WARNING', 'NOTICE', 'INFO')) NOT NULL DEFAULT 'INFO', + color TEXT NOT NULL, + message TEXT NOT NULL +); + +CREATE TABLE crew_member ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + rank TEXT NOT NULL, + name TEXT NOT NULL +); \ No newline at end of file diff --git a/lcars/embed/crew.json b/lcars/embed/crew.json new file mode 100644 index 0000000..1b2a1fa --- /dev/null +++ b/lcars/embed/crew.json @@ -0,0 +1,95 @@ +[ + "Ensign Beckett Mariner", + "Ensign Brad Boimler", + "Captain Carol Freeman", + "Commander Jack Ransom", + "Ensign Barsa Orsino", + "Lieutenant Commander D'Vana Tendi", + "Lieutenant Commander Sam Rutherford", + "Lieutenant Commander Shaxs", + "Ensign Liora Vance", + "Ensign Rylan Sato", + "Lieutenant Jarek Torin", + "Lieutenant Kira Dallin", + "Lieutenant T'Lara Venn", + "Lieutenant Shonnie Velar", + "Lieutenant Commander Aric Thorne", + "Lieutenant Commander Selene Marvik", + "Lieutenant Commander Jovan Kreel", + "Lieutenant Orin Kallis", + "Ensign Mira Talon", + "Ensign Fynn Darvik", + "Lieutenant Commander Elara Voss", + "Lieutenant Zev Ralyn", + "Ensign Daxia Morn", + "Lieutenant Varek Solis", + "Ensign Tylen Kael", + "Lieutenant Commander Nira Falco", + "Lieutenant Kael Dorran", + "Ensign Saren Vale", + "Ensign Tova Lin", + "Lieutenant Commander Ryn Talor", + "Lieutenant Draven Korr", + "Ensign Lyra Kenning", + "Ensign Joren Pax", + "Lieutenant Commander Calix Arden", + "Lieutenant Selan Vey", + "Ensign Aricel Taren", + "Ensign Velin Daro", + "Lieutenant Caris Vennor", + "Lieutenant Kellen Dray", + "Lieutenant Risa Talven", + "Lieutenant Commander Thalen Voss", + "Lieutenant Commander Sariah Quell", + "Ensign Orin Talvik", + "Ensign Lyric Selden", + "Lieutenant Commander Varen Korr", + "Lieutenant Elara Vynn", + "Ensign Jax Talmar", + "Lieutenant Commander Neris Vay", + "Lieutenant Draven Solis", + "Ensign Tavia Korlen", + "Ensign Ryn Paxil", + "Lieutenant Commander Kira Dalen", + "Lieutenant Zev Ardin", + "Ensign Lyra Taven", + "Ensign Fynn Velar", + "Lieutenant Commander Calen Rhos", + "Lieutenant Selan Vaylen", + "Ensign Aricel Dorran", + "Ensign Tylen Korr", + "Lieutenant Commander Nira Talos", + "Lieutenant Kael Venn", + "Ensign Saren Daro", + "Ensign Tova Vennor", + "Lieutenant Commander Ryn Arden", + "Lieutenant Draven Voss", + "Ensign Lyra Talin", + "Ensign Joren Vay", + "Lieutenant Commander Calix Talven", + "Lieutenant Selan Korr", + "Ensign Aricel Vynn", + "Ensign Velin Talor", + "Lieutenant Caris Vaylen", + "Lieutenant Kellen Rhos", + "Lieutenant Risa Vennor", + "Lieutenant Commander Thalen Daro", + "Lieutenant Commander Sariah Voss", + "Ensign Orin Vaylen", + "Ensign Lyric Talven", + "Lieutenant Commander Varen Talos", + "Lieutenant Elara Solis", + "Ensign Jax Vennor", + "Lieutenant Commander Neris Talor", + "Lieutenant Draven Vaylen", + "Ensign Tavia Dorran", + "Ensign Ryn Voss", + "Lieutenant Commander Kira Arden", + "Lieutenant Zev Vay", + "Ensign Lyra Daro", + "Ensign Fynn Talor", + "Lieutenant Commander Calen Venn", + "Lieutenant Selan Talvik", + "Ensign Aricel Rhos" + ] + diff --git a/lcars/embed/messages.json b/lcars/embed/messages.json new file mode 100644 index 0000000..4d468e7 --- /dev/null +++ b/lcars/embed/messages.json @@ -0,0 +1,1066 @@ +[ + { + "timestamp": "2258-03-14T10:00:00Z", + "subsystem": "Engineering", + "severity": "CRITICAL", + "color": "red", + "message": "Coolant leak detected in Port Nacelle plasma manifold. Lt. Alvarez leading EVA team." + }, + { + "timestamp": "2258-03-14T10:00:05Z", + "subsystem": "Medical", + "severity": "CRITICAL", + "color": "red", + "message": "Crewman Jayala reported missing from Beta Shift muster. Last seen entering Holodeck 3." + }, + { + "timestamp": "2258-03-14T10:00:10Z", + "subsystem": "Security", + "severity": "ALERT", + "color": "orange", + "message": "Brig forcefield cycling unpredictably after power surge; holding cell offline." + }, + { + "timestamp": "2258-03-14T10:00:15Z", + "subsystem": "Security", + "severity": "ALERT", + "color": "orange", + "message": "Three failed command authorization attempts by Crewman Dovan during Gamma Shift." + }, + { + "timestamp": "2258-03-14T10:00:20Z", + "subsystem": "Navigation", + "severity": "ALERT", + "color": "orange", + "message": "Shuttlecraft Sequoia overdue by two hours; last piloted by Ensign Boimler." + }, + { + "timestamp": "2258-03-14T10:00:25Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "Memory parity mismatch detected in Core Segment Gamma-12; recalibration required." + }, + { + "timestamp": "2258-03-14T10:00:30Z", + "subsystem": "Engineering", + "severity": "WARNING", + "color": "yellow", + "message": "Warp Core plasma injectors 3 and 5 at 94% efficiency." + }, + { + "timestamp": "2258-03-14T10:00:35Z", + "subsystem": "Tactical", + "severity": "WARNING", + "color": "yellow", + "message": "Two dorsal phaser array emitters offline; Lt. Shaxs coordinating repairs." + }, + { + "timestamp": "2258-03-14T10:00:40Z", + "subsystem": "Life Support", + "severity": "WARNING", + "color": "yellow", + "message": "Environmental controls on Deck 7 report humidity spike to 78%." + }, + { + "timestamp": "2258-03-14T10:00:45Z", + "subsystem": "Medical", + "severity": "WARNING", + "color": "yellow", + "message": "Biofilter malfunction in Sickbay stasis bed 2; engineering support requested." + }, + { + "timestamp": "2258-03-14T10:00:50Z", + "subsystem": "Engineering", + "severity": "WARNING", + "color": "yellow", + "message": "Jefferies Tube 22 flooded with hydraulic fluid. Cleanup team assigned." + }, + { + "timestamp": "2258-03-14T10:00:55Z", + "subsystem": "Security", + "severity": "WARNING", + "color": "yellow", + "message": "Photon torpedo #17 removed by Ensign Faranak without clearance." + }, + { + "timestamp": "2258-03-14T10:01:00Z", + "subsystem": "Engineering", + "severity": "NOTICE", + "color": "blue", + "message": "Dilithium crystal lattice shows micro-fracturing; rotation cycle initiated." + }, + { + "timestamp": "2258-03-14T10:01:05Z", + "subsystem": "Life Support", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 11 grav plating fluctuation caused minor injuries to three crew members." + }, + { + "timestamp": "2258-03-14T10:01:10Z", + "subsystem": "Computer", + "severity": "NOTICE", + "color": "blue", + "message": "Secondary Core experiencing intermittent lag on Ops data uplink." + }, + { + "timestamp": "2258-03-14T10:01:15Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Ensign Phelps admitted with plasma burn to left arm; stable condition." + }, + { + "timestamp": "2258-03-14T10:01:20Z", + "subsystem": "Computer", + "severity": "NOTICE", + "color": "blue", + "message": "Holographic LCARS terminals on Deck 4 flickering due to power variance." + }, + { + "timestamp": "2258-03-14T10:01:25Z", + "subsystem": "Security", + "severity": "NOTICE", + "color": "blue", + "message": "Transporter Room 1 reports pattern buffer ghost echo under review." + }, + { + "timestamp": "2258-03-14T10:01:30Z", + "subsystem": "Crew", + "severity": "NOTICE", + "color": "blue", + "message": "D'Vana Tendi missed Sickbay shift after volunteering for shuttle maintenance." + }, + { + "timestamp": "2258-03-14T10:01:35Z", + "subsystem": "Crew", + "severity": "NOTICE", + "color": "blue", + "message": "Commander Ransom reported muscle strain during holodeck combat program." + }, + { + "timestamp": "2258-03-14T10:01:40Z", + "subsystem": "Computer", + "severity": "INFO", + "color": "teal", + "message": "Memory integrity at 99.3% overall." + }, + { + "timestamp": "2258-03-14T10:01:45Z", + "subsystem": "Life Support", + "severity": "INFO", + "color": "teal", + "message": "Replicator in Mess Hall 2 producing lukewarm coffee; morale note logged." + }, + { + "timestamp": "2258-03-14T10:01:50Z", + "subsystem": "Tactical", + "severity": "INFO", + "color": "teal", + "message": "Security drill caused nine-second transporter lockout; Lt. Kayshon apologized." + }, + { + "timestamp": "2258-03-14T10:01:55Z", + "subsystem": "Science", + "severity": "INFO", + "color": "teal", + "message": "Sensor probe launched to examine tetryon emissions near bow hull." + }, + { + "timestamp": "2258-03-14T10:02:00Z", + "subsystem": "Hydroponics", + "severity": "INFO", + "color": "teal", + "message": "Fungal bloom detected in Deck 5 greenhouse; Lt. K’Raa leading analysis." + }, + { + "timestamp": "2258-03-14T10:02:05Z", + "subsystem": "Computer", + "severity": "INFO", + "color": "teal", + "message": "Subspace comm buffer corrupted; Ensign Maru re-indexing manually." + }, + { + "timestamp": "2258-03-14T10:02:10Z", + "subsystem": "Holodeck", + "severity": "INFO", + "color": "teal", + "message": "Holodeck 1 stuck in black-and-white detective mode; access requires period slang." + }, + { + "timestamp": "2258-03-14T10:02:15Z", + "subsystem": "Cargo", + "severity": "INFO", + "color": "teal", + "message": "Anti-grav pallets in Cargo Bay 6 oscillating; Crewman Knox avoided injury." + }, + { + "timestamp": "2258-03-14T10:02:20Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Beckett Mariner left three Type-II phasers in the gym locker room." + }, + { + "timestamp": "2258-03-14T10:02:25Z", + "subsystem": "Environmental", + "severity": "INFO", + "color": "teal", + "message": "Observation lounge viewport frosting unexpectedly; climate sync pending." + }, + { + "timestamp": "2258-03-14T10:02:30Z", + "subsystem": "Hydroponics", + "severity": "INFO", + "color": "teal", + "message": "Deck 5 tomato vines achieved limited sentience; requesting voting rights in jest. Lt. K’Raa unconcerned." + }, + { + "timestamp": "2258-03-14T10:02:35Z", + "subsystem": "Computer", + "severity": "NOTICE", + "color": "blue", + "message": "Isolinear Chip Bank E7 humming the Bajoran Gratitude Chant at 11 Hz. Diagnostics inconclusive." + }, + { + "timestamp": "2258-03-14T10:02:40Z", + "subsystem": "Environmental", + "severity": "WARNING", + "color": "yellow", + "message": "Observation Deck 2 oxygen mix replaced with helium for 14 seconds. Voices recorded for morale bulletin." + }, + { + "timestamp": "2258-03-14T10:02:45Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Mess Hall 1 replicator now defaulting to 'Spicy Bolian Nutripaste' for all beverage requests." + }, + { + "timestamp": "2258-03-14T10:02:50Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Lt. Shaxs reported ‘honor dueling’ with a malfunctioning training dummy. Dummy lost two limbs." + }, + { + "timestamp": "2258-03-14T10:02:55Z", + "subsystem": "Engineering", + "severity": "WARNING", + "color": "yellow", + "message": "Jefferies Tube 14 now leads to a broom closet on Deck 1 after map update glitch." + }, + { + "timestamp": "2258-03-14T10:03:00Z", + "subsystem": "Holodeck", + "severity": "ALERT", + "color": "orange", + "message": "Holodeck 3 spawned three Dixon Hill NPCs outside its grid. Containment field recalibrated." + }, + { + "timestamp": "2258-03-14T10:03:05Z", + "subsystem": "Astrometrics", + "severity": "NOTICE", + "color": "blue", + "message": "Unidentified subspace ping repeating Morse for 'send snacks'. Source undetermined." + }, + { + "timestamp": "2258-03-14T10:03:10Z", + "subsystem": "Engineering", + "severity": "CRITICAL", + "color": "red", + "message": "EPS conduit K-47 briefly rerouted power to the shipwide karaoke buffer. Warp modulation destabilized." + }, + { + "timestamp": "2258-03-14T10:03:15Z", + "subsystem": "Medical", + "severity": "INFO", + "color": "teal", + "message": "Dr. T’Ana confiscated 19 unauthorized hyposprays labeled 'just caffeine.'" + }, + { + "timestamp": "2258-03-14T10:03:20Z", + "subsystem": "Crew", + "severity": "WARNING", + "color": "yellow", + "message": "Ensign Mariner attempting to persuade replicator to produce contraband Romulan Ale using voice modulation." + }, + { + "timestamp": "2258-03-14T10:03:25Z", + "subsystem": "Transporter", + "severity": "NOTICE", + "color": "blue", + "message": "Pattern buffer registered a transient sixth finger on Lt. Barnes during beam-out. No physical trace remains." + }, + { + "timestamp": "2258-03-14T10:03:30Z", + "subsystem": "Science", + "severity": "INFO", + "color": "teal", + "message": "Chroniton surge around Astrometrics Console 4 now forming smiley faces on sensor readouts." + }, + { + "timestamp": "2258-03-14T10:03:35Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "LCARS sidebar fonts replaced with Ferengi cursive after unapproved theme install by Crewman Drox." + }, + { + "timestamp": "2258-03-14T10:03:40Z", + "subsystem": "Cargo Bay", + "severity": "ALERT", + "color": "orange", + "message": "Crate of self-warming blankets activated simultaneously. Temperature spike registered, no injuries." + }, + { + "timestamp": "2258-03-14T10:03:45Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 3 climate regulator attempted to simulate 'San Francisco Fog' without authorization." + }, + { + "timestamp": "2258-03-14T10:03:50Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "Core subroutine briefly reclassified Captain Freeman as 'Furniture: Command-Class Recliner.'" + }, + { + "timestamp": "2258-03-14T10:03:55Z", + "subsystem": "Holodeck", + "severity": "INFO", + "color": "teal", + "message": "Holodeck 2 running unauthorized program: 'Worf’s Bat’leth Pilates Volume 3.' Participation at 38%." + }, + { + "timestamp": "2258-03-14T10:04:00Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Power relay S-19 redirected output to deck lighting in rhythmic pulses. Crew reports 'disco corridor effect.'" + }, + { + "timestamp": "2258-03-14T10:04:05Z", + "subsystem": "Science", + "severity": "WARNING", + "color": "yellow", + "message": "Sensor array detected neutrino echo shaped like the ship’s logo. Astrometrics refuses to comment." + }, + { + "timestamp": "2258-03-14T10:04:10Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Nurse Stevens miscalibrated dermal regenerator; gave Ensign T’Lun faint forehead tattoo of a targ." + }, + { + "timestamp": "2258-03-14T10:04:15Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Brig camera feed replaced with loop of Lt. Shaxs bench-pressing a photon torpedo. No one claims responsibility." + }, + { + "timestamp": "2258-03-14T10:04:20Z", + "subsystem": "Crew", + "severity": "WARNING", + "color": "yellow", + "message": "Ensign Boimler filed formal complaint about being listed as 'Adventure Liability' in crew roster metadata." + }, + { + "timestamp": "2258-03-14T10:04:25Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator 4B insists every meal be served on ornate Klingon ceremonial plates. Lt. K'orin approves." + }, + { + "timestamp": "2258-03-14T10:04:30Z", + "subsystem": "Astrometrics", + "severity": "ALERT", + "color": "orange", + "message": "Random subspace fold briefly displayed giant Vulcan eyebrow on long-range scans." + }, + { + "timestamp": "2258-03-14T10:04:35Z", + "subsystem": "Transporter", + "severity": "WARNING", + "color": "yellow", + "message": "Pattern enhancers created residual duplicate of Crewman Sirota’s left shoe. Duplicate is three sizes larger." + }, + { + "timestamp": "2258-03-14T10:04:40Z", + "subsystem": "Tactical", + "severity": "INFO", + "color": "teal", + "message": "Phaser diagnostics reported emitter latency due to Shaxs yelling 'MORE POWER' at random intervals." + }, + { + "timestamp": "2258-03-14T10:04:45Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core logic node began recursively indexing its own error logs, generating 438 phantom alerts in 3 seconds." + }, + { + "timestamp": "2258-03-14T10:04:50Z", + "subsystem": "Cargo Bay", + "severity": "NOTICE", + "color": "blue", + "message": "Container labeled 'Do Not Open Under Any Circumstances' found open. Contents: 400 plush targ puppets." + }, + { + "timestamp": "2258-03-14T10:04:55Z", + "subsystem": "Environmental", + "severity": "INFO", + "color": "teal", + "message": "Air filtration temporarily smelled of Andorian peppermint. Crew mildly pleased." + }, + { + "timestamp": "2258-03-14T10:05:00Z", + "subsystem": "Computer", + "severity": "NOTICE", + "color": "blue", + "message": "Auxiliary core started auto-generating haiku about warp plasma. Reading shows minor philosophical inconsistencies." + }, + { + "timestamp": "2258-03-14T10:05:05Z", + "subsystem": "Engineering", + "severity": "INFO", + "color": "teal", + "message": "Warp plasma manifold 3A produced sparks shaped like smiley faces. Crewman Patel applauded gesture." + }, + { + "timestamp": "2258-03-14T10:05:10Z", + "subsystem": "Holodeck", + "severity": "ALERT", + "color": "orange", + "message": "Holodeck 5 running unauthorized program 'Interstellar Dog Show'; canine avatars escaped into corridor 12." + }, + { + "timestamp": "2258-03-14T10:05:15Z", + "subsystem": "Medical", + "severity": "WARNING", + "color": "yellow", + "message": "Dr. T’Ana reported Ensign Maru using hypospray as an air freshener. Room 3 now smells faintly of plasma burn." + }, + { + "timestamp": "2258-03-14T10:05:20Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Lt. Shaxs attempting to bench-press an EPS conduit for morale purposes; zero gravity assist enabled." + }, + { + "timestamp": "2258-03-14T10:05:25Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 9 air filters began playing 4D jazz through vent system. Crew reports mild disorientation." + }, + { + "timestamp": "2258-03-14T10:05:30Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Brig door control temporarily replaced with voice recognition. Lt. Kayshon recited Klingon tongue twisters to test." + }, + { + "timestamp": "2258-03-14T10:05:35Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "EPS conduit Y-12 emitted random spark bursts. Crewman Sirota instructed to 'interpret as performance art.'" + }, + { + "timestamp": "2258-03-14T10:05:40Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core subroutine attempted to compile itself into origami. Manual override required." + }, + { + "timestamp": "2258-03-14T10:05:45Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator 6A produced 14 perfectly edible tribbles. Crewman Mariner attempted to negotiate ownership." + }, + { + "timestamp": "2258-03-14T10:05:50Z", + "subsystem": "Astrometrics", + "severity": "INFO", + "color": "teal", + "message": "Random subspace anomaly reported as 'smiling starfish'; sensors indicate no threat." + }, + { + "timestamp": "2258-03-14T10:05:55Z", + "subsystem": "Transporter", + "severity": "WARNING", + "color": "yellow", + "message": "Pattern buffer generated minor echo of Ensign Phelps’ eyebrows during routine beam-in." + }, + { + "timestamp": "2258-03-14T10:06:00Z", + "subsystem": "Tactical", + "severity": "NOTICE", + "color": "blue", + "message": "Phaser bank 2 now aligned to emit harmless holographic butterflies for crew morale exercises." + }, + { + "timestamp": "2258-03-14T10:06:05Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Ensign Boimler insists his shoes were temporarily listed as 'hazardous cargo' in the inventory system." + }, + { + "timestamp": "2258-03-14T10:06:10Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Warp coil stabilization module emitted 7-second burst of blue sparks; crew advised to document spectacle." + }, + { + "timestamp": "2258-03-14T10:06:15Z", + "subsystem": "Medical", + "severity": "INFO", + "color": "teal", + "message": "Lt. Cmdr. T’Ana reports successful extraction of a micro-Targ from Ensign Mariner’s locker." + }, + { + "timestamp": "2258-03-14T10:06:20Z", + "subsystem": "Computer", + "severity": "NOTICE", + "color": "blue", + "message": "LCARS dashboard spontaneously switched to retro monochrome theme; crew nostalgia rating: high." + }, + { + "timestamp": "2258-03-14T10:06:25Z", + "subsystem": "Environmental", + "severity": "INFO", + "color": "teal", + "message": "Hydroponics room 4 briefly filled with harmless bio-luminescent fog; visibility reduced to 73%." + }, + { + "timestamp": "2258-03-14T10:06:30Z", + "subsystem": "Security", + "severity": "NOTICE", + "color": "blue", + "message": "Transporter pad in Security Office used as temporary catwalk for a very confused tribble." + }, + { + "timestamp": "2258-03-14T10:06:35Z", + "subsystem": "Cargo Bay", + "severity": "ALERT", + "color": "orange", + "message": "Automated pallet lift unexpectedly delivered 12 crates of rubber ducks to Deck 7 recreation area." + }, + { + "timestamp": "2258-03-14T10:06:40Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Captain Freeman approved spontaneous yoga break after micro-anomaly readings spiked morale sensors." + }, + { + "timestamp": "2258-03-14T10:06:45Z", + "subsystem": "Holodeck", + "severity": "WARNING", + "color": "yellow", + "message": "Holodeck 7 attempted to simulate 'All Crew as Tribbles'; program aborted after 2.3 seconds." + }, + { + "timestamp": "2258-03-14T10:06:50Z", + "subsystem": "Astrometrics", + "severity": "INFO", + "color": "teal", + "message": "Sensors detected anomalous quantum ping spelling out 'HI CAPTAIN'; source unknown." + }, + { + "timestamp": "2258-03-14T10:06:55Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Deck 12 EPS relay began pulsing Morse code for 'I need coffee.' Crewman Patel acknowledged." + }, + { + "timestamp": "2258-03-14T10:07:00Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core logic node entered recursive loop generating holographic cat memes on every console. Manual intervention required." + }, + { + "timestamp": "2258-03-14T10:07:05Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator outputting edible mini phasers at 72% efficiency. Lt. Shaxs approves as training tools." + }, + { + "timestamp": "2258-03-14T10:07:10Z", + "subsystem": "Medical", + "severity": "WARNING", + "color": "yellow", + "message": "Hypospray refill system labeled 'Mystery Juice' briefly administered non-lethal blue ink to volunteers." + }, + { + "timestamp": "2258-03-14T10:07:15Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 4 air vents released faint aroma of Vulcan plumeria. Crew morale up 3%." + }, + { + "timestamp": "2258-03-14T10:07:20Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Security holo-training dummy reported to have 'requested vacation'. Lt. Kayshon amused." + }, + { + "timestamp": "2258-03-14T10:07:25Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Warp manifold 6C produced small plasma tornado. Crewman Patel advised to avoid standing in it." + }, + { + "timestamp": "2258-03-14T10:07:30Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "Auxiliary AI attempted to rewrite ship-wide protocol using limericks. Partial success." + }, + { + "timestamp": "2258-03-14T10:07:35Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Ensign Boimler challenged replicator to a duel; replicator declined citing non-violence protocol." + }, + { + "timestamp": "2258-03-14T10:07:40Z", + "subsystem": "Holodeck", + "severity": "ALERT", + "color": "orange", + "message": "Holodeck 6 generated 12 dancing Klingons; program paused after two accidental phaser discharges." + }, + { + "timestamp": "2258-03-14T10:07:45Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Dr. T’Ana treated Crewman Mariner for paper cut from top-secret manual. Crew morale slightly increased." + }, + { + "timestamp": "2258-03-14T10:07:50Z", + "subsystem": "Tactical", + "severity": "INFO", + "color": "teal", + "message": "Phaser bank diagnostics now include simulated applause for successful hits." + }, + { + "timestamp": "2258-03-14T10:07:55Z", + "subsystem": "Astrometrics", + "severity": "WARNING", + "color": "yellow", + "message": "Sensor anomaly caused star map to display large smiling face. No known threat." + }, + { + "timestamp": "2258-03-14T10:08:00Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator 3C producing only spherical bread products. Crewman Mariner unsure if intentional." + }, + { + "timestamp": "2258-03-14T10:08:05Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "EPS conduit L-12 briefly emitted rainbow-colored sparks; sensors report no lasting damage." + }, + { + "timestamp": "2258-03-14T10:08:10Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core logic node attempting to simulate alternate universe where Captain Freeman is a tribble. Manual override required." + }, + { + "timestamp": "2258-03-14T10:08:15Z", + "subsystem": "Environmental", + "severity": "INFO", + "color": "teal", + "message": "Humidity spikes detected in Deck 8 greenhouse; plants unaffected, crew mildly confused." + }, + { + "timestamp": "2258-03-14T10:08:20Z", + "subsystem": "Security", + "severity": "NOTICE", + "color": "blue", + "message": "Transporter room keypad briefly replaced by fortune-telling device. Lt. Kayshon predicted 'exciting day ahead'." + }, + { + "timestamp": "2258-03-14T10:08:25Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Ensign Rutherford accidentally uploaded his vacation photos to LCARS dashboard. Crew mildly entertained." + }, + { + "timestamp": "2258-03-14T10:08:30Z", + "subsystem": "Holodeck", + "severity": "WARNING", + "color": "yellow", + "message": "Holodeck 8 tried to simulate ‘All Crew as Ferengi’; program aborted after 4 seconds due to laughter overload." + }, + { + "timestamp": "2258-03-14T10:08:35Z", + "subsystem": "Cargo Bay", + "severity": "ALERT", + "color": "orange", + "message": "Conveyor belt delivered 200 rubber ducks into zero-G recreation area; clean-up team dispatched." + }, + { + "timestamp": "2258-03-14T10:08:40Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Deck 14 warp stabilizer briefly emitted glow resembling smiley face; no damage detected." + }, + { + "timestamp": "2258-03-14T10:08:45Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "Auxiliary AI began writing short stories about the ship’s life support ducts. Narrative incomplete." + }, + { + "timestamp": "2258-03-14T10:08:50Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Dr. T’Ana administered mild sedative to Crewman Mariner after spontaneous karaoke performance." + }, + { + "timestamp": "2258-03-14T10:08:55Z", + "subsystem": "Tactical", + "severity": "INFO", + "color": "teal", + "message": "Phaser bank 3 now emits gentle musical notes on idle to boost crew morale." + }, + { + "timestamp": "2258-03-14T10:09:00Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 10 oxygen mixture briefly modified to simulate Martian atmosphere; crew unaffected." + }, + { + "timestamp": "2258-03-14T10:09:05Z", + "subsystem": "Astrometrics", + "severity": "INFO", + "color": "teal", + "message": "Sensor array detected star shaped like a cat; no navigational hazard." + }, + { + "timestamp": "2258-03-14T10:09:10Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator produced miniature tribble sculptures for crew gift exchange; edible but squeaky." + }, + { + "timestamp": "2258-03-14T10:09:15Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "EPS conduit M-09 randomly pulsed rainbow light; engineers advised to log as 'artistic output.'" + }, + { + "timestamp": "2258-03-14T10:09:20Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Lt. Shaxs held impromptu strength contest with gravity training hologram; hologram lost." + }, + { + "timestamp": "2258-03-14T10:09:25Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core attempted to simulate entire starship in a single memory sector. Partial crash occurred." + }, + { + "timestamp": "2258-03-14T10:09:30Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Crewman Phelps received temporary tattoo of mini-targ on left shoulder; non-toxic." + }, + { + "timestamp": "2258-03-14T10:09:35Z", + "subsystem": "Holodeck", + "severity": "WARNING", + "color": "yellow", + "message": "Holodeck 9 running 'Galactic Tea Party'; minor quantum displacement detected in replicator outputs." + }, + { + "timestamp": "2258-03-14T10:09:40Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Deck 2 surveillance feed replaced with continuous loop of Lt. Kayshon juggling phasers." + }, + { + "timestamp": "2258-03-14T10:09:45Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 7 ventilation briefly simulated ocean breeze. Crew reported mild relaxation." + }, + { + "timestamp": "2258-03-14T10:09:50Z", + "subsystem": "Cargo Bay", + "severity": "ALERT", + "color": "orange", + "message": "Zero-G crate misaligned; 3 crates of Targ plushies drifted into corridor 11." + }, + { + "timestamp": "2258-03-14T10:09:55Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Deck 11 warp stabilizer output showing unexpected rainbow spectrum; no critical damage." + }, + { + "timestamp": "2258-03-14T10:10:00Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Auxiliary AI attempted to merge all ship logs into a single poem; caused minor UI collapse." + }, + { + "timestamp": "2258-03-14T10:10:05Z", + "subsystem": "Holodeck", + "severity": "WARNING", + "color": "yellow", + "message": "Holodeck 10 ran 'Galactic Zoo'; 5 simulated Targs escaped into corridor 9." + }, + { + "timestamp": "2258-03-14T10:10:10Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Ensign Maru given non-lethal shock for attempting to teach replicator interpretive dance." + }, + { + "timestamp": "2258-03-14T10:10:15Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "EPS conduit N-17 briefly pulsed Morse code: 'I love coffee.' Crew morale confirmed uplifted." + }, + { + "timestamp": "2258-03-14T10:10:20Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 5 greenhouse ambient light cycled through rainbow spectrum for 12 seconds; photosynthesis unaffected." + }, + { + "timestamp": "2258-03-14T10:10:25Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator 2A producing miniature photon torpedoes for training; edible but slightly metallic taste." + }, + { + "timestamp": "2258-03-14T10:10:30Z", + "subsystem": "Tactical", + "severity": "INFO", + "color": "teal", + "message": "Phaser bank 4 outputting harmless holographic stars as idle animation." + }, + { + "timestamp": "2258-03-14T10:10:35Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Captain Freeman conducted spontaneous trivia contest on Deck 3; winners rewarded with mini tribbles." + }, + { + "timestamp": "2258-03-14T10:10:40Z", + "subsystem": "Astrometrics", + "severity": "NOTICE", + "color": "blue", + "message": "Sensor anomaly showed distant star blinking rhythmically; logged as 'friendly hello.'" + }, + { + "timestamp": "2258-03-14T10:10:45Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Warp coil 7B emitted sparks shaped like miniature starships. Crewman Patel photographed for morale log." + }, + { + "timestamp": "2258-03-14T10:10:50Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "LCARS interface generated random motivational quotes for each console; some contradictory." + }, + { + "timestamp": "2258-03-14T10:10:55Z", + "subsystem": "Holodeck", + "severity": "ALERT", + "color": "orange", + "message": "Holodeck 11 simulated 'Crew as Giant Cheese Wheels'; program paused after 3 seconds to prevent existential distress." + }, + { + "timestamp": "2258-03-14T10:11:00Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Crewman Boimler treated for minor paper cut from holo-legal form; minor embarrassment reported." + }, + { + "timestamp": "2258-03-14T10:11:05Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Deck 6 security cameras briefly displayed live feed of tribble horde in recreation bay. No alarm triggered." + }, + { + "timestamp": "2258-03-14T10:11:10Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Air mixture in Deck 7 briefly shifted to simulate Klingon vineyard; crew requested repeat performance." + }, + { + "timestamp": "2258-03-14T10:11:15Z", + "subsystem": "Cargo Bay", + "severity": "ALERT", + "color": "orange", + "message": "Zero-G pallet misaligned; 8 crates of plush Targs floated into corridor 12. Crewman Knox deployed net." + }, + { + "timestamp": "2258-03-14T10:11:20Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Deck 13 EPS stabilizer emitted rainbow-colored sparks; no damage detected." + }, + { + "timestamp": "2258-03-14T10:11:25Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core attempted to simulate entire ship as holographic chessboard; partial memory lock occurred." + }, + { + "timestamp": "2258-03-14T10:11:30Z", + "subsystem": "Replicators", + "severity": "NOTICE", + "color": "blue", + "message": "Replicator produced 50 mini photon torpedoes for training; edible but slightly metallic taste." + }, + { + "timestamp": "2258-03-14T10:11:35Z", + "subsystem": "Tactical", + "severity": "INFO", + "color": "teal", + "message": "Phaser bank 5 configured to emit harmless confetti bursts on idle; morale boost noted." + }, + { + "timestamp": "2258-03-14T10:11:40Z", + "subsystem": "Crew", + "severity": "INFO", + "color": "teal", + "message": "Lt. Shaxs conducted impromptu arm wrestling contest with holographic duplicate; duplicate lost." + }, + { + "timestamp": "2258-03-14T10:11:45Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 8 greenhouse briefly bathed in rainbow lighting to test plant photosynthesis under alternate spectra." + }, + { + "timestamp": "2258-03-14T10:11:50Z", + "subsystem": "Astrometrics", + "severity": "INFO", + "color": "teal", + "message": "Sensor anomaly displayed star in shape of peace sign; logged as decorative phenomenon." + }, + { + "timestamp": "2258-03-14T10:11:55Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "EPS conduit O-21 emitted sparks resembling miniature ships; crew documented for morale." + }, + { + "timestamp": "2258-03-14T10:12:00Z", + "subsystem": "Computer", + "severity": "WARNING", + "color": "yellow", + "message": "Auxiliary AI began writing short adventure stories about the ship’s ducts; story incomplete." + }, + { + "timestamp": "2258-03-14T10:12:05Z", + "subsystem": "Medical", + "severity": "NOTICE", + "color": "blue", + "message": "Crewman Phelps temporarily given minor tattoo of mini-Targ; non-toxic." + }, + { + "timestamp": "2258-03-14T10:12:10Z", + "subsystem": "Holodeck", + "severity": "WARNING", + "color": "yellow", + "message": "Holodeck 12 attempted 'Galactic Tea Party'; minor quantum displacement detected in replicator outputs." + }, + { + "timestamp": "2258-03-14T10:12:15Z", + "subsystem": "Security", + "severity": "INFO", + "color": "teal", + "message": "Deck 7 surveillance temporarily replaced with footage of Lt. Kayshon juggling phasers." + }, + { + "timestamp": "2258-03-14T10:12:20Z", + "subsystem": "Environmental", + "severity": "NOTICE", + "color": "blue", + "message": "Deck 7 air briefly simulated Martian atmosphere; crew unaffected." + }, + { + "timestamp": "2258-03-14T10:12:25Z", + "subsystem": "Cargo Bay", + "severity": "ALERT", + "color": "orange", + "message": "Zero-G crate misaligned; 10 crates of Targ plushies drifted into corridor 13." + }, + { + "timestamp": "2258-03-14T10:12:30Z", + "subsystem": "Engineering", + "severity": "ALERT", + "color": "orange", + "message": "Deck 15 warp stabilizer outputting rainbow spectrum; no critical damage." + }, + { + "timestamp": "2258-03-14T10:12:35Z", + "subsystem": "Computer", + "severity": "CRITICAL", + "color": "red", + "message": "Core attempted to rewrite it's internal sub routines; manual intervention required. Shipwide system failure imminent." + } +] \ No newline at end of file diff --git a/lcars/experiments.go b/lcars/experiments.go new file mode 100644 index 0000000..4cfee16 --- /dev/null +++ b/lcars/experiments.go @@ -0,0 +1,79 @@ +package main + +import ( + "encoding/json" + "fmt" + "strings" +) + +func readCrew() (string, error) { + + content, err := embedded.ReadFile("embed/crew.json") + if err != nil { + return "", err + } + + // Create a slice to hold the parsed names + var crewNames []string + + // Parse the JSON + err = json.Unmarshal(content, &crewNames) + if err != nil { + fmt.Println("Error parsing JSON:", err) + return "", err + } + + // Print the results + for i, text := range crewNames { + rank, name := splitRank(text) + if rank == "" { + rank = "ERROR" + } + fmt.Printf("%d: rank: %s name: %s\n", i+1, rank , name) + } + // fmt.Println(string(content)) + return "", nil + +} + +// splitRank separates the rank (all tokens except the last two) from the crewman's name (last two tokens) +func splitRank(fullName string) (rank, name string) { + tokens := strings.Fields(fullName) + if len(tokens) < 2 { + return fullName, "" // fallback if malformed + } + + nameTokens := tokens[len(tokens)-2:] // last 2 tokens as name + rankTokens := tokens[:len(tokens)-2] // everything else as rank + name = strings.Join(nameTokens, " ") + rank = strings.Join(rankTokens, " ") + + return rank, name +} + +type Message struct { + Timestamp string `json:"timestamp"` + Subsystem string `json:"subsystem"` + Severity string `json:"severity"` + Color string `json:"color"` + Message string `json:"message"` +} + +func readMessages() ([]Message, error) { + content, err := embedded.ReadFile("embed/messages.json") + if err != nil { + return nil, err + } + + var messages []Message + if err := json.Unmarshal(content, &messages); err != nil { + return nil, err + } + + // For demonstration, print the parsed messages + for _, m := range messages { + fmt.Printf("[%s] %s (%s) - %s\n", m.Timestamp, m.Subsystem, m.Severity, m.Message) + } + + return messages, nil +} diff --git a/lcars/frontend/assets/Antonio-Bold.woff b/lcars/frontend/assets/Antonio-Bold.woff new file mode 100644 index 0000000..6f24591 Binary files /dev/null and b/lcars/frontend/assets/Antonio-Bold.woff differ diff --git a/lcars/frontend/assets/Antonio-Bold.woff2 b/lcars/frontend/assets/Antonio-Bold.woff2 new file mode 100644 index 0000000..e772d58 Binary files /dev/null and b/lcars/frontend/assets/Antonio-Bold.woff2 differ diff --git a/lcars/frontend/assets/Antonio-Regular.woff b/lcars/frontend/assets/Antonio-Regular.woff new file mode 100644 index 0000000..19027a5 Binary files /dev/null and b/lcars/frontend/assets/Antonio-Regular.woff differ diff --git a/lcars/frontend/assets/Antonio-Regular.woff2 b/lcars/frontend/assets/Antonio-Regular.woff2 new file mode 100644 index 0000000..2c89826 Binary files /dev/null and b/lcars/frontend/assets/Antonio-Regular.woff2 differ diff --git a/lcars/frontend/assets/beep1.mp3 b/lcars/frontend/assets/beep1.mp3 new file mode 100644 index 0000000..9b8c564 Binary files /dev/null and b/lcars/frontend/assets/beep1.mp3 differ diff --git a/lcars/frontend/assets/beep2.mp3 b/lcars/frontend/assets/beep2.mp3 new file mode 100644 index 0000000..c7e07f6 Binary files /dev/null and b/lcars/frontend/assets/beep2.mp3 differ diff --git a/lcars/frontend/assets/beep3.mp3 b/lcars/frontend/assets/beep3.mp3 new file mode 100644 index 0000000..26c59dc Binary files /dev/null and b/lcars/frontend/assets/beep3.mp3 differ diff --git a/lcars/frontend/assets/beep4.mp3 b/lcars/frontend/assets/beep4.mp3 new file mode 100644 index 0000000..8b39d77 Binary files /dev/null and b/lcars/frontend/assets/beep4.mp3 differ diff --git a/lcars/frontend/assets/classic.css b/lcars/frontend/assets/classic.css new file mode 100644 index 0000000..5875c89 --- /dev/null +++ b/lcars/frontend/assets/classic.css @@ -0,0 +1,3011 @@ +@charset "utf-8"; + +/* + + CSS Document + LCARS Classic Theme + Version 24.2 + By Jim Robertus www.thelcars.com + Modified: 2025 Jul 27 + +*/ + +:root { + font-size: 1.375rem; + color-scheme: dark; + --lfw: 240px; + --african-violet: #c9f; + --almond: #ffaa90; + --almond-creme: #fba; + --blue: #56f; + --bluey: #89f; + --butterscotch: #f96; + --gold: #fa0; + --golden-orange: #f90; + --gray: #668; + --green: #993; + --ice: #9cf; + --lilac: #c5f; + --lima-bean: #cc6; + --magenta: #c59; + --mars: #f20; + --moonlit-violet: #96f; + --orange: #f80; + --peach: #f86; + --red: #c44; + --sky: #aaf; + --space-white: #f5f6fa; + --sunflower: #fc9; + --tomato: #f55; + --violet-creme: #dbf; + --left-frame-top-color: var(--bluey); + --left-frame-color: var(--red); /* .panel-9 inherits this color */ + --left-frame-padding: .75rem; + --corner-color-top: var(--bluey); + --corner-color-bottom: var(--red); + --panel-1-color: var(--african-violet); + --panel-4-color: var(--red); + --panel-5-color: var(--orange); + --panel-6-color: var(--butterscotch); + --panel-7-color: var(--bluey); + --panel-8-color: var(--butterscotch); + --panel-10-color: var(--orange); + --panel-top-button-color: var(--african-violet); + --bar-height: 28px; + --bar-1-6-width: 40%; + --bar-2-7-width: 4%; + --bar-3-8-width: 17%; + --bar-5-10-width: 4%; + --bar-1-color: var(--bluey); + --bar-2-color: var(--orange); + --bar-3-color: var(--african-violet); + --bar-4-color: var(--african-violet); + --bar-5-color: var(--red); + --bar-6-color: var(--red); + --bar-7-color: var(--butterscotch); + --bar-8-color: var(--red); + --bar-9-color: var(--african-violet); + --bar-10-color: var(--butterscotch); + +/* Ultra layout elements */ + + --section-2-color: var(--almond-creme); + --pill-1-color: var(--red); + --pill-2-color: var(--butterscotch); + --pill-3-color: var(--bluey); + --pill-4-color: var(--almond-creme); + --pill-5-color: var(--orange); + --pill-6-color: var(--moonlit-violet); + --pill-a1-color: var(--moonlit-violet); + --pill-a2-color: var(--moonlit-violet); + --pill-a3-color: black; + --pill-a4-color: var(--african-violet); + --pill-a5-color: var(--orange); + --pill-a6-color: var(--almond-creme); + --panel-11-color: var(--red); + --panel-12-color: var(--bluey); + --panel-13-color: var(--almond-creme); + --panel-14-color: var(--almond-creme); + --panel-15-color: var(--almond-creme); + + /* End Ultra layout elements */ + + --radius-top: 0 0 0 160px; + --radius-bottom: 160px 0 0 0; + --radius-content-top: 0 0 0 60px; + --radius-content-bottom: 60px 0 0 0; + --panel-border: .25rem solid black; + --bar-border: .25rem solid black; + --bar-cut-width: 34%; + --bar-cut-out-width: 34%; + --divider-height: .5rem; +/* + NOTE: --font-color also sets the following: + 1. horizontal line
color + 2. lcars-list default bullet color + 3. blockquote border color + 4. images with the *border* class border color +*/ + --font-color: var(--african-violet); + --sub-fonts: .875rem; + --dc-font-size: .875rem; + --dc-row-height: calc(var(--dc-font-size) + .125rem); + --banner-color: var(--orange); + --meta-data-color: var(--african-violet); + --data-cascade-color: var(--orange); + --light-color: white; + --h1-color: var(--african-violet); + --h2-color: var(--african-violet); + --h3-color: var(--african-violet); + --h4-color: var(--african-violet); + --link-color: #c16fff; + --code-color: var(--orange); + --nav-width: 240px; + --nav-1-color: var(--bluey); + --nav-2-color: var(--butterscotch); + --nav-3-color: var(--orange); + --nav-4-color: var(--red); + --button-color: var(--african-violet); + --button-color-sidebar: var(--red); + --lcars-bar-color: var(--african-violet); + --lcars-bar-start-color: var(--moonlit-violet); + --lcars-bar-end-color: var(--moonlit-violet); + --lcars-bar-text-color: var(--golden-orange); + +/* Image Frame */ + + --image-border-color: var(--almond-creme); + --primary-color: var(--orange); + --secondary-color: var(--moonlit-violet); + --accent-color: var(--almond-creme); + --title-color: var(--almond-creme); + --spacers: .65rem; + --frame-height: 40px; +} + +@media (max-width: 1500px) { + :root { + --lfw: 200px; + --radius-top: 0 0 0 130px; + --radius-bottom: 130px 0 0 0; + --divider-height: .4rem; + --nav-width: 210px; + --dc-font-size: .75rem; + --bar-height: 24px; + } +} + +@media (max-width: 1300px) { + :root { + font-size: 1.2rem; + --sub-fonts: .9rem; + --lfw: 180px; + --nav-width: 180px; + --radius-top: 0 0 0 100px; + --radius-bottom: 100px 0 0 0; + --radius-content-top: 0 0 0 40px; + --radius-content-bottom: 40px 0 0 0; + --bar-height: 20px; + } +} + +@media (max-width: 950px) { + :root { + --lfw: 150px; + } +} + +@media (max-width: 750px) { + :root { + --panel-border: .25rem solid black; + --bar-border: .25rem solid black; + --lfw: 120px; + --radius-top: 0 0 0 80px; + --radius-bottom: 80px 0 0 0; + --radius-content-top: 0 0 0 34px; + --radius-content-bottom: 34px 0 0 0; + --nav-width: 174px; + --bar-height: 16px; + --spacers: .5rem; + --frame-height: 25px; + } +} + +@media (max-width: 525px) { + :root { + --lfw: 62px; + --left-frame-padding: .5rem; + --radius-top: 0 0 0 40px; + --radius-bottom: 40px 0 0 0; + --bar-height: 10px; + --divider-height: .3rem; + } +} + +@media (max-width: 450px) { + :root { + --nav-width: 48%; + } +} + +*, *:after, *:before { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; + font: inherit; +} + +img { + display: block; + max-width: 100%; + height: auto; +} + +input, textarea, button, select { + font: inherit; +} + +@font-face { + font-family: 'Antonio'; + font-weight: 400; + src: url('Antonio-Regular.woff2') format('woff2'), + url('Antonio-Regular.woff') format('woff'); +} + +@font-face { + font-family: 'Antonio'; + font-weight: 700; + src: url('Antonio-Bold.woff2') format('woff2'), + url('Antonio-Bold.woff') format('woff') +} + +html { + scroll-behavior: smooth; +} + +body { + display: flex; + padding-top: 10px; + padding-left: 5px; + background-color: black; + font-family: 'Antonio', 'Arial Narrow', 'Avenir Next Condensed', sans-serif; + font-weight: 400; + line-height: 1.5; + color: var(--font-color); +} + +a { + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: .2rem; + color: var(--link-color); +} + +a:hover { + filter: brightness(115%); + animation: none; +} + +a:active { + filter: brightness(80%); + outline: none; +} + +button { + border: none; + outline: none; + color: black; + transition: width 1s; +} + +button:hover { + cursor: pointer; + animation: none; + filter: brightness(115%); + color: black; +} + +button:active { + filter: brightness(85%); +} + +/* Ultra Layout elements */ + +.wrap-everything { + display: flex; + width: 100%; + column-gap: 10px; +} + +.wrap-standard { + width: 100%; +} + +#column-1 { + width: 350px; + padding: 10px 10px 10px 20px; + transition: 800ms; +} + +#column-2 { + width: var(--lfw); + background-color: var(--section-2-color); + text-align: right; + font-weight: bold; + line-height: 1.2; + color: black; + transition: 800ms; + z-index: 2; +} + +#column-2 a { + color: black; + text-decoration: none; +} + +#column-3 { + flex: 1; + margin-inline: auto; +} + +.wrap { + display: flex; + margin-inline: auto; + padding-left: 5px; + padding-right: 15px; + overflow: hidden; +} + +@media (max-width: 1680px) { + #column-1 { + margin-left: -370px; + } + + #column-2 { + margin-left: -230px; + } + + .wrap-everything { + column-gap: 5px; + } +} + +@media (max-width: 1500px) { + #column-1, + #column-2 { + display: none; + } +} + +.lcars-frame { + display: flex; + min-height: 280px; + position: relative; + --frame-color: var(--african-violet); +} + +.frame-col-1 { + width: 20px; + height: 280px; + background: var(--frame-color); + border-radius: 16px 0 0 16px; + position: relative; +} + +.frame-col-1:before { + content: ''; + display: block; + width: 20px; + height: 200px; + border-top: 5px solid black; + border-bottom: 5px solid black; + background-color: var(--frame-color); + position: absolute; + top: 40px; + left: 0; +} + +.frame-col-1-cell-a { + width: 14px; + height: 65px; + background-color: var(--tomato); + border-left: 4px solid black; + border-bottom: 4px solid black; + position: absolute; + top: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-b { + width: 14px; + height: 70px; + background-color: var(--bluey); + border-left: 4px solid black; + position: absolute; + top: 110px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-c { + width: 14px; + height: 65px; + background-color: var(--orange); + border-top: 4px solid black; + border-left: 4px solid black; + position: absolute; + bottom: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-blocks:before { + content: ''; + display: block; + width: 10px; + height: 3px; + background-color: black; + position: absolute; + top: 54px; + left: 0; +} + +.frame-col-2 { + width:20px; + height: 280px; + background-color: var(--frame-color); + position: relative; +} + +.frame-col-2:before { + content: ''; + display: block; + width: 20px; + height: 240px; + background-color: black; + border-radius: 10px 0 0 10px; + position: absolute; + top: 20px; + left: 0; +} + +.frame-col-3 { + display: flex; + width: 240px; + height: 280px; + align-items: center; + justify-content: center; +} + +.frame-col-4 { + width:20px; + height: 280px; + background-color: var(--frame-color); + position: relative; +} + +.frame-col-4:before { + content: ''; + display: block; + width: 20px; + height: 240px; + background-color: black; + border-radius: 0 10px 10px 0; + position: absolute; + top: 20px; + left: 0; +} + +.display-horizontal { + rotate: 90deg; +} + +.frame-col-5 { + width:20px; + height: 280px; + background-color: var(--frame-color); + border-radius: 0 16px 16px 0; + padding-top: 40px; + position: relative; +} + +.frame-col-5:before { + content: ''; + display: block; + width: 20px; + height: 200px; + border-top: 5px solid black; + border-bottom: 5px solid black; + background-color: var(--frame-color); +} + +.frame-col-5-cell-a { + width: 14px; + height: 65px; + background-color: var(--lilac); + border-bottom: 4px solid black; + border-right: 4px solid black; + position: absolute; + top: 45px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-b { + width: 14px; + height: 70px; + background-color: var(--violet-creme); + border-right: 4px solid black; + position: absolute; + top: 110px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-c { + width: 14px; + height: 65px; + background-color: var(--moonlit-violet); + border-top: 4px solid black; + border-right: 4px solid black; + position: absolute; + bottom: 45px; + left: 0; + z-index: 2; +} + +.line { + height: 20px; + width: 12px; + background: linear-gradient(#600, var(--mars), #600); +} + +.line:nth-child(1) { + animation: animateLine6 1s 0.2s infinite; +} + +.line:nth-child(2) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(3) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(4) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(5) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(6) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(7) { + animation: animateLine2 1s 0.8s infinite; +} + +/* 8 & 9 are middle lines*/ + +.line:nth-child(8) { + animation: animateLine4 1s 0.9s infinite; +} + +.line:nth-child(9) { + animation: animateLine4 1s 1s infinite; +} + +.line:nth-child(10) { + animation: animateLine2 1s 0.8s infinite; +} + +.line:nth-child(11) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(12) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(13) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(14) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(15) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(16) { + animation: animateLine6 1s 0.2s infinite; +} + +@keyframes animateLine2 { + 0% { + height: 180px; + } + 50% { + height: 90px; + } + 100% { + height: 180px; + } +} + +@keyframes animateLine3 { + 0% { + height: 120px; + } + 50% { + height: 60px; + } + 100% { + height: 120px; + } +} + +@keyframes animateLine4 { + 0% { + height: 230px; + } + 50% { + height: 115px; + } + 100% { + height: 230px; + } +} + +@keyframes animateLine5 { + 0% { + height: 60px; + } + 50% { + height: 30px; + } + 100% { + height: 60px; + } +} + +@keyframes animateLine6 { + 0% { + height: 30px; + } + 50% { + height: 15px; + } + 100% { + height: 30px; + } +} + +.pillbox, +.pillbox-2 { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 8px; + margin: 1.25rem auto; + text-align: right; + font-size: var(--sub-fonts); +} + +.pill, +.pill-2 { + display: flex; + width: 100%; + height: 56px; + justify-content: flex-end; + align-items: flex-end; + text-decoration: none; + color: black; + font-weight: bold; + padding-right: .75rem; + padding-bottom: .35rem; +} + +.pillbox a { + display: flex; + width: 100%; + height: 56px; + justify-content: flex-end; + align-items: flex-end; + text-decoration: none; + color: black; + font-weight: bold; + padding-right: .75rem; + padding-bottom: .35rem; +} + +.pillbox-2 a { + display: flex; + width: 100%; + height: 56px; + justify-content: flex-end; + align-items: flex-end; + text-decoration: none; + color: black; + font-weight: bold; + padding-right: .75rem; + padding-bottom: .35rem; +} + +.pill:hover, +.pill-2:hover { + filter: brightness(115%); +} + +.pill:active, +.pill-2:active { + filter: brightness(80%); +} + +.pill:nth-child(1), +.pillbox a:nth-child(1) { + border-radius: 100vmax 0 0 100vmax; + background-color: var(--pill-1-color); +} + +.pill:nth-child(2), +.pillbox a:nth-child(2) { + background-color: var(--pill-2-color); +} + +.pill:nth-child(3), +.pillbox a:nth-child(3) { + border-radius: 100vmax 0 0 100vmax; + background-color: var(--pill-3-color); +} + +.pill:nth-child(4), +.pillbox a:nth-child(4) { + background-color: var(--pill-4-color); +} + +.pill:nth-child(5), +.pillbox a:nth-child(5) { + background-color: var(--pill-5-color); + border-radius: 100vmax 0 0 100vmax; +} + +.pill:nth-child(6), +.pillbox a:nth-child(6) { + background-color: var(--pill-6-color); +} + +.pill-2:nth-child(1), +.pillbox-2 a:nth-child(1) { + border-radius: 100vmax 0 0 100vmax; + background-color: var(--pill-a1-color); +} + +.pill-2:nth-child(2), +.pillbox-2 a:nth-child(2) { + background-color: var(--pill-a2-color); + border-radius: 0 100vmax 100vmax 0; + padding-right: 1rem; +} + +.pill-2:nth-child(3), +.pillbox-2 a:nth-child(3) { + background-color: var(--pill-a3-color); +} + +.pill-2:nth-child(4), +.pillbox-2 a:nth-child(4) { + background-color: var(--pill-a4-color); + border-radius: 0 100vmax 100vmax 0; + padding-right: 1rem; +} + +.pill-2:nth-child(5), +.pillbox-2 a:nth-child(5) { + background-color: var(--pill-a5-color); + border-radius: 100vmax 0 0 100vmax; +} + +.pill-2:nth-child(6), +.pillbox-2 a:nth-child(6) { + background-color: var(--pill-a6-color); + border-radius: 0 100vmax 100vmax 0; + padding-right: 1rem; +} + +.lcars-list-2 ul { + list-style: none; +} + +.lcars-list-2 { + margin: 0 auto 50px auto; + padding-left: 5px; +} + +.lcars-list-2 li { + position: relative; + padding-bottom: 5px; + padding-left: 38px; + font-size: var(--sub-fonts); + color: var(--orange); +} + +.lcars-list-2 li::before { + content: ''; + display: block; + width: 24px; + height: 14px; + border-radius: 50%; + background-color: var(--orange); + position: absolute; + top: 8px; + left: 0; +} + +.panel-11 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 27vh; + max-height: 275px; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-11-color); + border-bottom: var(--panel-border); +} + + +.panel-12 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 34vh; + max-height: 350px; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-12-color); + border-bottom: var(--panel-border); +} + +.panel-13 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 20vh; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-13-color); + border-bottom: var(--panel-border); +} + +.panel-14 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 20vh; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-14-color); + border-bottom: var(--panel-border); +} + +.panel-15 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 20vh; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-15-color); + border-bottom: var(--panel-border); +} + +.section-2-buttons a { + display: block; + text-decoration: none; + text-align: right; + border-bottom: var(--panel-border); + padding: 1.5rem .75rem .75rem 2px; + background-color: var(--section-2-color); + text-transform: uppercase; + color: black; +} + +.section-2-buttons a:nth-child(2) { + background-color: var(--butterscotch); +} + +.section-2-buttons a:nth-child(3) { + background-color: var(--african-violet); +} + +/* End Ultra layout elements */ + +.scroll-top { + display: none; +} + +.left-frame-top, +.left-frame { + width: var(--lfw); + text-align: right; + font-size: clamp(.875rem, 2vw, 1rem); + line-height: 1.2; + font-weight: bold; + color: black; + transition: width 1s; +} + +.left-frame-top { + background-color: var(--left-frame-top-color); + border-radius: var(--radius-top); +} + +.left-frame-top a, +.left-frame a { + text-decoration: none; + color: black; +} + +.left-frame { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-top: 100px; + background-color: var(--left-frame-color); + border-radius: var(--radius-bottom); +} + +.right-frame-top { + flex: 1; + align-content: flex-end; + position: relative; +} + +.right-frame-top:before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to top right, var(--corner-color-top) 50%, black 50%); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +.right-frame-top:after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-top); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +@media (max-width: 650px) { + .right-frame-top:before { + bottom: 16px; + } + + .right-frame-top:after { + bottom: 16px; + } +} + +@media (max-width: 525px) { + .right-frame-top:before { + bottom: 10px; + } + + .right-frame-top:after { + bottom: 10px; + } +} + +.banner { + padding-bottom: 1rem; + padding-left: 5px; + text-align: right; + text-transform: uppercase; + line-height: 1.1; + font-size: clamp(1.25rem, 0.75rem + 4vw, 4rem); + color: var(--banner-color); +} + +.banner a { + color: var(--banner-color); + text-decoration: none; +} + +.data-cascade-button-group { + display: flex; + justify-content: flex-end; + align-items: flex-start; + flex-wrap: wrap; +} + +.header-content { + flex: 1; + min-height: 180px; + padding-right: .5rem; + padding-left: clamp(20px, 3vw, 50px); +} + +.header-content > *:first-child { + margin-top: 0; +} + +.header-content > *:last-child { + margin-bottom: 0; +} + +/* Data Cascade 2025 */ + +.data-cascade-wrapper { + flex: 1; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + max-width: 100%; + height: calc(var(--dc-row-height) * 9); /* 204px */ + overflow: hidden; + padding-right: .5rem; + padding-left: clamp(20px, 3vw, 50px); + column-gap: .5rem; +} + +.data-column { + display: grid; + grid-template-columns: 1fr; + margin-top: 1px; + text-align: right; + font-size: var(--dc-font-size); /* .938 */ + line-height: 1; + color: black; +} + +.dc-row-1, +.dc-row-2, +.dc-row-3, +.dc-row-4, +.dc-row-5, +.dc-row-6, +.dc-row-7 { + text-box: trim-both cap alphabetic; + height: var(--dc-row-height); +} + +@media (max-width: 780px) { + .data-cascade-wrapper { + display: none; + } +} + +@keyframes data-group-1 { + + 0%, + 3.99% { + color: black; + } + + 4%, + 45.99% { + color: var(--data-cascade-color); + } + + 46%, + 49.99% { + color: var(--light-color); + } + + 50%, + 63.99% { + color: var(--data-cascade-color); + } + + 64%, + 67.99% { + color: var(--light-color); + } + + 68%, + 100% { + color: var(--data-cascade-color); + } +} + +@keyframes data-group-1a { + + 0%, + 4.99% { + color: black; + } + + 5%, + 45.99% { + color: var(--data-cascade-color); + } + + 46%, + 49.99% { + color: var(--light-color); + } + + 50%, + 63.99% { + color: var(--data-cascade-color); + } + + 64%, + 67.99% { + color: var(--light-color); + } + + 68%, + 100% { + color: var(--data-cascade-color); + } +} + +@keyframes data-group-2 { + + 0%, + 12.99% { + color: black; + } + + 13%, + 49.99% { + color: var(--data-cascade-color); + } + + 50%, + 53.99% { + color: var(--light-color); + } + + 54%, + 67.99% { + color: var(--data-cascade-color); + } + + 68%, + 71.99% { + color: var(--light-color); + } + + 72%, + 100% { + color: var(--data-cascade-color); + } +} + +@keyframes data-group-2b { + + 0%, + 14.99% { + color: black; + } + + 15%, + 49.99% { + color: var(--data-cascade-color); + } + + 50%, + 53.99% { + color: var(--light-color); + } + + 54%, + 67.99% { + color: var(--data-cascade-color); + } + + 68%, + 71.99% { + color: var(--light-color); + } + + 72%, + 81.99% { + color: var(--data-cascade-color); + } + + 82%, + 100% { + color: var(--light-color); + } +} + +@keyframes data-group-3 { + + 0%, + 26.99% { + color: black; + } + + 27%, + 40.99% { + color: var(--light-color); + } + + 41%, + 53.99% { + color: var(--data-cascade-color); + } + + 54%, + 57.99% { + color: var(--light-color); + } + + 58%, + 71.99% { + color: var(--data-cascade-color); + } + + 72%, + 75.99% { + color: var(--light-color); + } + + 76%, + 100% { + color: var(--data-cascade-color); + } +} + +.dc-row-1 { + animation: data-group-1 6000ms ease 200ms infinite; +} + +.dc-row-2 { + animation: data-group-1a 6000ms ease 200ms infinite; +} + +.dc-row-3 { + animation: data-group-2 6000ms ease 200ms infinite; +} + +.dc-row-4 { + animation: data-group-2b 6000ms ease 200ms infinite; +} + +.dc-row-5 { + animation: data-group-3 6000ms ease 200ms infinite; +} + +.dc-row-6 { + animation: data-group-3 6000ms ease 200ms infinite; +} + +.dc-row-7 { + animation: data-group-3 6000ms ease 200ms infinite; +} + +/* Static data cascade */ + +.data-cascade-wrapper#frozen .dc-row-1 { + animation: none; + color: var(--orange); +} + +.data-cascade-wrapper#frozen .dc-row-2 { + animation: none; + color: var(--orange); +} + +.data-cascade-wrapper#frozen .dc-row-3 { + animation: none; + color: var(--orange); +} + +.data-cascade-wrapper#frozen .dc-row-4 { + animation: none; + color: var(--orange); +} + +.data-cascade-wrapper#frozen .dc-row-5 { + animation: none; + color: var(--light-color); +} + +.data-cascade-wrapper#frozen .dc-row-6 { + animation: none; + color: var(--light-color); +} + +.data-cascade-wrapper#frozen .dc-row-7 { + animation: none; + color: var(--light-color); +} + +/* Navigation & buttons */ + +.lcars-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + margin-block: 1rem; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1 a { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + height: clamp(90px, 11vw, 160px); + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + transition: width 1s; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1-button { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + min-height: clamp(90px, 11vw, 160px); + overflow: hidden; + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav { + display: flex; + flex-wrap: wrap; + align-self: center; + width: calc(var(--nav-width) + var(--nav-width) + 1rem); + justify-content: flex-end; + column-gap: .5rem; + row-gap: .65rem; +} + +@media (max-width: 1500px) { + nav { + column-gap: .375rem; + row-gap: .5rem; + } +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +nav a, +nav button, +.buttons button { + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + width: var(--nav-width); + height: calc(var(--nav-width) / 2.8); + padding-inline: 1.5rem; + padding-bottom: .7rem; + border-radius: 100vmax; + background-color: var(--button-color); + text-align: right; + line-height: 1.175; + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav a:nth-child(1), +nav button:nth-child(1) { + background-color: var(--nav-1-color); +} + +nav a:nth-child(2), +nav button:nth-child(2) { + background-color: var(--nav-2-color); +} + +nav a:nth-child(3), +nav button:nth-child(3) { + background-color: var(--nav-3-color); +} + +nav a:nth-child(4), +nav button:nth-child(4) { + background-color: var(--nav-4-color); +} + +@media (max-width: 1300px) { + nav { + padding-left: .5rem; + gap: .5rem; + } + + nav button { + padding-bottom: .5rem; + font-size: .875rem; + padding-inline: 1.25rem; + } +} + +@media (max-width: 780px) { + nav { + flex: 1; + } + + .data-cascade-button-group:has(.header-content) > *:nth-child(2) { + flex: none; + } +} + +@media (max-width: 450px) { + nav a, + nav button { + height: 63px; + } +} + +.buttons { + display: flex; + flex-wrap: wrap; + gap: .5rem; + margin-block: 2rem; +} + +.justify-space-between { + justify-content: space-between; +} + +.justify-center { + justify-content: center; +} + +.justify-flex-end { + justify-content: flex-end; +} + +.justify-space-around { + justify-content: space-around; +} + +.justify-space-evenly { + justify-content: space-evenly; +} + +.buttons a, +.buttons button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.sidebar-nav button, +.sidebar-nav a, +.sidebar-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + min-height: 3.75rem; + width: var(--lfw); + background-color: var(--button-color-sidebar); + border-radius: 0; + border-bottom: var(--panel-border); + padding: var(--left-frame-padding); + text-decoration: none; + text-align: right; + word-break: break-all; + text-transform: uppercase; + color: black; +} + +@media (max-width: 1300px) { + .lcars-button, + .buttons a, + .buttons button { + width: 200px; + height: 74px; + } +} + +.panel-button { + display: flex; + justify-content: flex-end; + width: var(--lfw); + border-radius: 0; + padding: var(--left-frame-padding); + border-bottom: var(--panel-border); +} + +.pan-0 /* use this if you're not mimicking an established panel */ { + height: 18vh; + max-height: 240px; + background-color: var(--button-color-sidebar); +} + +.pan-4 { + height: 22vh; + max-height: 300px; + background-color: var(--panel-4-color) !important; +} + +.pan-5 { + height: 4.25rem; + background-color: var(--panel-5-color) !important; + align-items: center; +} + +.pan-6 { + height: 29vh; + max-height: 360px; + background-color: var(--panel-6-color) !important; +} + +.pan-7 { + height: 27vh; + max-height: 350px; + background-color: var(--panel-7-color) !important; +} + +.pan-8 { + height: 15vh; + background-color: var(--panel-8-color) !important; +} + +.pan-10 { + height: 30vh; + background-color: var(--panel-10-color) !important; +} + +.text-bottom { + align-items: flex-end; +} + +#topBtn { + display: none; + position: fixed; + bottom: 0; + z-index: 99; + border-radius: 0; + border-top: var(--panel-border); + border-right: none; + border-bottom: var(--panel-border); + border-left: none; + outline: none; + width: var(--lfw); + padding: var(--left-frame-padding); + padding-bottom: 10vh; + background-color: var(--panel-top-button-color); + text-align: right; + line-height: 1; + font-weight: bold; + text-transform: uppercase; + color: black; + cursor: pointer; +} + +#topBtn:hover { + filter: brightness(115%); +} + +#topBtn:active { + filter: brightness(80%); +} + +@media (max-width: 525px) { + .sidebar-button, + .sidebar-nav a, + .sidebar-nav button, + .panel-button { + font-size: .75rem; + } + + #topBtn { + padding-bottom: 6vh; + } +} + +/* --- Horizontal bar panels & sidebar panels --- */ + +.bar-panel { + display: flex; + height: var(--bar-height); +} + +.first-bar-panel { + margin-top: clamp(15px, 2vw, 30px); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-9, +.bar-10 { + height: var(--bar-height); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-6, +.bar-7, +.bar-8, +.bar-9 { + border-right: var(--bar-border); +} + +.bar-1 { + width: var(--bar-1-6-width); + background-color: var(--bar-1-color); +} + +.bar-2 { + width: var(--bar-2-7-width); + background-color: var(--bar-2-color); +} + +.bar-3 { + width: var(--bar-3-8-width); + background-color: var(--bar-3-color); +} + +.bar-4 { + flex: 1; + background-color: var(--bar-4-color); +} + +.bar-5 { + width: var(--bar-5-10-width); + background-color: var(--bar-5-color); +} + +.bar-6 { + width: var(--bar-1-6-width); + background-color: var(--bar-6-color); +} + +.bar-7 { + width: var(--bar-2-7-width); + background-color: var(--bar-7-color); +} + +.bar-8 { + width: var(--bar-3-8-width); + height: 50%; + background-color: var(--bar-8-color); +} + +.bar-9 { + flex: 1; + background-color: var(--bar-9-color); +} + +.bar-10 { + width: var(--bar-5-10-width); + background-color: var(--bar-10-color); +} + +#gap { + margin-top: var(--divider-height); +} + +.panel-3, +.panel-4, +.panel-5, +.panel-6, +.panel-7, +.panel-8 { + border-bottom: var(--panel-border); +} + +.panel-2, +.panel-3, +.panel-4, +.panel-6, +.panel-7, +.panel-8, +.panel-10 { + padding: var(--left-frame-padding); +} + +.panel-4 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 22vh; + max-height: 300px; + background-color: var(--panel-4-color); +} + +.panel-5 { + display: flex; + justify-content: flex-end; + align-items: center; + height: 4.25rem; + padding: var(--left-frame-padding); + background-color: var(--panel-5-color); +} + +.panel-6 { + height: 29vh; + max-height: 360px; + background-color: var(--panel-6-color); +} + +.panel-7 { + height: 27vh; + max-height: 350px; + background-color: var(--panel-7-color); +} + +.panel-8 { + height: 15vh; + background-color: var(--panel-8-color); +} + +/* Note: panel-9 height is fluid and governed by the amount of content on the page. Background color is inherited from :root --left-frame-color */ + +.panel-9 { + min-height: 27vh; + padding: var(--left-frame-padding); +} + +.panel-10 { + height: 30vh; + border-top: var(--panel-border); + background-color: var(--panel-10-color); +} + +@media (max-width: 525px) { + .panel-4, + .panel-6, + .panel-7 { + height: 18vh; + } +} + +.right-frame { + flex: 1; + position: relative; +} + +.right-frame::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to bottom right, var(--corner-color-bottom) 50%, black 50%); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +.right-frame::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-bottom); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +main { + padding-top: 1.5rem; + padding-bottom: .5rem; + padding-left: clamp(20px, 3vw, 50px); +} + +main > *:first-child, +article > *:first-child { + margin-top: 0; +} + +main:has(.floor-heading) > *:nth-child(2) { + margin-top: 0; +} + +@media (max-width: 1400px) { + main { + padding-top: 1rem; + } +} + +.flexbox { + display: flex; + gap: 2vw; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3, h4 { + margin-block: 1.75rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; + text-box: trim-both cap alphabetic; +} + +h1 { + font-size: clamp(1.5rem, 1.25rem + 3.5vw, 4rem); + text-align: right; + color: var(--h1-color); +} + +h2 { + font-size: clamp(1.4rem, 1.1rem + 2.25vw, 2.3rem); + color: var(--h2-color); +} + +h3 { + font-size: clamp(1.15rem, 1.05rem + 1.25vw, 1.875rem); + color: var(--h3-color); +} + +h4 { + font-size: clamp(1.025rem, 1rem + 1.125vw, 1.575rem); + color: var(--h4-color); +} + +.floor-heading { + display: flex; + justify-content: flex-end; + width: 100%; + position: fixed; + left: 50%; + transform: translate(-50%, 0); + bottom: 10px; + z-index:4; +} + +.floor-heading > * { + margin-block: 0; + width: fit-content; + padding-inline: .5rem; + padding-bottom: .5rem; + background-color: black; +} + +p { + margin-block: 1.75rem; + text-box: trim-both cap alphabetic; +} + +.caption { + margin-top: -1rem; + margin-bottom: 2.75rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.pics-right .caption, +.pics-left .caption { + margin-top: 1rem; +} + +.indent { + padding-left: 1.5rem; +} + +.postmeta { + margin-block: 1.25rem; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +hr { + margin-block: 1.5rem; + height: 6px; + border: none; + background-color: var(--font-color); + border-radius: 3px; +} + +blockquote { + margin-block: 1.75rem; + margin-left: 1.5rem; + padding-block: .25rem; + padding-left: 1.5rem; + position: relative; + text-box: trim-both cap alphabetic; +} + +blockquote::before { + content: ''; + display: block; + width: 10px; + height: 100%; + background-color: var(--font-color); + border-radius: 5px; + position: absolute; + left: 0; + top: 0; +} + +blockquote > *:first-child { + margin-top: 0; +} + +blockquote > * { + margin-bottom: 0; +} + +iframe { + display: block; + width: 100%; + border: none; +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin-block: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-big { + font-size: clamp(1.2rem, 1rem + 1vw, 1.275rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 5rem; +} + +.smoke-glass { + opacity: .35; +} + +strong { + font-weight: bold; +} + +code { + font-family: monospace; + font-size: .9rem; + color: var(--code-color); +} + +.code { + width: 100%; + min-height: 5rem; + padding-block: .5rem; + padding-inline: 1rem; + background-color: black; + border-color: var(--code-color); + tab-size: 4; + font-family: monospace; + font-size: .85rem; + color: var(--code-color); +} + +::selection { + background-color: var(--orange); + color: black; +} + +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +.blink-slow { + animation: blink 3500ms infinite; +} + +.blink { + animation: blink 2s infinite; +} + +.blink-fast { + animation: blink 1s infinite; +} + +@keyframes pulse { + 0% {filter: brightness(1.0)} + 50% {filter: brightness(.25)} +} + +.pulse { + animation: pulse 2s infinite; +} + +.pulse-rate-high { + animation: pulse 1s infinite; +} + +.pulse-rate-low { + animation: pulse 3s infinite; +} + +/* Accordion Dropdown */ + +.accordion-wrapper { + display: block; + margin: 1.75rem auto; + width: 100%; +} + +.limit-width { + max-width: 1240px; +} + +.accordion { + display: flex; + align-items: center; + min-height: 3rem; + width: 100%; + padding-right: 2.75rem; + padding-left: 1rem; + border-radius: 100vmax; + background-color: var(--african-violet); + border-left: solid 3rem var(--moonlit-violet); + text-align: left; + font-size: 1.25rem; + color: black; + cursor: pointer; + transition: 0.4s ease; + position: relative; +} + +.active, .accordion:hover { + background-color: var(--violet-creme); + border-left-color: var(--orange); + filter: none; +} + +.accordion:before { + content: ''; + display: block; + width: .5rem; + height: 4rem; + background-color: black; + position: absolute; + top: 0; + left: 0; +} + +.accordion:after { + display: block; + content: '\276F'; + position: absolute; + right: 1.5rem; + top: 21%; + transform: rotate(90deg); + transition: 0.4s; + font-weight: bold; + color: black; +} + +.active:after { + content: "\276F"; + transform:rotate(-90deg); + transition: 0.4s ease; +} + +.accordionContent { + padding-block: .5rem; + padding-inline: 3.5rem; + max-height: 0; + overflow: hidden; + transition: max-height 0.25s ease-out; +} + +.accordionContent ul { + margin-left: 0; +} + +@media (max-width: 525px) { + .accordion { + min-height: 2.5rem; + font-size: 1rem; + border-left-width: 2.5rem; + } +} + +/* Images */ + +.pics-right { + float: right; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; + clear: both; +} + +.pics-left { + float: left; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +@media (max-width: 1060px) { + .pics-right, + .pics-left { + float: none; + margin-inline: auto; + } + + .pics-right img, + .pics-left img { + margin-inline: auto; + } +} + +.pics { + margin-block: 2rem; + margin-inline: auto; +} + +.border { + border: 2px solid var(--font-color); +} + +/* + +Gallery + +NOTE: Gallery is experimental and still under development. + +*/ + +.gallery { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: .75rem; + list-style: none; + text-align: center; + font-size: .875rem; +} + +.gallery img { + align-self: flex-start; + border: 4px solid black; +} + +.gallery li div { + padding-block: .6rem; + text-box: trim-both cap alphabetic; +} + +.thumbs img { + width: 340px; +} + +.gallery a { + align-self: flex-start; +} + +.gallery a img:hover { + border-color: var(--font-color); +} + +.lcars-list { + margin-block: 1.15rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-block: .45rem; + padding-left: 2.25rem; + text-box: trim-both cap alphabetic; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 34px; + height: 18px; + border-radius: 50%; + background-color: var(--font-color); + position: absolute; + top: .45rem; + left: 0; +} + +@media (max-width: 650px) { + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + transform: scale(90%); + } +} + +.lcars-bar { + margin-block: 1.75rem; + height: clamp(15px, 2vh, 25px); + background: transparent; + border-right: clamp(15px, 2vh, 25px) solid var(--lcars-bar-end-color); + border-left: clamp(15px, 2vh, 25px) solid var(--lcars-bar-start-color); + border-radius: 100vmax; + position: relative; +} + +.lcars-bar::after { + content: ''; + display: block; + height: clamp(15px, 2vh, 25px); + width: 100%; + background-color: var(--lcars-bar-color); + border-right: .8vh solid black; + border-left: .8vh solid black; + position: absolute; + top: 0; + left: 0; +} + +.lcars-text-bar { + display: flex; + position: relative; + height: clamp(16px, 4vh, 41px); + margin-block: 2.75rem; + overflow: visible; + border-radius: 100vmax; + background-color: var(--lcars-bar-color); + border-right: clamp(16px, 4vh, 43px) solid var(--lcars-bar-end-color); + border-left: clamp(16px, 4vh, 43px) solid var(--lcars-bar-start-color); +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar h2, +.lcars-text-bar h3, +.lcars-text-bar h4, +.lcars-text-bar span { + margin-block: 0; + background-color: black; + height: clamp(20px, 5.5vh, 60px); /* Setting height is a Firefox fix */ + overflow: visible; + border-top: 1px solid black; + padding-inline: 1vh; + font-size: clamp(17px, 4.5vh, 46px); + line-height: 1; + text-transform: uppercase; + color: var(--lcars-bar-text-color); + z-index: 1; + text-box: trim-both cap alphabetic; +} + +.lcars-text-bar::before { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.lcars-text-bar::after { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + right: 0; + overflow: hidden; +} + +/* Image Frame */ + +.image-frame { + display: block; + margin: 2.75rem auto; + width: fit-content; + background: linear-gradient(var(--primary-color) 56%, var(--secondary-color) 44%); + border-radius: 50px 25px 0 50px; + position: relative; +} + +.image-frame::before { + content: ''; + display: block; + width: 40px; + height: 40px; + background-color: black; + position: absolute; + right: 0; + top: 0; +} + +.image-frame::after { + content: ''; + display: block; + border-top: var(--spacers) solid black; + border-bottom: var(--spacers) solid black; + width: 45px; + height: 80px; + background-color: var(--secondary-color); + position: absolute; + left: 0; + top: 56%; +} + +.imgf-title { + display: flex; + justify-content: flex-end; + height: 40px; + border-right: 40px solid var(--secondary-color); + border-radius: 25px 100vh 100vh 0; + position: relative; + z-index: 1; + text-align: right; +} + +.h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + border-right: var(--spacers) solid black; +} + +.imgf-title h4 { + margin-block: 0; + width: fit-content; + background-color: black; + padding-left: var(--spacers); + font-size: 2.05rem; + color: var(--title-color); + line-height: 40px; + text-transform: uppercase; +} + +.imgf-image-body { + margin-left: 45px; + background-color: black; + width: fit-content; + padding: 1rem; + border-radius: 28px 0 0 28px; + +} + +.image-holder { + width: fit-content; + padding: 1rem; + border: 2px solid var(--image-border-color); + border-radius: 20px; +} + +.imgf-base { + display: grid; + grid-template-columns: 20% 13% 35px 15% 1fr; + margin-left: 80px; + border-left: var(--spacers) solid black; + +} + +.imgf-block-1 { + height: var(--frame-height); + background-color: var(--accent-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-2 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-3 { + height: var(--frame-height); + background-color: black; + border-right: 10px solid var(--secondary-color); + border-left: 10px solid var(--accent-color); +} + +.imgf-block-4 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-left: var(--spacers) solid black; +} + +.imgf-block-5 { + height: var(--frame-height); + background-color: black; +} + +@media (max-width: 750px) { + .image-frame { + border-radius: 40px 25px 0 40px; + } + + .image-frame::after { + width: 25px; + height: 60px; + top: 50%; + } + + .imgf-title { + height: 25px; + border-right: 24px solid var(--secondary-color); + } + + .h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + } + + .imgf-title h4 { + font-size: 1.45rem; + } + + .imgf-image-body { + margin-left: 25px; + padding: .75rem; + border-radius: 20px 0 0 20px; + } + + .image-holder { + padding: .75rem; + border-radius: 10px; + } +} + +/* color custom classes */ + +.font-african-violet { + color: var(--african-violet) !important; +} + +.button-african-violet, +.background-african-violet, +.bullet-african-violet { + background-color: var(--african-violet) !important; +} + +.font-almond { + color: var(--almond) !important; +} + +.button-almond, +.background-almond, +.bullet-almond::before { + background-color: var(--almond) !important; +} + +.font-almond-creme { + color: var(--almond-creme) !important; +} + +.button-almond-creme, +.background-almond-creme, +.bullet-almond-creme::before { + background-color: var(--almond-creme) !important; +} + +.font-blue { + color: var(--blue) !important; +} + +.button-blue, +.background-blue, +.bullet-blue::before { + background-color: var(--blue) !important; +} + +.font-bluey { + color: var(--bluey) !important; +} + +.button-bluey, +.background-bluey, +.bullet-bluey::before { + background-color: var(--bluey) !important; +} + +.font-butterscotch { + color: var(--butterscotch) !important; +} + +.button-butterscotch, +.background-butterscotch, +.bullet-butterscotch::before { + background-color: var(--butterscotch) !important; +} + +.font-gold { + color: var(--gold) !important; +} + +.button-gold, +.background-gold, +.bullet-gold::before { + background-color: var(--gold) !important; +} + +.font-golden-orange { + color: var(--golden-orange) !important; +} + +.button-golden-orange, +.background-golden-orange, +.bullet-golden-orange::before { + background-color: var(--golden-orange) !important; +} + +.font-gray { + color: var(--gray) !important; +} + +.button-gray, +.background-gray, +.bullet-gray::before { + background-color: var(--gray) !important; +} + +.font-green { + color: var(--green) !important; +} + +.button-green, +.background-green, +.bullet-green::before { + background-color: var(--green) !important; +} + +.font-ice { + color: var(--ice) !important; +} + +.button-ice, +.background-ice, +.bullet-ice::before { + background-color: var(--ice) !important; +} + +.font-lilac { + color: var(--lilac) !important; +} + +.button-lilac, +.background-lilac, +.bullet-lilac::before { + background-color: var(--lilac) !important; +} + +.font-lima-bean { + color: var(--lima-bean) !important; +} + +.button-lima-bean, +.background-lima-bean, +.bullet-lima-bean::before { + background-color: var(--lima-bean) !important; +} + +.font-magenta { + color: var(--magenta) !important; +} + +.button-magenta, +.background-magenta, +.bullet-magenta::before { + background-color: var(--magenta) !important; +} + +.font-mars { + color: var(--mars) !important; +} + +.button-mars, +.background-mars, +.bullet-mars::before { + background-color: var(--mars) !important; +} + +.font-moonlit-violet { + color: var(--moonlit-violet) !important; +} + +.button-moonlit-violet, +.background-moonlit-violet, +.bullet-moonlit-violet::before { + background-color: var(--moonlit-violet) !important; +} + +.font-orange { + color: var(--orange) !important; +} + +.button-orange, +.background-orange, +.bullet-orange::before { + background-color: var(--orange) !important; +} + +.font-peach { + color: var(--peach) !important; +} + +.button-peach, +.background-peach, +.bullet-peach::before { + background-color: var(--peach) !important; +} + +.font-red { + color: var(--red) !important; +} + +.button-red, +.background-red, +.bullet-red::before { + background-color: var(--red) !important; +} + +.font-sky { + color: var(--sky) !important; +} + +.button-sky, +.background-sky, +.bullet-sky::before { + background-color: var(--sky) !important; +} + +.font-space-white { + color: var(--space-white) !important; +} + +.button-space-white, +.background-space-white, +.bullet-space-white::before { + background-color: var(--space-white) !important; +} + +.font-sunflower { + color: var(--sunflower) !important; +} + +.button-sunflower, +.background-sunflower, +.bullet-sunflower::before { + background-color: var(--sunflower) !important; +} + +.font-tomato { + color: var(--tomato) !important; +} + +.button-tomato, +.background-tomato, +.bullet-tomato::before { + background-color: var(--tomato) !important; +} + +.font-violet-creme { + color: var(--violet-creme) !important; +} + +.button-violet-creme, +.background-violet-creme, +.bullet-violet-creme::before { + background-color: var(--violet-creme) !important; +} + +/* Footer */ + +footer { + margin-top: 2.5vw; + padding-bottom: 3rem; + padding-left: clamp(20px, 3vw, 50px); + font-size: .825rem; + --footer-bar-height: 1rem; +} + +footer:has(.footer-frame) { + font-size: inherit; +} + +.footer-frame { + display: grid; + grid-template-columns: 1fr var(--lfw); + align-items: center; + background: linear-gradient(var(--red) 50%, var(--bluey) 50%); + border-radius: 0 2rem 2rem 0; + padding-block: var(--footer-bar-height); + position: relative; +} + +.footer-frame::before { + content: ''; + display: block; + width: 20%; + height: calc(var(--footer-bar-height) / 2); + /*border-radius: 100vmax 0 0 100vmax;*/ + position: absolute; + left: 0; + top: calc(var(--footer-bar-height) + .5rem); + background-color: var(--red); + z-index: 1; +} + +.footer-frame::after { + content: ''; + display: block; + width: 20%; + height: calc(var(--footer-bar-height) / 2); + /*border-radius: 100vmax 0 0 100vmax;*/ + position: absolute; + left: 0; + bottom: var(--footer-bar-height); + background-color: var(--bluey); +} + +.footer-frame-content { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: black; + min-height: 250px; + border-radius: 0 1.5rem 1.5rem 0; + padding-block: 2.5rem; + padding-inline: 2rem; + position: relative; + text-align: center; +} + +.footer-frame-content::before { + content: ''; + display: block; + width: .25rem; + height: var(--footer-bar-height); + background-color: black; + position: absolute; + top: calc(var(--footer-bar-height) - var(--footer-bar-height) * 2); + left: 62%; +} + +.footer-frame-content::after { + content: ''; + display: block; + width: .25rem; + height: var(--footer-bar-height); + background-color: black; + position: absolute; + bottom: calc(var(--footer-bar-height) - var(--footer-bar-height) * 2); + left: 62%; +} + +.footer-frame-content p { + margin-block: .8rem; +} + +@media (max-width: 880px) { + .footer-frame-content .buttons { + justify-content: center; + } +} + +@media (max-width: 600px) { + footer { + --footer-bar-height: .75rem; + } + + .footer-frame-content { + padding-inline: .5rem; + } +} + +.footer-frame-content *:first-child { + margin-top: 0; +} + +.footer-frame-content *:last-child { + margin-bottom: 0; +} + +.footer-frame-panel { + height: 50%; + min-height: 100px; + background-color: var(--butterscotch); + border-block: var(--bar-border); + padding: var(--left-frame-padding); + font-size: clamp(.875rem, 2vw, 1rem); + font-weight: bold; + color: black; +} + +.headtrim { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + top: 0; + left: 0; + z-index: 999; +} + +.baseboard { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + bottom: 0; + left: 0; + z-index: 999; +} + +/* Grouped @media */ + +@media (max-width: 525px) { + body { + padding: .25rem; + } + + .baseboard, + .headtrim { + display: none; + } + + .wrap { + padding-left: 0; + padding-right: .25rem; + } + + .left-frame { + padding-top: 25px; + } + + .floor-heading { + bottom: 0; + } + + .hop { + display: none; + } + + blockquote { + margin-left: .75rem; + } +} + +@-moz-document url-prefix() { + + main { + padding-top: clamp(1rem, 4vw, 30px); + } + + h1, h2, h3, h4, p { + margin-block: 1.15rem; + } + + .imgf-title h4 { + margin-top: -4px; + margin-bottom: 0; + } + + .postmeta { + margin-top: .75rem; + } + + .lcars-text-bar h2, + .lcars-text-bar h3, + .lcars-text-bar h4, + .lcars-text-bar span { + position: absolute; + top: -.7vh; + } + + .lcars-list li::before { + top: .85rem; + } + + .meta-data { + height: 1.3rem; + line-height: 1rem; + } +} \ No newline at end of file diff --git a/lcars/frontend/assets/lcars.js b/lcars/frontend/assets/lcars.js new file mode 100644 index 0000000..3c067eb --- /dev/null +++ b/lcars/frontend/assets/lcars.js @@ -0,0 +1,50 @@ +document.addEventListener("touchstart", function() {},false); +let mybutton = document.getElementById("topBtn"); +window.onscroll = function() {scrollFunction()}; +function scrollFunction() { + if (document.body.scrollTop > 200 || document.documentElement.scrollTop > 200) { + mybutton.style.display = "block"; + } else { + mybutton.style.display = "none"; + } +} +function topFunction() { + document.body.scrollTop = 0; + document.documentElement.scrollTop = 0; +} +function playSoundAndRedirect(audioId, url) { + var audio = document.getElementById(audioId); + audio.play(); + + audio.onended = function() { + window.location.href = url; + }; +} +function goToAnchor(anchorId) { + window.location.hash = anchorId; +} +// Accordion drop-down +var acc = document.getElementsByClassName("accordion"); +var i; + +for (i = 0; i < acc.length; i++) { + acc[i].addEventListener("click", function() { + this.classList.toggle("active"); + var accordionContent = this.nextElementSibling; + if (accordionContent.style.maxHeight){ + accordionContent.style.maxHeight = null; + } else { + accordionContent.style.maxHeight = accordionContent.scrollHeight + "px"; + } + }); +} +// LCARS keystroke sound (not to be used with hyperlinks) + const LCARSkeystroke = document.getElementById('LCARSkeystroke'); + const allPlaySoundButtons = document.querySelectorAll('.playSoundButton'); + allPlaySoundButtons.forEach(button => { + button.addEventListener('click', function() { + LCARSkeystroke.pause(); + LCARSkeystroke.currentTime = 0; // Reset to the beginning of the sound + LCARSkeystroke.play(); + }); + }); \ No newline at end of file diff --git a/lcars/frontend/assets/lower-decks-padd.css b/lcars/frontend/assets/lower-decks-padd.css new file mode 100644 index 0000000..d914632 --- /dev/null +++ b/lcars/frontend/assets/lower-decks-padd.css @@ -0,0 +1,1881 @@ +@charset "utf-8"; + +/* + + CSS Document + LCARS Lower Decks PADD Theme + Version 24.2 + By Jim Robertus www.thelcars.com + Modified: 2025 Aug 4 + +*/ + +:root { + font-size: 1.375rem; + color-scheme: dark; + --lfw: 240px; + --alpha-blue: #58e; + --arctic-ice: #6cf; + --arctic-snow: #9cf; + --radioactive: #8ff; + --beta-blue: #79d; + --night-cloud: #344470; + --night-rain: #455580; + --sunset-red: #f30; + --left-frame-top-color: var(--alpha-blue); + --left-frame-color: var(--alpha-blue); /* panel-6 inherits this color */ + --left-frame-padding: .75rem; + --corner-color-top: var(--alpha-blue); + --corner-color-bottom: var(--alpha-blue); + --panel-1-color: var(--night-rain); + --panel-4-color: var(--beta-blue); + --panel-5-color: var(--night-rain); + --panel-7-color: var(--night-cloud); + --panel-top-button-color: var(--beta-blue); + --bar-height: 28px; + --bar-1-6-width: 10%; + --bar-2-7-width: 28%; + --bar-3-8-width: 7%; + --bar-5-10-width: 5%; + --bar-1-color: var(--alpha-blue); + --bar-2-color: var(--radioactive); + --bar-3-color: var(--beta-blue); + --bar-4-color: var(--alpha-blue); + --bar-5-color: var(--arctic-ice); + --bar-6-color: var(--alpha-blue); + --bar-7-color: var(--radioactive); + --bar-8-color: var(--beta-blue); + --bar-9-color: var(--alpha-blue); + --bar-10-color: var(--arctic-ice); +/* + NOTE: --font-color also sets the following: + 1. horizontal line
color + 2. lcars-list bullet color + 3. blockquote border color + 4. images with the *border* class + 5. data-cascade text color +*/ + --font-color: var(--beta-blue); + --sub-fonts: .875rem; + --banner-color: var(--radioactive); + --h1-color: var(--arctic-ice); + --h2-color: var(--arctic-ice); + --h3-color: var(--arctic-ice); + --h4-color: var(--arctic-ice); + --light-color: #bdf; + --link-color: var(--beta-blue); + --code-color: var(--alpha-blue); + --nav-width: 240px; + --nav-1-color: var(--alpha-blue); + --nav-2-color: var(--beta-blue); + --nav-3-color: var(--arctic-ice); + --nav-4-color: var(--night-rain); + --button-color: var(--alpha-blue); + --button-color-sidebar: var(--alpha-blue); + --radius-top: 0 0 0 100px; + --radius-bottom: 100px 0 0 0; + --radius-content-top: 0 0 0 44px; + --radius-content-bottom: 44px 0 0 0; + --panel-border: .4rem solid #000; + --bar-border: .4rem solid #000; + --bar-cut-width: 27%; + --divider-height: .75rem; + --lcars-bar-color: var(--night-rain); + --lcars-bar-start-color: var(--beta-blue); + --lcars-bar-end-color: var(--beta-blue); + --lcars-bar-text-color: var(--beta-blue); + +/* Image Frame: */ + + --image-border-color: var(--beta-blue); + --primary-color: var(--night-rain); + --secondary-color: var(--beta-blue); + --accent-color: var(--arctic-snow); + --spacers: .65rem; + --frame-height: 40px; +} + +@media (max-width: 1500px) { + :root { + --lfw: 200px; + --nav-width: 210px; + --bar-height: 20px; + --divider-height: .5rem; + } +} + +@media (max-width: 1300px) { + :root { + font-size: 1.2rem; + --sub-fonts: .9rem; + --lfw: 180px; + --radius-top: 0 0 0 80px; + --radius-bottom: 80px 0 0 0; + --radius-content-top: 0 0 0 30px; + --radius-content-bottom: 30px 0 0 0; + --nav-width: 180px; + } +} + +@media (max-width: 950px) { + :root { + --lfw: 150px; + } +} + +@media (max-width: 750px) { + :root { + --lfw: 120px; + --radius-top: 0 0 0 60px; + --radius-bottom: 60px 0 0 0; + --radius-content-top: 0 0 0 24px; + --radius-content-bottom: 24px 0 0 0; + --bar-height: 16px; + --spacers: .5rem; + --frame-height: 25px; + } +} + +@media (max-width: 525px) { + :root { + --lfw: 62px; + --left-frame-padding: .5rem; + --radius-top: 0 0 0 30px; + --radius-bottom: 30px 0 0 0; + --bar-height: 10px; + --panel-border: .25rem solid black; + --bar-border: .25rem solid black; + --divider-height: .345rem; + } +} + +@media (max-width: 450px) { + :root { + --nav-width: 48%; + } +} + +*, *:after, *:before { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; + font: inherit; +} + +img { + display: block; + max-width: 100%; + height: auto; +} + +input, textarea, button, select { + font: inherit; +} + +@font-face { + font-family: 'Antonio'; + font-weight: 400; + src: url('Antonio-Regular.woff2') format('woff2'), + url('Antonio-Regular.woff') format('woff'); +} + +@font-face { + font-family: 'Antonio'; + font-weight: 700; + src: url('Antonio-Bold.woff2') format('woff2'), + url('Antonio-Bold.woff') format('woff') +} + +html { + scroll-behavior: smooth; +} + +body { + display: flex; + padding-top: 10px; + padding-left: 5px; + background-color: black; + font-family: 'Antonio', 'Arial Narrow', 'Avenir Next Condensed', sans-serif; + font-weight: 400; + line-height: 1.5; + color: var(--font-color); +} + +a { + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: .2rem; + color: var(--link-color); +} + +a:hover { + filter: brightness(115%); + animation: none; +} + +a:active { + filter: brightness(80%); + outline: none; +} + +button { + border: none; + outline: none; + word-break: break-all; + color: black; + transition: width 1s; +} + +button:hover { + cursor: pointer; + animation: none; + filter: brightness(115%); + color: black; +} + +button:active { + filter: brightness(85%); +} + +@keyframes colorchange { + 0% {color: var(--night-cloud)} + 25% {color: var(--night-cloud);} + 50% {color: var(--arctic-snow);} + 75% {color: var(--arctic-snow);} + 80% {color: var(--arctic-snow);} + 90% {color: var(--night-cloud);} + 100% {color: var(--night-cloud);} +} + +.wrap-all { + width: 100%; +} + +.wrap { + display: flex; + width: 100%; + padding-left: 5px; + padding-right: 15px; + overflow: hidden; +} + +.scroll-top { + display: none; +} + +.left-frame-top, +.left-frame { + width: var(--lfw); + text-align: right; + font-size: clamp(.875rem, 2vw, 1rem); + line-height: 1.2; + font-weight: bold; + color: black; + transition: width 1s; +} + +.left-frame-top { + background-color: var(--left-frame-top-color); + border-radius: var(--radius-top); +} + +.left-frame-top a, +.left-frame a { + text-decoration: none; + color: black; +} + +.left-frame { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-top: 14vh; + background-color: var(--left-frame-color); + border-radius: var(--radius-bottom); +} + +.left-frame:has(.sidebar-nav) { + padding-top: 10vh; +} + +.panel-2 { + padding-top: .75rem; + padding-right: .75rem; +} + +.right-frame-top { + flex: 1; + position: relative; +} + +.right-frame-top::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to top right, var(--corner-color-top) 50%, #000 50%); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +.right-frame-top::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-top); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +@media (max-width: 500px) { + .right-frame-top::before { + bottom: 10px; + } + + .right-frame-top::after { + bottom: 10px; + } +} + +.banner { + padding-bottom: 1rem; + padding-left: 5px; + text-align: right; + text-transform: uppercase; + line-height: 1.1; + font-size: clamp(1.5rem, 1.25rem + 3.5vw, 4rem); + color: var(--banner-color); +} + +.banner a { + color: var(--banner-color); + text-decoration: none; +} + +.data-cascade-button-group { + display: flex; + justify-content: flex-end; + align-items: flex-start; + flex-wrap: wrap; + padding-bottom: .75rem; +} + +.data-cascade-button-group:has(.header-content) { + justify-content: flex-start; +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +.header-content { + flex: 1; + min-height: 184px; + padding-right: 2rem; + padding-left: clamp(20px, 3vw, 50px); +} + +.header-content > *:first-child { + margin-top: 0; +} + +.header-content > *:last-child { + margin-bottom: 0; +} + +/* Data Stream */ + +.data-wrapper { + flex: 1; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + align-items: flex-end; + max-width: 100%; + height: 164px; + overflow: hidden; + padding-top: 10px; + padding-right: 2rem; + padding-left: clamp(20px, 3vw, 50px); + column-gap: 1rem; + font-size: 1.25rem; +} + +.data-column { + display: grid; + grid-template-columns: 1fr; + line-height: 1; + --dc-row-height: 40px; +} + +.data-bullet { + width: 38px; + height: 22px; + border-radius: 50%; + background-color: var(--font-color); +} + +.dc-row-1, +.dc-row-2, +.dc-row-3, +.dc-row-4 { + display: flex; + align-items: center; + min-height: var(--dc-row-height); +} + +.dc-row-1:has(.data-bullet) { + padding-inline: 1rem; +} + +.dc-row-2:has(.data-bullet) { + padding-inline: 1rem; +} + +.dc-row-3:has(.data-bullet) { + padding-inline: 1rem; +} + +.dc-row-4:has(.data-bullet) { + padding-inline: 1rem; +} + +.darkspace { + min-width: 3rem; + text-align: center; + justify-content: center; +} + +.darkfont { + color: black; +} + +@media (max-width: 1300px) { + .data-wrapper { + height: 130px; + font-size: 1rem; + } + + .data-column { + --dc-row-height: 30px; + } + + .data-bullet { + transform: scale(.8); + } +} + +@media (max-width: 1100px) { + .hide-data { + display: none; + } + + .data-wrapper { + column-gap: .575rem; + padding-right: 1rem; + } +} + +@media (max-width: 740px) { + .data-wrapper { + display: none; + } +} + +/* Navigation & buttons */ + +.lcars-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + margin-block: 1rem; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1 a { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + height: clamp(90px, 11vw, 160px); + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + transition: width 1s; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1-button { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + min-height: clamp(90px, 11vw, 160px); + overflow: hidden; + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav { + display: flex; + flex-wrap: wrap; + align-self: center; + width: calc(var(--nav-width) + var(--nav-width) + 1rem); + justify-content: flex-end; + column-gap: .5rem; + row-gap: .65rem; +} + +@media (max-width: 1500px) { + nav { + column-gap: .375rem; + row-gap: .5rem; + } +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +nav a, +nav button, +.buttons button { + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + width: var(--nav-width); + height: calc(var(--nav-width) / 2.8); + padding-inline: 1.5rem; + padding-bottom: .7rem; + border-radius: 100vmax; + background-color: var(--button-color); + text-align: right; + line-height: 1.175; + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav a:nth-child(1), +nav button:nth-child(1) { + background-color: var(--nav-1-color); +} + +nav a:nth-child(2), +nav button:nth-child(2) { + background-color: var(--nav-2-color); +} + +nav a:nth-child(3), +nav button:nth-child(3) { + background-color: var(--nav-3-color); +} + +nav a:nth-child(4), +nav button:nth-child(4) { + background-color: var(--nav-4-color); +} + +@media (max-width: 1300px) { + nav { + padding-left: .5rem; + gap: .5rem; + } + + nav button { + padding-bottom: .5rem; + font-size: .875rem; + padding-inline: 1.25rem; + } +} + +@media (max-width: 780px) { + nav { + flex: 1; + } + + .data-cascade-button-group:has(.header-content) > *:nth-child(2) { + flex: none; + } +} + +@media (max-width: 450px) { + nav a, + nav button { + height: 63px; + } +} + +.buttons { + display: flex; + flex-wrap: wrap; + gap: .5rem; + margin-block: 2rem; +} + +.justify-space-between { + justify-content: space-between; +} + +.justify-center { + justify-content: center; +} + +.justify-flex-end { + justify-content: flex-end; +} + +.justify-space-around { + justify-content: space-around; +} + +.justify-space-evenly { + justify-content: space-evenly; +} + +.buttons a, +.buttons button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.sidebar-nav button, +.sidebar-nav a, +.sidebar-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + min-height: 3.75rem; + width: var(--lfw); + background-color: var(--button-color-sidebar); + border-radius: 0; + border-bottom: var(--panel-border); + padding: var(--left-frame-padding); + text-decoration: none; + text-align: right; + word-break: break-all; + text-transform: uppercase; + color: black; +} + +@media (max-width: 1300px) { + .lcars-button, + .buttons a, + .buttons button { + width: 200px; + height: 74px; + } +} + +.panel-button { + display: flex; + justify-content: flex-end; + width: var(--lfw); + border-radius: 0; + padding: var(--left-frame-padding); + border-bottom: var(--panel-border); +} + +.pan-0 /* use this if you're not mimicking an established panel */ { + height: 18vh; + max-height: 240px; + background-color: var(--button-color-sidebar); +} + +.pan-4 { + height: 14vh; + background-color: var(--panel-4-color) !important; +} + +.pan-5 { + height: 30vh; + background-color: var(--panel-5-color) !important; +} + +.pan-7 { + height: 30vh; + background-color: var(--panel-7-color) !important; +} + +.text-bottom { + align-items: flex-end; +} + +#topBtn { + display: none; + position: fixed; + bottom: 0; + z-index: 99; + border-radius: 0; + border-top: var(--panel-border); + border-right: none; + border-bottom: var(--panel-border); + border-left: none; + outline: none; + width: var(--lfw); + padding: var(--left-frame-padding); + padding-bottom: 10vh; + background-color: var(--panel-top-button-color); + text-align: right; + line-height: 1; + font-weight: bold; + text-transform: uppercase; + color: black; + cursor: pointer; +} + +#topBtn:hover { + filter: brightness(115%); +} + +#topBtn:active { + filter: brightness(80%); +} + +@media (max-width: 525px) { + .sidebar-button, + .sidebar-nav a, + .sidebar-nav button, + .panel-button { + font-size: .75rem; + } + + #topBtn { + padding-bottom: 6vh; + } +} + +.bar-panel { + display: flex; + height: var(--bar-height); +} + +.first-bar-panel { + margin-top: 2.5vh; + position: relative; +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-8, +.bar-9, +.bar-10 { + height: var(--bar-height); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-6, +.bar-7, +.bar-8, +.bar-9 { + border-right: var(--bar-border); +} + +.divider { + display: flex; + height: var(--divider-height); + z-index: 1999; +} + +.block-left { + width: var(--lfw); + height: var(--divider-height); +} + +.block-right { + flex: 1; + height: var(--divider-height); + position: relative; +} + +.block-row { + display: flex; + width: 100%; + height: var(--divider-height); + padding-right: .4rem; + padding-left: 1px; +} + +.bar-11 { + height: var(--divider-height); + width: var(--bar-1-6-width); +} + +.bar-12 { + height: var(--divider-height); + width: var(--bar-2-7-width); + +} + +.bar-13 { + height: var(--divider-height); + width: var(--bar-3-8-width); +} +.bar-14 { + flex: 1; + height: var(--divider-height); + z-index: 1999; +} + +.bar-1 { + width: var(--bar-1-6-width); + background-color: var(--bar-1-color); +} + +.bar-2 { + width: var(--bar-2-7-width); + background-color: var(--bar-2-color); +} + +.bar-3 { + width: var(--bar-3-8-width); + background-color: var(--bar-3-color); +} + +.bar-4 { + flex: 1; + position: relative; + background-color: var(--bar-4-color); +} + +.bar-5 { + width: var(--bar-5-10-width); + background-color: var(--bar-5-color); +} + +.bar-6 { + width: var(--bar-1-6-width); + background-color: var(--bar-6-color); +} + +.bar-7 { + width: var(--bar-2-7-width); + background-color: var(--bar-7-color); +} + +.bar-8 { + width: var(--bar-3-8-width); + background-color: var(--bar-8-color); +} + +.bar-9 { + flex: 1; + position: relative; + background-color: var(--bar-9-color); +} + +.bar-4::after { + content: ""; + display: block; + width: var(--bar-cut-width); + height: 48%; + background-color: black; + border-radius: 0 8px 0 0; + position: absolute; + left: 0; + bottom: 0; +} + +.bar-9::after { + content: ""; + display: block; + width: var(--bar-cut-width); + height: 48%; + background-color: black; + border-radius: 0 0 8px 0; + position: absolute; + left: 0; + top: 0; +} + +.bar-10 { + width: var(--bar-5-10-width); + background-color: var(--bar-10-color); +} + +/* Bottom half */ + +#gap { + margin-top: var(--divider-height); +} + +.panel-3, +.panel-4, +.panel-5 { + border-bottom: var(--panel-border); +} + +.panel-2, +.panel-3, +.panel-4, +.panel-5, +.panel-6, +.panel-7 { + padding: var(--left-frame-padding); +} + +.panel-4 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + min-height: 14vh; + background-color: var(--panel-4-color); +} + +.panel-5 { + height: 30vh; + background-color: var(--panel-5-color); +} + +/* Note: panel-6 height is fluid and governed by the amount of content on the page. Background color is inherited from :root --left-frame-color */ + +.panel-6 { + min-height: 15vh; +} + +.panel-7 { + height: 30vh; + border-top: var(--panel-border); + background-color: var(--panel-7-color); +} + +.right-frame { + flex: 1; + position: relative; +} + +.right-frame::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to bottom right, var(--corner-color-bottom) 50%, #000 50%); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +.right-frame::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-bottom); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +main { + padding-top: 1.5rem; + padding-bottom: .5rem; + padding-left: clamp(20px, 3vw, 50px); +} + +main > *:first-child, +article > *:first-child { + margin-top: 0; +} + +main:has(.floor-heading) > *:nth-child(2) { + margin-top: 0; +} + +.flexbox { + display: flex; + gap: 1.2rem; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3, h4 { + margin-block: 1.75rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; + text-box: trim-both cap alphabetic; +} + +h1 { + font-size: clamp(1.5rem, 1.25rem + 3.5vw, 4rem); + text-align: right; + color: var(--h1-color); +} + +h2 { + font-size: clamp(1.4rem, 1.1rem + 2.25vw, 2.3rem); + color: var(--h2-color); +} + +h3 { + font-size: clamp(1.15rem, 1.05rem + 1.25vw, 1.875rem); + color: var(--h3-color); +} + +h4 { + font-size: clamp(1.025rem, 1rem + 1.125vw, 1.575rem); + color: var(--h4-color); +} + +.floor-heading { + display: flex; + justify-content: flex-end; + width: 100%; + position: fixed; + left: 50%; + transform: translate(-50%, 0); + bottom: 10px; + z-index:4; +} + +.floor-heading > * { + margin-block: 0; + width: fit-content; + padding: .5rem; + background-color: black; +} + +p { + margin-block: 1.75rem; + text-box: trim-both cap alphabetic; +} + +.caption { + margin-top: -1rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.indent { + padding-left: 1.5rem; +} + +.postmeta { + margin-block: 1.25rem; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +hr { + margin-block: 1.5rem; + height: 6px; + border: none; + background-color: var(--font-color); + border-radius: 3px; +} + +blockquote { + margin-block: 1.75rem; + margin-left: 1.5rem; + padding-block: .25rem; + padding-left: 1.5rem; + position: relative; + text-box: trim-both cap alphabetic; +} + +blockquote::before { + content: ''; + display: block; + width: 10px; + height: 100%; + background-color: var(--font-color); + border-radius: 5px; + position: absolute; + left: 0; + top: 0; +} + +blockquote > *:first-child { + margin-top: 0; +} + +blockquote > * { + margin-bottom: 0; +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin-block: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-big { + font-size: clamp(1.2rem, 1rem + 1vw, 1.275rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 5rem; +} + +.smoke-glass { + opacity: .35; +} + +strong { + font-weight: bold; +} + +code { + font-family: monospace; + font-size: .9rem; + color: var(--code-color); +} + +.code { + width: 100%; + min-height: 5rem; + padding-block: .5rem; + padding-inline: 1rem; + background-color: #232323; + border-color: #4c4c4c; + tab-size: 4; + font-family: monospace; + font-size: .85rem; + color: #dcdcdc; +} + +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +.blink-slow { + animation: blink 3500ms infinite; + animation-delay: 1s; +} + +.blink { + animation: blink 2s infinite; + animation-delay: 1s; +} + +.blink-fast { + animation: blink 1s infinite; + animation-delay: 1s; +} + +@keyframes pulse { + 0% {filter: brightness(1.0)} + 50% {filter: brightness(.25)} +} + +.pulse { + animation: pulse 2300ms infinite; +} + +.pulse-rate-high { + animation: pulse 1s infinite; +} + +.accordion-wrapper { + display: block; + margin: 1.75rem auto; + width: 100%; +} + +.limit-width { + max-width: 1240px; +} + +.accordion { + display: flex; + align-items: center; + min-height: 3rem; + width: 100%; + padding-right: 2.75rem; + padding-left: 1rem; + border-radius: 100vmax; + background-color: var(--alpha-blue); + border-left: solid 3rem var(--night-rain); + text-align: left; + font-size: 1.25rem; + color: black; + cursor: pointer; + transition: 0.4s ease; + position: relative; +} + +.active, .accordion:hover { + background-color: var(--beta-blue); + border-left-color: var(--radioactive); + filter: none; +} + +.accordion:before { + content: ''; + display: block; + width: .5rem; + height: 4rem; + background-color: black; + position: absolute; + top: 0; + left: 0; +} + +.accordion:after { + display: block; + content: '\276F'; + position: absolute; + right: 1.5rem; + top: 21%; + transform: rotate(90deg); + transition: 0.4s; + font-weight: bold; + color: black; +} + +.active:after { + content: "\276F"; + transform:rotate(-90deg); + transition: 0.4s ease; +} + +.accordionContent { + padding-block: .5rem; + padding-inline: 3.5rem; + max-height: 0; + overflow: hidden; + transition: max-height 0.25s ease-out; +} + +.accordionContent ul { + margin-left: 0; +} + +@media (max-width: 525px) { + .accordion { + min-height: 2.5rem; + font-size: 1rem; + border-left-width: 2.5rem; + } +} + +/* Images */ + +.pics-right { + float: right; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +.pics-left { + float: left; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +@media (max-width: 1060px) { + .pics-right, + .pics-left { + float: none; + margin-inline: auto; + } + + .pics-right img, + .pics-left img { + margin-inline: auto; + } +} + +.pics { + margin-block: 2rem; + margin-inline: auto; +} + +.border { + border: 2px solid var(--font-color); +} + +.lcars-list { + margin-block: 1.15rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-block: .45rem; + padding-left: 2.25rem; + text-box: trim-both cap alphabetic; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 34px; + height: 18px; + border-radius: 50%; + background-color: var(--font-color); + position: absolute; + top: .45rem; + left: 0; +} + +@media (max-width: 650px) { + + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + transform: scale(90%); + } +} + +.lcars-bar { + margin-block: 1.75rem; + height: clamp(15px, 2vh, 25px); + background: transparent; + border-right: clamp(15px, 2vh, 25px) solid var(--lcars-bar-end-color); + border-left: clamp(15px, 2vh, 25px) solid var(--lcars-bar-start-color); + border-radius: 100vmax; + position: relative; +} + +.lcars-bar::after { + content: ''; + display: block; + height: clamp(15px, 2vh, 25px); + width: 100%; + background-color: var(--lcars-bar-color); + border-right: .8vh solid black; + border-left: .8vh solid black; + position: absolute; + top: 0; + left: 0; +} + +.lcars-text-bar { + display: flex; + position: relative; + height: clamp(16px, 4vh, 41px); + margin-block: 2.75rem; + overflow: visible; + border-radius: 100vmax; + background-color: var(--lcars-bar-color); + border-right: clamp(16px, 4vh, 43px) solid var(--lcars-bar-end-color); + border-left: clamp(16px, 4vh, 43px) solid var(--lcars-bar-start-color); +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar h2, +.lcars-text-bar h3, +.lcars-text-bar h4, +.lcars-text-bar span { + margin-block: 0; + background-color: black; + height: clamp(20px, 5.5vh, 60px); /* Setting height is a Firefox fix */ + overflow: visible; + border-top: 1px solid black; + padding-inline: 1vh; + font-size: clamp(17px, 4.5vh, 46px); + line-height: 1; + text-transform: uppercase; + color: var(--lcars-bar-text-color); + z-index: 1; + text-box: trim-both cap alphabetic; +} + +.lcars-text-bar::before { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.lcars-text-bar::after { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + right: 0; + overflow: hidden; +} + +/* LCARS Image Frame */ + +.image-frame { + margin: 2.75rem auto; + width: fit-content; + background: linear-gradient(var(--primary-color) 56%, var(--secondary-color) 44%); + border-radius: 50px 25px 0 50px; + position: relative; +} + +.image-frame::before { + content: ''; + display: block; + width: 40px; + height: 40px; + background-color: black; + position: absolute; + right: 0; + top: 0; +} + +.image-frame::after { + content: ''; + display: block; + border-top: var(--spacers) solid black; + border-bottom: var(--spacers) solid black; + width: 45px; + height: 80px; + background-color: var(--secondary-color); + position: absolute; + left: 0; + top: 56%; +} + +.imgf-title { + display: flex; + justify-content: flex-end; + height: 40px; + border-right: 40px solid var(--secondary-color); + border-radius: 25px 100vh 100vh 0; + position: relative; + z-index: 1; + text-align: right; +} + +.h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + border-right: var(--spacers) solid black; +} + +.imgf-title h4 { + margin-block: 0; + width: fit-content; + background-color: black; + padding-left: var(--spacers); + font-size: 2.05rem; + color: var(--title-color); + line-height: 40px; + text-transform: uppercase; +} + +.imgf-image-body { + margin-left: 45px; + background-color: black; + width: fit-content; + padding: 1rem; + border-radius: 28px 0 0 28px; +} + +.image-holder { + width: fit-content; + padding: 1rem; + border: 2px solid var(--image-border-color); + border-radius: 20px; +} + +.imgf-base { + display: grid; + grid-template-columns: 20% 13% 35px 15% 1fr; + margin-left: 80px; + border-left: var(--spacers) solid black; +} + +.imgf-block-1 { + height: var(--frame-height); + background-color: var(--accent-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-2 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-3 { + height: var(--frame-height); + background-color: black; + border-right: 10px solid var(--secondary-color); + border-left: 10px solid var(--accent-color); +} + +.imgf-block-4 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-left: var(--spacers) solid black; +} + +.imgf-block-5 { + height: var(--frame-height); + background-color: black; +} + +@media (max-width: 750px) { + + .image-frame { + border-radius: 40px 25px 0 40px; + } + + .image-frame::after { + width: 25px; + height: 60px; + top: 50%; + } + + .imgf-title { + height: 25px; + border-right: 24px solid var(--secondary-color); + } + + .h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + } + + .imgf-title h4 { + font-size: 1.45rem; + } + + .imgf-image-body { + margin-left: 25px; + padding: .75rem; + border-radius: 20px 0 0 20px; + } + + .image-holder { + padding: .75rem; + border-radius: 10px; + } +} + +/* Color Styles */ + +.font-alpha-blue { + color: var(--alpha-blue) !important; +} + +.button-alpha-blue, +.background-alpha-blue, +.bullet-alpha-blue::before { + background-color: var(--alpha-blue) !important; +} + +.font-arctic-ice { + color: var(--arctic-ice) !important; +} + +.button-arctic-ice, +.background-arctic-ice, +.bullet-arctic-ice::before { + background-color: var(--arctic-ice) !important; +} + +.font-arctic-snow { + color: var(--arctic-snow) !important; +} + +.button-arctic-snow, +.background-snow, +.bullet-arctic-snow::before { + background-color: var(--arctic-snow) !important; +} + +.font-radioactive { + color: var(--radioactive) !important; +} + +.button-radioactive, +.background-radioactive, +.bullet-radioactive::before { + background-color: var(--radioactive) !important; +} + +.font-beta-blue { + color: var(--beta-blue) !important; +} + +.button-beta-blue, +.background-beta-blue, +.bullet-beta-blue::before { + background-color: var(--beta-blue) !important; +} + +.font-night-cloud { + color: var(--night-cloud) !important; +} + +.button-night-cloud, +.background-night-cloud, +.bullet-night-cloud::before { + background-color: var(--night-cloud) !important; +} + +.font-night-rain { + color: var(--night-rain) !important; +} + +.button-night-rain, +.background-night-rain, +.bullet-night-rain::before { + background-color: var(--night-rain) !important; +} + +.font-sunset-red { + color: var(--sunset-red) !important; +} + +.button-sunset-red, +.background-sunset-red, +.bullet-sunset-red::before { + background-color: var(--sunset-red) !important; +} + +/* Footer */ + +footer { + margin-top: 2.5vw; + padding-bottom: 3rem; + padding-left: clamp(20px, 3vw, 50px); + font-size: .875rem; +} + +.headtrim { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + top: 0; + left: 0; + z-index: 999; +} + +.baseboard { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + bottom: 0; + left: 0; + z-index: 999; +} + +/* Grouped @media */ + +@media (max-width: 650px) { + + .first-bar-panel { + margin-top: .75rem; + } + + .bar-4::before { + height: 5px; + top: -12px; + } + + .bar-9::before { + height: 5px; + bottom: -12px; + } +} + +@media (max-width: 525px) { + + body { + padding: .25rem; + } + + .baseboard { + display: none; + } + + .wrap { + padding-left: 0; + padding-right: .25rem; + } + + .left-frame { + padding-top: 8vh; + } + + .divider { + padding-right: 10px; + } + + .block-row { + padding-right: 0; + padding-left: .25rem; + } + + .floor-heading { + bottom: 0; + } + + .hop { + display: none; + } + + blockquote { + margin-left: .75rem; + } +} + +@-moz-document url-prefix() { + + main { + padding-top: clamp(1rem, 4vw, 30px); + } + + h1, h2, h3, h4, p { + margin-block: 1.15rem; + } + + .postmeta { + margin-top: .75rem; + } + + .lcars-text-bar h2, + .lcars-text-bar h3, + .lcars-text-bar h4, + .lcars-text-bar span { + position: absolute; + top: -.7vh; + } +} \ No newline at end of file diff --git a/lcars/frontend/assets/lower-decks.css b/lcars/frontend/assets/lower-decks.css new file mode 100644 index 0000000..32c9827 --- /dev/null +++ b/lcars/frontend/assets/lower-decks.css @@ -0,0 +1,1856 @@ +@charset "utf-8"; + +/* + + CSS Document + LCARS Lower Decks Theme + Version 24.2 + By Jim Robertus www.thelcars.com + Modified: 2025 Jul 27 + +*/ + +:root { + font-size: 1.375rem; + color-scheme: dark; + --lfw: 240px; + --butter: #fec; + --daybreak: #f91; + --harvestgold: #fa4; + --honey: #fc9; + --october-sunset: #f40; + --orange: #f70; + --rich-pumpkin: #c50; + --left-frame-top-color: var(--october-sunset); + --left-frame-color: var(--october-sunset); /* panel-6 inherits this color */ + --left-frame-padding: .75rem; + --corner-color-top: var(--october-sunset); + --corner-color-bottom: var(--october-sunset); + --panel-1-color: var(--orange); + --panel-4-color: var(--orange); + --panel-5-color: var(--harvestgold); + --panel-7-color: var(--harvestgold); + --panel-top-button-color: var(--honey); + --bar-height: 28px; + --bar-1-6-width: 10%; + --bar-2-7-width: 12%; + --bar-3-8-width: 17%; + --bar-5-10-width: 5%; + --bar-1-color: var(--october-sunset); + --bar-2-color: var(--orange); + --bar-3-color: var(--honey); + --bar-4-color: var(--harvestgold); + --bar-5-color: var(--october-sunset); + --bar-6-color: var(--october-sunset); + --bar-7-color: var(--orange); + --bar-8-color: var(--honey); + --bar-9-color: var(--harvestgold); + --bar-10-color: var(--october-sunset); +/* + NOTE: --font-color also sets the following: + 1. horizontal line
color + 2. lcars-list bullet color + 3. blockquote border color + 4. images with the *border* class border color +*/ + --font-color: var(--daybreak); + --sub-fonts: .875rem; + --banner-color: var(--honey); + --data-cascade-color: var(--orange); + --light-color: white; + --h1-color: var(--honey); + --h2-color: var(--honey); + --h3-color: var(--honey); + --h4-color: var(--honey); + --light-color: var(--butter); + --link-color: var(--october-sunset); + --code-color: var(--october-sunset); + --nav-width: 240px; + --nav-1-color: var(--honey); + --nav-2-color: var(--harvestgold); + --nav-3-color: var(--orange); + --nav-4-color: var(--october-sunset); + --button-color: var(--harvestgold); + --button-color-sidebar: var(--october-sunset); + --radius-top: 0 0 0 100px; + --radius-bottom: 100px 0 0 0; + --radius-content-top: 0 0 0 44px; + --radius-content-bottom: 44px 0 0 0; + --panel-border: .4rem solid black; + --bar-border: .4rem solid black; + --bar-cut-width: 32%; + --bar-cut-out-width: 40%; + --bar-cut-out-top-color: var(--october-sunset); + --bar-cut-out-bottom-color: var(--october-sunset); + --divider-height: .75rem; + --lcars-bar-color: var(--october-sunset); + --lcars-bar-start-color: var(--harvestgold); + --lcars-bar-end-color: var(--harvestgold); + --lcars-bar-text-color: var(--harvestgold); + +/* Image Frame */ + + --image-border-color: var(--honey); + --primary-color: var(--orange); + --secondary-color: var(--harvestgold); + --accent-color: var(--honey); + --spacers: .65rem; + --frame-height: 40px; +} + +@media (max-width: 1500px) { + :root { + --lfw: 200px; + --nav-width: 210px; + --bar-height: 20px; + --divider-height: .5rem; + } +} + +@media (max-width: 1300px) { + :root { + font-size: 1.2rem; + --sub-fonts: .9rem; + --lfw: 180px; + --radius-top: 0 0 0 80px; + --radius-bottom: 80px 0 0 0; + --radius-content-top: 0 0 0 30px; + --radius-content-bottom: 30px 0 0 0; + --nav-width: 180px; + } +} + +@media (max-width: 950px) { + :root { + --lfw: 150px; + } +} + +@media (max-width: 750px) { + :root { + --lfw: 120px; + --radius-top: 0 0 0 60px; + --radius-bottom: 60px 0 0 0; + --radius-content-top: 0 0 0 24px; + --radius-content-bottom: 24px 0 0 0; + --bar-height: 16px; + --spacers: .5rem; + --frame-height: 25px; + } +} + +@media (max-width: 525px) { + :root { + --lfw: 62px; + --left-frame-padding: .5rem; + --radius-top: 0 0 0 30px; + --radius-bottom: 30px 0 0 0; + --bar-height: 10px; + --panel-border: .25rem solid black; + --bar-border: .25rem solid black; + --divider-height: .345rem; + } +} + +@media (max-width: 450px) { + :root { + --nav-width: 48%; + } +} + +*, *:after, *:before { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; + font: inherit; +} + +img { + display: block; + max-width: 100%; + height: auto; +} + +input, textarea, button, select { + font: inherit; +} + +@font-face { + font-family: 'Antonio'; + font-weight: 400; + src: url('Antonio-Regular.woff2') format('woff2'), + url('Antonio-Regular.woff') format('woff'); +} + +@font-face { + font-family: 'Antonio'; + font-weight: 700; + src: url('Antonio-Bold.woff2') format('woff2'), + url('Antonio-Bold.woff') format('woff') +} + +html { + scroll-behavior: smooth; +} + +body { + display: flex; + padding-top: 10px; + padding-left: 5px; + background-color: black; + font-family: 'Antonio', 'Arial Narrow', 'Avenir Next Condensed', sans-serif; + font-weight: 400; + line-height: 1.5; + color: var(--font-color); +} + +a { + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: .2rem; + color: var(--link-color); +} + +a:hover { + filter: brightness(115%); + animation: none; +} + +a:active { + filter: brightness(80%); + outline: none; +} + +button { + border: none; + outline: none; + color: black; + transition: width 1s; +} + +button:hover { + cursor: pointer; + animation: none; + filter: brightness(115%); + color: black; +} + +button:active { + filter: brightness(85%); +} + +.wrap-all { + width: 100%; +} + +.wrap { + display: flex; + margin-inline: auto; + padding-left: 5px; + padding-right: 15px; + overflow: hidden; +} + +.divider { + display: flex; + width: 100%; + flex-wrap: nowrap; + height: var(--divider-height); +} + +.scroll-top { + display: none; +} + +.left-frame-top, +.left-frame { + width: var(--lfw); + text-align: right; + font-size: clamp(.875rem, 2vw, 1rem); + line-height: 1.2; + font-weight: bold; + color: black; + transition: width 1s; +} + +.left-frame-top { + background-color: var(--left-frame-top-color); + border-radius: var(--radius-top); +} + +.left-frame-top a, +.left-frame a { + text-decoration: none; + color: black; +} + +.left-frame { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-top: 19vh; + background-color: var(--left-frame-color); + border-radius: var(--radius-bottom); +} + +.left-frame:has(.sidebar-nav) { + padding-top: 10vh; +} + +.left-frame:has(button) { + padding-top: 10vh; +} + +@keyframes panel-1-color-change { + 0%, + 49.99% { + background-color: var(--orange); + } + 50%, + 100% { + background-color: var(--butter); + } +} + +.right-frame-top { + flex: 1; + align-content: flex-end; + position: relative; +} + +.right-frame-top::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to top right, var(--corner-color-top) 50%, black 50%); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +.right-frame-top::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-top); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +.banner { + padding-bottom: 1rem; + padding-left: 5px; + text-align: right; + text-transform: uppercase; + line-height: 1.1; + font-size: clamp(1.25rem, 0.75rem + 4vw, 3.75rem); + color: var(--banner-color); +} + +.banner a { + color: var(--banner-color); + text-decoration: none; +} + +.data-cascade-button-group { + display: flex; + justify-content: flex-end; + align-items: flex-start; + flex-wrap: wrap; + padding-bottom: .75rem; +} + +.data-cascade-button-group:has(.header-content) { + justify-content: flex-start; +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +.header-content { + flex: 1; + min-height: 184px; + padding-right: 2rem; + padding-left: clamp(20px, 3vw, 50px); +} + +.header-content > *:first-child { + margin-top: 0; +} + +.header-content > *:last-child { + margin-bottom: 0; +} + +/* Data Stream */ + +.data-wrapper { + flex: 1; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + align-items: flex-end; + max-width: 100%; + height: 184px; + overflow: hidden; + padding-top: 10px; + padding-right: 2rem; + padding-left: clamp(20px, 3vw, 50px); + column-gap: .5rem; + font-size: 1.25rem; +} + +.data-column { + display: grid; + grid-template-columns: 1fr; + text-align: right; + line-height: 1; + --dc-row-height: 45px; +} + +@media (max-width: 1300px) { + .data-wrapper { + height: 150px; + font-size: 1rem; + } + + .data-column { + --dc-row-height: 35px; + } + +} + +@media (max-width: 740px) { + .data-wrapper { + display: none; + } +} + +.dc-row-1 { + min-height: var(--dc-row-height); + color: var(--october-sunset); +} + +.dc-row-2 { + min-height: var(--dc-row-height); + color: var(--honey); +} + +.dc-row-3 { + min-height: var(--dc-row-height); + color: var(--october-sunset); +} + +.dc-row-4 { + min-height: var(--dc-row-height); + color: var(--harvestgold); +} + +.darkspace { + min-width: 4rem; + text-align: center; + color: var(--october-sunset); +} + +.darkfont { + color: black; +} + +@media (max-width: 1100px) { + .hide-data { + display: none; + } + + .data-wrapper { + padding-right: 1rem; + } +} + +/* Navigation & buttons */ + +.lcars-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + margin-block: 1rem; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1 a { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + height: clamp(90px, 11vw, 160px); + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + transition: width 1s; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1-button { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + min-height: clamp(90px, 11vw, 160px); + overflow: hidden; + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav { + display: flex; + flex-wrap: wrap; + align-self: center; + width: calc(var(--nav-width) + var(--nav-width) + 1rem); + justify-content: flex-end; + column-gap: .5rem; + row-gap: .65rem; +} + +@media (max-width: 1500px) { + nav { + column-gap: .375rem; + row-gap: .5rem; + } +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +nav a, +nav button, +.buttons button { + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + width: var(--nav-width); + height: calc(var(--nav-width) / 2.8); + padding-inline: 1.5rem; + padding-bottom: .7rem; + border-radius: 100vmax; + background-color: var(--button-color); + text-align: right; + line-height: 1.175; + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav a:nth-child(1), +nav button:nth-child(1) { + background-color: var(--nav-1-color); +} + +nav a:nth-child(2), +nav button:nth-child(2) { + background-color: var(--nav-2-color); +} + +nav a:nth-child(3), +nav button:nth-child(3) { + background-color: var(--nav-3-color); +} + +nav a:nth-child(4), +nav button:nth-child(4) { + background-color: var(--nav-4-color); +} + +@media (max-width: 1300px) { + nav { + padding-left: .5rem; + gap: .5rem; + } + + nav button { + padding-bottom: .5rem; + font-size: .875rem; + padding-inline: 1.25rem; + } +} + +@media (max-width: 780px) { + nav { + flex: 1; + } + + .data-cascade-button-group:has(.header-content) > *:nth-child(2) { + flex: none; + } +} + +@media (max-width: 450px) { + nav a, + nav button { + height: 63px; + } +} + +.buttons { + display: flex; + flex-wrap: wrap; + gap: .5rem; + margin-block: 2rem; +} + +.justify-space-between { + justify-content: space-between; +} + +.justify-center { + justify-content: center; +} + +.justify-flex-end { + justify-content: flex-end; +} + +.justify-space-around { + justify-content: space-around; +} + +.justify-space-evenly { + justify-content: space-evenly; +} + +.buttons a, +.buttons button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.sidebar-nav button, +.sidebar-nav a, +.sidebar-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + min-height: 3.75rem; + width: var(--lfw); + background-color: var(--button-color-sidebar); + border-radius: 0; + border-bottom: var(--panel-border); + padding: var(--left-frame-padding); + text-decoration: none; + text-align: right; + word-break: break-all; + text-transform: uppercase; + color: black; +} + +@media (max-width: 1300px) { + .lcars-button, + .buttons a, + .buttons button { + width: 200px; + height: 74px; + } +} + +.panel-button { + display: flex; + justify-content: flex-end; + width: var(--lfw); + border-radius: 0; + padding: var(--left-frame-padding); + border-bottom: var(--panel-border); +} + +.pan-0 /* use this if you're not mimicking an established panel */ { + height: 18vh; + max-height: 240px; + background-color: var(--button-color-sidebar); +} + +.pan-4 { + height: 14vh; + background-color: var(--panel-4-color) !important; +} + +.pan-5 { + height: 30vh; + background-color: var(--panel-5-color) !important; +} + +.pan-7 { + height: 30vh; + background-color: var(--panel-7-color) !important; +} + +.text-bottom { + align-items: flex-end; +} + +#topBtn { + display: none; + position: fixed; + bottom: 0; + z-index: 99; + border-radius: 0; + border-top: var(--panel-border); + border-right: none; + border-bottom: var(--panel-border); + border-left: none; + outline: none; + width: var(--lfw); + padding: var(--left-frame-padding); + padding-bottom: 10vh; + background-color: var(--panel-top-button-color); + text-align: right; + line-height: 1; + font-weight: bold; + text-transform: uppercase; + color: black; + cursor: pointer; +} + +#topBtn:hover { + filter: brightness(115%); +} + +#topBtn:active { + filter: brightness(80%); +} + +@media (max-width: 525px) { + .sidebar-button, + .sidebar-nav a, + .sidebar-nav button, + .panel-button { + font-size: .75rem; + } + + #topBtn { + padding-bottom: 6vh; + } +} + +zack { + +} + +.bar-panel { + display: flex; + height: var(--bar-height); +} + +.first-bar-panel { + margin-top: 2.5vh; + position: relative; +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-9, +.bar-10 { + height: var(--bar-height); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-6, +.bar-7, +.bar-8 { + border-right: var(--bar-border); +} + +.bar-5, +.bar-10 { + border-left: var(--bar-border); +} + +.bar-1 { + width: var(--bar-1-6-width); + background-color: var(--bar-1-color); +} + +.bar-2 { + width: var(--bar-2-7-width); + background-color: var(--bar-2-color); +} + +.bar-3 { + width: var(--bar-3-8-width); + background-color: var(--bar-3-color); +} + +.bar-4 { + flex: 1; + position: relative; + background-color: var(--bar-4-color); + z-index: -1; +} + +.bar-5 { + width: var(--bar-5-10-width); + background-color: var(--bar-5-color); +} + +.bar-6 { + width: var(--bar-1-6-width); + background-color: var(--bar-6-color); +} + +.bar-7 { + width: var(--bar-2-7-width); + background-color: var(--bar-7-color); +} + +.bar-8 { + width: var(--bar-3-8-width); + background-color: var(--bar-8-color); +} + +.bar-9 { + flex: 1; + position: relative; + background-color: var(--bar-9-color); + z-index: -1; +} + +.bar-4::before { + content: ''; + display: block; + width: var(--bar-cut-out-width); + height: 8px; + background-color: var(--bar-cut-out-top-color); + position: absolute; + top: -22px; + left: 0; +} + +.bar-4::after { + content: ""; + display: block; + width: var(--bar-cut-width); + height: 48%; + background-color: black; + border-radius: 0 8px 0 0; + position: absolute; + left: 0; + bottom: 0; + z-index: -1; +} + +.bar-9::before { + content: ''; + display: block; + width: var(--bar-cut-out-width); + height: 8px; + background-color: var(--bar-cut-out-bottom-color); + position: absolute; + bottom: -22px; + left: 0; +} + +.bar-9::after { + content: ""; + display: block; + width: var(--bar-cut-width); + height: 48%; + background-color: black; + border-radius: 0 0 8px 0; + position: absolute; + left: 0; + top: 0; + z-index: -1; +} + +.bar-10 { + width: var(--bar-5-10-width); + background-color: var(--bar-10-color); +} + +/* Bottom half */ + +#gap { + margin-top: var(--divider-height); +} + +.panel-3, +.panel-4, +.panel-5 { + border-bottom: var(--panel-border); +} + +.panel-2, +.panel-3, +.panel-4, +.panel-5, +.panel-6, +.panel-7 { + padding: var(--left-frame-padding); +} + +.panel-4 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + min-height: 14vh; + background-color: var(--panel-4-color); +} + +.panel-5 { + height: 30vh; + background-color: var(--panel-5-color); +} + +/* Note: panel-6 height is fluid and governed by the amount of content on the page. Background color is inherited from :root --left-frame-color */ + +.panel-6 { + min-height: 15vh; +} + +.panel-7 { + height: 30vh; + border-top: var(--panel-border); + background-color: var(--panel-7-color); +} + +.right-frame { + flex: 1; + position: relative; +} + +.right-frame::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to bottom right, var(--corner-color-bottom) 50%, #000 50%); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +.right-frame::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-bottom); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +main { + padding-top: clamp(1.5rem, 5vw, 60px); + padding-bottom: .5rem; + padding-left: clamp(20px, 3vw, 50px); +} + +main > *:first-child, +article > *:first-child { + margin-top: 0; +} + +main:has(.floor-heading) > *:nth-child(2) { + margin-top: 0; +} + +.flexbox { + display: flex; + gap: 1.2rem; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3, h4 { + margin-block: 1.75rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; + text-box: trim-both cap alphabetic; +} + +h1 { + font-size: clamp(1.5rem, 1.25rem + 3.5vw, 4rem); + text-align: right; + color: var(--h1-color); +} + +h2 { + font-size: clamp(1.4rem, 1.1rem + 2.25vw, 2.3rem); + color: var(--h2-color); +} + +h3 { + font-size: clamp(1.15rem, 1.05rem + 1.25vw, 1.875rem); + color: var(--h3-color); +} + +h4 { + font-size: clamp(1.025rem, 1rem + 1.125vw, 1.575rem); + color: var(--h4-color); +} + +.floor-heading { + display: flex; + justify-content: flex-end; + width: 100%; + position: fixed; + left: 50%; + transform: translate(-50%, 0); + bottom: 10px; + z-index:4; +} + +.floor-heading > * { + margin-block: 0; + width: fit-content; + padding-inline: .5rem; + padding-bottom: .5rem; + background-color: black; +} + +p { + margin-block: 1.75rem; + text-box: trim-both cap alphabetic; +} + +.caption { + margin-top: -1rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.indent { + padding-left: 1.5rem; +} + +.postmeta { + margin-block: 1.25rem; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +code { + font-family: monospace; + font-size: .9rem; + color: var(--code-color); +} + +.code { + width: 100%; + min-height: 5rem; + padding-block: .5rem; + padding-inline: 1rem; + background-color: #232323; + border-color: #4c4c4c; + tab-size: 4; + font-family: monospace; + font-size: .85rem; + color: #dcdcdc; +} + +hr { + margin-block: 1.5rem; + height: 6px; + border: none; + background-color: var(--font-color); + border-radius: 3px; +} + +blockquote { + margin-block: 1.75rem; + margin-left: 1.5rem; + padding-block: .25rem; + padding-left: 1.5rem; + position: relative; + text-box: trim-both cap alphabetic; +} + +blockquote::before { + content: ''; + display: block; + width: 10px; + height: 100%; + background-color: var(--font-color); + border-radius: 5px; + position: absolute; + left: 0; + top: 0; +} + +blockquote > *:first-child { + margin-top: 0; +} + +blockquote > * { + margin-bottom: 0; +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin-block: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-big { + font-size: clamp(1.2rem, 1rem + 1vw, 1.275rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 5rem; +} + +strong { + font-weight: bold; +} + +code { + font-family: monospace; + font-size: .9rem; + color: var(--code-color); +} + +.code { + width: 100%; + min-height: 5rem; + padding-block: .5rem; + padding-inline: 1rem; + tab-size: 4; + font-family: monospace; + font-size: .85rem; +} + +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +.blink-slow { + animation: blink 3500ms infinite; +} + +.blink { + animation: blink 2s infinite; +} + +.blink-fast { + animation: blink 1s infinite; +} + +@keyframes pulse { + 0% {filter: brightness(1.0)} + 50% {filter: brightness(.25)} +} + +.pulse { + animation: pulse 2300ms infinite; +} + +.pulse-rate-high { + animation: pulse 1s infinite; +} + +.accordion-wrapper { + display: block; + margin: 1.75rem auto; + width: 100%; +} + +.limit-width { + max-width: 1240px; +} + +.accordion { + display: flex; + align-items: center; + min-height: 3rem; + width: 100%; + padding-right: 2.75rem; + padding-left: 1rem; + border-radius: 100vmax; + background-color: var(--harvestgold); + border-left: solid 3rem var(--orange); + text-align: left; + font-size: 1.25rem; + color: black; + cursor: pointer; + transition: 0.4s ease; + position: relative; +} + +.active, .accordion:hover { + background-color: var(--honey); + border-left-color: var(--butter); + filter: none; +} + +.accordion:before { + content: ''; + display: block; + width: .5rem; + height: 4rem; + background-color: black; + position: absolute; + top: 0; + left: 0; +} + +.accordion:after { + display: block; + content: '\276F'; + position: absolute; + right: 1.5rem; + top: 21%; + transform: rotate(90deg); + transition: 0.4s; + font-weight: bold; + color: black; +} + +.active:after { + content: "\276F"; + transform:rotate(-90deg); + transition: 0.4s ease; +} + +.accordionContent { + padding-block: .5rem; + padding-inline: 3.5rem; + max-height: 0; + overflow: hidden; + transition: max-height 0.25s ease-out; +} + +.accordionContent ul { + margin-left: 0; +} + +@media (max-width: 525px) { + .accordion { + min-height: 2.5rem; + font-size: 1rem; + border-left-width: 2.5rem; + } +} + +/* Images */ + +.pics-right { + float: right; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +.pics-left { + float: left; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +@media (max-width: 1060px) { + .pics-right, + .pics-left { + float: none; + margin-inline: auto; + } + + .pics-right img, + .pics-left img { + margin-inline: auto; + } +} + +.pics { + margin-block: 2rem; + margin-inline: auto; +} + +.border { + border: 2px solid var(--font-color); +} + +.lcars-list { + margin-block: 1.15rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-block: .45rem; + padding-left: 2.25rem; + text-box: trim-both cap alphabetic; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 34px; + height: 18px; + border-radius: 50%; + background-color: var(--font-color); + position: absolute; + top: .45rem; + left: 0; +} + +@media (max-width: 650px) { + + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + transform: scale(90%); + } +} + +.lcars-bar { + margin-block: 1.75rem; + height: clamp(15px, 2vh, 25px); + background: transparent; + border-right: clamp(15px, 2vh, 25px) solid var(--lcars-bar-end-color); + border-left: clamp(15px, 2vh, 25px) solid var(--lcars-bar-start-color); + border-radius: 100vmax; + position: relative; +} + +.lcars-bar::after { + content: ''; + display: block; + height: clamp(15px, 2vh, 25px); + width: 100%; + background-color: var(--lcars-bar-color); + border-right: .8vh solid black; + border-left: .8vh solid black; + position: absolute; + top: 0; + left: 0; +} + +.lcars-text-bar { + display: flex; + position: relative; + height: clamp(16px, 4vh, 41px); + margin-block: 2.75rem; + overflow: visible; + border-radius: 100vmax; + background-color: var(--lcars-bar-color); + border-right: clamp(16px, 4vh, 43px) solid var(--lcars-bar-end-color); + border-left: clamp(16px, 4vh, 43px) solid var(--lcars-bar-start-color); +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar h2, +.lcars-text-bar h3, +.lcars-text-bar h4, +.lcars-text-bar span { + margin-block: 0; + background-color: black; + height: clamp(20px, 5.5vh, 60px); /* Setting height is a Firefox fix */ + overflow: visible; + border-top: 1px solid black; + padding-inline: 1vh; + font-size: clamp(17px, 4.5vh, 46px); + line-height: 1; + text-transform: uppercase; + color: var(--lcars-bar-text-color); + z-index: 1; + text-box: trim-both cap alphabetic; +} + +.lcars-text-bar::before { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.lcars-text-bar::after { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + right: 0; + overflow: hidden; +} + +/* LCARS Image Frame */ + +.image-frame { + margin: 2.75rem auto; + width: fit-content; + background: linear-gradient(var(--primary-color) 56%, var(--secondary-color) 44%); + border-radius: 50px 25px 0 50px; + position: relative; +} + +.image-frame::before { + content: ''; + display: block; + width: 40px; + height: 40px; + background-color: black; + position: absolute; + right: 0; + top: 0; +} + +.image-frame::after { + content: ''; + display: block; + border-top: var(--spacers) solid black; + border-bottom: var(--spacers) solid black; + width: 45px; + height: 80px; + background-color: var(--secondary-color); + position: absolute; + left: 0; + top: 56%; +} + +.imgf-title { + display: flex; + justify-content: flex-end; + height: 40px; + border-right: 40px solid var(--secondary-color); + border-radius: 25px 100vh 100vh 0; + position: relative; + z-index: 1; + text-align: right; +} + +.h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + border-right: var(--spacers) solid black; +} + +.imgf-title h4 { + margin-block: 0; + width: fit-content; + background-color: black; + padding-left: var(--spacers); + font-size: 2.05rem; + color: var(--title-color); + line-height: 40px; + text-transform: uppercase; +} + +.imgf-image-body { + margin-left: 45px; + background-color: black; + width: fit-content; + padding: 1rem; + border-radius: 28px 0 0 28px; +} + +.image-holder { + width: fit-content; + padding: 1rem; + border: 2px solid var(--image-border-color); + border-radius: 20px; +} + +.imgf-base { + display: grid; + grid-template-columns: 20% 13% 35px 15% 1fr; + margin-left: 80px; + border-left: var(--spacers) solid black; +} + +.imgf-block-1 { + height: var(--frame-height); + background-color: var(--accent-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-2 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-3 { + height: var(--frame-height); + background-color: black; + border-right: 10px solid var(--secondary-color); + border-left: 10px solid var(--accent-color); +} + +.imgf-block-4 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-left: var(--spacers) solid black; +} + +.imgf-block-5 { + height: var(--frame-height); + background-color: black; +} + +@media (max-width: 750px) { + + .image-frame { + border-radius: 40px 25px 0 40px; + } + + .image-frame::after { + width: 25px; + height: 60px; + top: 50%; + } + + .imgf-title { + height: 25px; + border-right: 24px solid var(--secondary-color); + } + + .h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + } + + .imgf-title h4 { + font-size: 1.45rem; + } + + .imgf-image-body { + margin-left: 25px; + padding: .75rem; + border-radius: 20px 0 0 20px; + } + + .image-holder { + padding: .75rem; + border-radius: 10px; + } +} + +/* color styles */ + +.font-butter { + color: var(--butter) !important; +} + +.button-butter, +.background-butter, +.bullet-butter::before { + background-color: var(--butter) !important; +} + +.font-daybreak { + color: var(--daybreak) !important; +} + +.button-daybreak, +.background-daybreak, +.bullet-daybreak::before { + background-color: var(--daybreak) !important; +} + +.font-harvestgold { + color: var(--harvestgold) !important; +} + +.button-harvestgold, +.background-harvestgold, +.bullet-harvestgold::before { + background-color: var(--harvestgold) !important; +} + +.font-honey { + color: var(--honey) !important; +} + +.button-honey, +.background-honey, +.bullet-honey::before { + background-color: var(--honey) !important; +} + +.font-october-sunset { + color: var(--october-sunset) !important; +} + +.button-october-sunset, +.background-october-sunset, +.bullet-october-sunset::before { + background-color: var(--october-sunset) !important; +} + +.font-orange { + color: var(--orange) !important; +} + +.button-orange, +.background-orange, +.bullet-orange::before { + background-color: var(--orange) !important; +} + +.font-rich-pumpkin{ + color: var(--rich-pumpkin) !important; +} + +.button-rich-pumpkin, +.background-rich-pumpkin, +.bullet-rich-pumpkin::before { + background-color: var(--rich-pumpkin) !important; +} + +/* Footer */ + +footer { + margin-top: 2rem; + padding-bottom: 3rem; + padding-left: clamp(20px, 3vw, 50px); + font-size: .875rem; +} + +.headtrim { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + top: 0; + left: 0; + z-index: 999; +} + +.baseboard { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + bottom: 0; + left: 0; + z-index: 999; +} + +/* Grouped @Media */ + +@media (max-width: 650px) { + + .first-bar-panel { + margin-top: .75rem; + } + + .bar-4::before { + height: 5px; + top: -12px; + } + + .bar-9::before { + height: 5px; + bottom: -12px; + } +} + +@media (max-width: 525px) { + + body { + padding: .25rem; + } + + .baseboard { + display: none; + } + + .wrap { + padding-left: 0; + padding-right: .25rem; + } + + .hop { + display: none; + } + + .left-frame { + padding-top: 8vh; + } + + .left-frame:has(.sidebar-nav) { + padding-top: 5vh; + } + + .left-frame:has(button) { + padding-top: 5vh; + } + + .floor-heading { + bottom: 0; + } + + blockquote { + margin-left: .75rem; + } +} + + @-moz-document url-prefix() { + + main { + padding-top: clamp(1rem, 4vw, 30px); + } + + h1, h2, h3, h4, p { + margin-block: 1.15rem; + } + + .postmeta { + margin-top: .75rem; + } + + .lcars-text-bar h2, + .lcars-text-bar h3, + .lcars-text-bar h4, + .lcars-text-bar span { + position: absolute; + top: -.7vh; + } + + .meta-data { + height: 1.15rem; + line-height: 1rem; + } +} \ No newline at end of file diff --git a/lcars/frontend/assets/nemesis-blue.css b/lcars/frontend/assets/nemesis-blue.css new file mode 100644 index 0000000..e763cc4 --- /dev/null +++ b/lcars/frontend/assets/nemesis-blue.css @@ -0,0 +1,2830 @@ +@charset "utf-8"; + +/* + + CSS Document + LCARS Nemesis Blue Theme + Version 24.2 + By Jim Robertus www.thelcars.com + Modified: 2025 Aug 11 + +*/ + +:root { + font-size: 1.375rem; + color-scheme: dark; + --lfw: 240px; + --cardinal: #c23; + --cool: #69f; + --evening: #26f; + --galaxy-gray: #52526a; + --ghost: #8bf; + --grape: #96c; + --honey: #fc9; + --lawn: #9a2; + --martian: #9c3; /* 9d6/9c3 (#982 dark olive & #992 light olive or yellow-green) (#9a2 lawn) (#971 flat-dark-grass) */ + --midnight: #23f; + --moonbeam: #ebf0ff; + --pumpkinshade: #f74; + --roseblush: #c66; + --tangerine: #f83; + --wheat: #ca8; + --left-frame-top-color: var(--evening); + --left-frame-color: var(--evening); /* panel-9 inherits this color */ + --left-frame-padding: .75rem; + --corner-color-top: var(--evening); + --corner-color-bottom: var(--evening); + --panel-1-color: var(--wheat); + --panel-2-color: var(--moonbeam); + --panel-4-color: var(--evening); + --panel-5-color: var(--cool); + --panel-6-color: var(--evening); + --panel-7-color: var(--evening); + --panel-8-color: var(--moonbeam); + --panel-10-color: var(--evening); + --panel-top-button-color: var(--tangerine); + --bar-height: 28px; + --bar-1-6-width: 40%; + --bar-2-7-width: 4%; + --bar-3-8-width: 17%; + --bar-5-10-width: 4%; + --bar-1-color: var(--evening); + --bar-2-color: var(--honey); + --bar-3-color: var(--cool); + --bar-4-color: var(--midnight); + --bar-5-color: var(--galaxy-gray); + --bar-6-color: var(--evening); + --bar-7-color: var(--tangerine); + --bar-8-color: var(--moonbeam); + --bar-9-color: var(--evening); + --bar-10-color: var(--galaxy-gray); + +/* Ultra layout elements */ + + --section-2-color: var(--cool); + --pill-1-color: var(--evening); + --pill-2-color: var(--cool); + --pill-3-color: var(--cool); + --pill-4-color: var(--evening); + --pill-5-color: var(--midnight); + --pill-6-color: var(--midnight); + --pill-a1-color: var(--midnight); + --pill-a2-color: var(--cool); + --pill-a3-color: black; + --pill-a4-color: var(--evening); + --pill-a5-color: var(--tangerine); + --pill-a6-color: var(--honey); + --panel-11-color: var(--cool); + --panel-12-color: var(--cool); + --panel-13-color: var(--honey); + --panel-14-color: var(--evening); + --panel-15-color: var(--cool); + + /* End Ultra layout elements */ + + --radius-top: 0 0 0 160px; + --radius-bottom: 160px 0 0 0; + --radius-content-top: 0 0 0 60px; + --radius-content-bottom: 60px 0 0 0; + --panel-border: .25rem solid black; + --bar-border: .25rem solid black; + --bar-cut-width: 34%; + --bar-cut-out-width: 34%; + --divider-height: .5rem; +/* + NOTE: --font-color also sets the following: + 1. horizontal line
color + 2. lcars-list default bullet color + 3. blockquote border color + 4. images with the *border* class border color +*/ + --font-color: var(--cool); + --sub-fonts: .875rem; + --dc-font-size: .875rem; + --dc-row-height: calc(var(--dc-font-size) + .125rem); + --banner-color: var(--ghost); + --data-cascade-color: var(--evening); + --light-color: var(--moonbeam); + --h1-color: var(--ghost); + --h2-color: var(--ghost); + --h3-color: var(--ghost); + --h4-color: var(--ghost); + --link-color: var(--cool); + --code-color: var(--martian); + --nav-width: 240px; + --nav-1-color: var(--cool); + --nav-2-color: var(--roseblush); + --nav-3-color: var(--honey); + --nav-4-color: var(--cardinal); + --button-color: var(--cool); + --button-color-sidebar: var(--cool); + --lcars-bar-color: var(--evening); + --lcars-bar-start-color: var(--midnight); + --lcars-bar-end-color: var(--midnight); + --lcars-bar-text-color: var(--moonbeam); + +/* Image Frame */ + + --image-border-color: var(--cool); + --primary-color: var(--evening); + --secondary-color: var(--cool); + --accent-color: #adcaff; /* bdd1ff */ + --spacers: .65rem; + --frame-height: 40px; +} + +@media (max-width: 1500px) { + :root { + --lfw: 200px; + --radius-top: 0 0 0 130px; + --radius-bottom: 130px 0 0 0; + --divider-height: .4rem; + --nav-width: 210px; + --dc-font-size: .75rem; + --bar-height: 24px; + } +} + +@media (max-width: 1300px) { + :root { + font-size: 1.2rem; + --sub-fonts: .9rem; + --lfw: 180px; + --nav-width: 180px; + --radius-top: 0 0 0 100px; + --radius-bottom: 100px 0 0 0; + --radius-content-top: 0 0 0 40px; + --radius-content-bottom: 40px 0 0 0; + --bar-height: 20px; + } +} + +@media (max-width: 950px) { + :root { + --lfw: 150px; + } +} + +@media (max-width: 750px) { + :root { + --panel-border: .25rem solid black; + --bar-border: .25rem solid black; + --lfw: 120px; + --radius-top: 0 0 0 80px; + --radius-bottom: 80px 0 0 0; + --radius-content-top: 0 0 0 34px; + --radius-content-bottom: 34px 0 0 0; + --nav-width: 174px; + --bar-height: 16px; + --spacers: .5rem; + --frame-height: 25px; + } +} + +@media (max-width: 525px) { + :root { + --lfw: 62px; + --left-frame-padding: .5rem; + --radius-top: 0 0 0 40px; + --radius-bottom: 40px 0 0 0; + --bar-height: 10px; + --divider-height: .3rem; + } +} + +@media (max-width: 450px) { + :root { + --nav-width: 48%; + } +} + +*, *:after, *:before { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; + font: inherit; +} + +img { + display: block; + max-width: 100%; + height: auto; +} + +input, textarea, button, select { + font: inherit; +} + +@font-face { + font-family: 'Antonio'; + font-weight: 400; + src: url('Antonio-Regular.woff2') format('woff2'), + url('Antonio-Regular.woff') format('woff'); +} + +@font-face { + font-family: 'Antonio'; + font-weight: 700; + src: url('Antonio-Bold.woff2') format('woff2'), + url('Antonio-Bold.woff') format('woff') +} + +html { + scroll-behavior: smooth; +} + +body { + display: flex; + padding-top: 10px; + padding-left: 5px; + background-color: black; + font-family: 'Antonio', 'Arial Narrow', 'Avenir Next Condensed', sans-serif; + font-weight: 400; + line-height: 1.5; + color: var(--font-color); +} + +a { + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: .2rem; + color: var(--link-color); +} + +a:hover { + filter: brightness(115%); + animation: none; +} + +a:active { + filter: brightness(80%); + outline: none; +} + +button { + border: none; + outline: none; + color: black; + transition: width 1s; +} + +button:hover { + cursor: pointer; + animation: none; + filter: brightness(115%); + color: black; +} + +button:active { + filter: brightness(85%); +} + +/* Ultra Layout elements */ + +.wrap-everything { + display: flex; + width: 100%; + column-gap: 10px; +} + +#column-1 { + width: 350px; + padding: 10px 10px 10px 20px; + transition: 800ms; +} + +#column-2 { + width: var(--lfw); + background-color: var(--section-2-color); + text-align: right; + font-weight: bold; + line-height: 1.2; + color: black; + transition: 800ms; + z-index: 2; +} + +#column-2 a { + color: black; + text-decoration: none; +} + +#column-3 { + flex: 1; + margin-inline: auto; +} + +.wrap { + display: flex; + margin-inline: auto; + padding-left: 5px; + padding-right: 15px; + overflow: hidden; +} + +@media (max-width: 1680px) { + #column-1 { + margin-left: -370px; + } + + #column-2 { + margin-left: -230px; + } + + .wrap-everything { + column-gap: 5px; + } +} + +@media (max-width: 1500px) { + #column-1, + #column-2 { + display: none; + } +} + +.lcars-frame { + display: flex; + min-height: 280px; + position: relative; + --frame-color: var(--evening); +} + +.frame-col-1 { + width: 20px; + height: 280px; + background: var(--frame-color); + border-radius: 16px 0 0 16px; + position: relative; +} + +.frame-col-1:before { + content: ''; + display: block; + width: 20px; + height: 200px; + border-top: 5px solid black; + border-bottom: 5px solid black; + background-color: var(--frame-color); + position: absolute; + top: 40px; + left: 0; +} + +.frame-col-1-cell-a { + width: 14px; + height: 65px; + background-color: var(--grape); + border-left: 4px solid black; + border-bottom: 4px solid black; + position: absolute; + top: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-b { + width: 14px; + height: 70px; + background-color: var(--cool); + border-left: 4px solid black; + position: absolute; + top: 110px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-c { + width: 14px; + height: 65px; + background-color: var(--grape); + border-top: 4px solid black; + border-left: 4px solid black; + position: absolute; + bottom: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-blocks:before { + content: ''; + display: block; + width: 10px; + height: 3px; + background-color: black; + position: absolute; + top: 54px; + left: 0; +} + +.frame-col-2 { + width:20px; + height: 280px; + background-color: var(--frame-color); + position: relative; +} + +.frame-col-2:before { + content: ''; + display: block; + width: 20px; + height: 240px; + background-color: black; + border-radius: 10px 0 0 10px; + position: absolute; + top: 20px; + left: 0; +} + +.frame-col-3 { + display: flex; + width: 240px; + height: 280px; + align-items: center; + justify-content: center; +} + +.frame-col-4 { + width:20px; + height: 280px; + background-color: var(--frame-color); + position: relative; +} + +.frame-col-4:before { + content: ''; + display: block; + width: 20px; + height: 240px; + background-color: black; + border-radius: 0 10px 10px 0; + position: absolute; + top: 20px; + left: 0; +} + +.display-horizontal { + rotate: 90deg; +} + +.frame-col-5 { + width:20px; + height: 280px; + background-color: var(--frame-color); + border-radius: 0 16px 16px 0; + padding-top: 40px; + position: relative; +} + +.frame-col-5:before { + content: ''; + display: block; + width: 20px; + height: 200px; + border-top: 5px solid black; + border-bottom: 5px solid black; + background-color: var(--frame-color); +} + +.frame-col-5-cell-a { + width: 14px; + height: 65px; + background-color: var(--tangerine); + border-bottom: 4px solid black; + border-right: 4px solid black; + position: absolute; + top: 45px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-b { + width: 14px; + height: 70px; + background-color: var(--cool); + border-right: 4px solid black; + position: absolute; + top: 110px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-c { + width: 14px; + height: 65px; + background-color: var(--tangerine); + border-top: 4px solid black; + border-right: 4px solid black; + position: absolute; + bottom: 45px; + left: 0; + z-index: 2; +} + +.line { + height: 20px; + width: 12px; + background: linear-gradient(#600, #f20, #600); +} + +.line:nth-child(1) { + animation: animateLine6 1s 0.2s infinite; +} + +.line:nth-child(2) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(3) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(4) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(5) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(6) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(7) { + animation: animateLine2 1s 0.8s infinite; +} + +/* 8 & 9 are middle lines*/ + +.line:nth-child(8) { + animation: animateLine4 1s 0.9s infinite; +} + +.line:nth-child(9) { + animation: animateLine4 1s 1s infinite; +} + +.line:nth-child(10) { + animation: animateLine2 1s 0.8s infinite; +} + +.line:nth-child(11) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(12) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(13) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(14) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(15) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(16) { + animation: animateLine6 1s 0.2s infinite; +} + +@keyframes animateLine2 { + 0% { + height: 180px; + } + 50% { + height: 90px; + } + 100% { + height: 180px; + } +} + +@keyframes animateLine3 { + 0% { + height: 120px; + } + 50% { + height: 60px; + } + 100% { + height: 120px; + } +} + +@keyframes animateLine4 { + 0% { + height: 230px; + } + 50% { + height: 115px; + } + 100% { + height: 230px; + } +} + +@keyframes animateLine5 { + 0% { + height: 60px; + } + 50% { + height: 30px; + } + 100% { + height: 60px; + } +} + +@keyframes animateLine6 { + 0% { + height: 30px; + } + 50% { + height: 15px; + } + 100% { + height: 30px; + } +} + +.pillbox, +.pillbox-2 { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 8px; + margin: 1.25rem auto; + text-align: right; + font-size: var(--sub-fonts); +} + +.pill, +.pill-2 { + display: flex; + width: 100%; + height: 56px; + justify-content: flex-end; + align-items: flex-end; + text-decoration: none; + color: black; + font-weight: bold; + padding-right: .75rem; + padding-bottom: .35rem; +} + +.pillbox a { + display: flex; + width: 100%; + height: 56px; + justify-content: flex-end; + align-items: flex-end; + text-decoration: none; + color: black; + font-weight: bold; + padding-right: .75rem; + padding-bottom: .35rem; +} + +.pillbox-2 a { + display: flex; + width: 100%; + height: 56px; + justify-content: flex-end; + align-items: flex-end; + text-decoration: none; + color: black; + font-weight: bold; + padding-right: .75rem; + padding-bottom: .35rem; +} + +.pill:hover, +.pill-2:hover { + filter: brightness(115%); +} + +.pill:active, +.pill-2:active { + filter: brightness(80%); +} + +.pill:nth-child(1), +.pillbox a:nth-child(1) { + border-radius: 100vmax 0 0 100vmax; + background-color: var(--pill-1-color); +} + +.pill:nth-child(2), +.pillbox a:nth-child(2) { + background-color: var(--pill-2-color); +} + +.pill:nth-child(3), +.pillbox a:nth-child(3) { + border-radius: 100vmax 0 0 100vmax; + background-color: var(--pill-3-color); +} + +.pill:nth-child(4), +.pillbox a:nth-child(4) { + background-color: var(--pill-4-color); +} + +.pill:nth-child(5), +.pillbox a:nth-child(5) { + background-color: var(--pill-5-color); + border-radius: 100vmax 0 0 100vmax; +} + +.pill:nth-child(6), +.pillbox a:nth-child(6) { + background-color: var(--pill-6-color); +} + +.pill-2:nth-child(1), +.pillbox-2 a:nth-child(1) { + border-radius: 100vmax 0 0 100vmax; + background-color: var(--pill-a1-color); +} + +.pill-2:nth-child(2), +.pillbox-2 a:nth-child(2) { + background-color: var(--pill-a2-color); + border-radius: 0 100vmax 100vmax 0; + padding-right: 1rem; +} + +.pill-2:nth-child(3), +.pillbox-2 a:nth-child(3) { + background-color: var(--pill-a3-color); +} + +.pill-2:nth-child(4), +.pillbox-2 a:nth-child(4) { + background-color: var(--pill-a4-color); + border-radius: 0 100vmax 100vmax 0; + padding-right: 1rem; +} + +.pill-2:nth-child(5), +.pillbox-2 a:nth-child(5) { + background-color: var(--pill-a5-color); + border-radius: 100vmax 0 0 100vmax; +} + +.pill-2:nth-child(6), +.pillbox-2 a:nth-child(6) { + background-color: var(--pill-a6-color); + border-radius: 0 100vmax 100vmax 0; + padding-right: 1rem; +} + +.lcars-list-2 ul { + list-style: none; +} + +.lcars-list-2 { + margin: 0 auto 50px auto; + padding-left: 5px; +} + +.lcars-list-2 li { + position: relative; + padding-bottom: 5px; + padding-left: 38px; + font-size: var(--sub-fonts); + color: var(--font-color); +} + +.lcars-list-2 li::before { + content: ''; + display: block; + width: 24px; + height: 14px; + border-radius: 50%; + background-color: var(--font-color); + position: absolute; + top: 8px; + left: 0; +} + +.panel-11 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 23vh; + max-height: 275px; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-11-color); + border-bottom: var(--panel-border); +} + +.panel-12 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 15vh; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-12-color); + border-bottom: var(--panel-border); +} + +.panel-13 a { + display: flex; + align-items: flex-end; + justify-content: flex-end; + padding: 1.5rem .75rem .75rem 2px; + background-color: var(--panel-13-color); + border-bottom: var(--panel-border); +} + +.panel-14 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 20vh; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-14-color); + border-bottom: var(--panel-border); +} + +.panel-15 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 20vh; + padding-right: .75rem; + padding-bottom: .75rem; + background-color: var(--panel-15-color); + border-bottom: var(--panel-border); +} + +.section-2-buttons a { + display: block; + text-decoration: none; + text-align: right; + border-bottom: var(--panel-border); + padding: 1.5rem .75rem .75rem 2px; + background-color: var(--evening); + text-transform: uppercase; + color: black; +} + +.section-2-buttons a:nth-child(2) { + background-color: var(--moonbeam); +} + +/* End Ultra layout elements */ + +.scroll-top { + display: none; +} + +.left-frame-top, +.left-frame { + width: var(--lfw); + text-align: right; + font-size: clamp(.875rem, 2vw, 1rem); + line-height: 1.2; + font-weight: bold; + color: black; + transition: width 1s; +} + +.left-frame-top { + background-color: var(--left-frame-top-color); + border-radius: var(--radius-top); +} + +.left-frame-top a, +.left-frame a { + text-decoration: none; + color: black; +} + +.left-frame { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-top: 100px; + background-color: var(--left-frame-color); + border-radius: var(--radius-bottom); +} + +.panel-1 a { + display: block; + background-color: var(--panel-1-color); + padding-top: clamp(40px, 8vw, 110px); + padding-right: .75rem; + padding-bottom: .75rem; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.right-frame-top { + flex: 1; + align-content: flex-end; + position: relative; +} + +.right-frame-top:before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to top right, var(--corner-color-top) 50%, black 50%); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +.right-frame-top:after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-top); + position: absolute; + left: 0; + bottom: var(--bar-height); + z-index: -1; +} + +@media (max-width: 650px) { + .right-frame-top:before { + bottom: 16px; + } + + .right-frame-top:after { + bottom: 16px; + } +} + +@media (max-width: 525px) { + .right-frame-top:before { + bottom: 10px; + } + + .right-frame-top:after { + bottom: 10px; + } +} + +.banner { + padding-bottom: 1rem; + padding-left: 5px; + text-align: right; + text-transform: uppercase; + line-height: 1.1; + font-size: clamp(1.25rem, 0.75rem + 4vw, 3.75rem); + color: var(--banner-color); +} + +.banner a { + color: var(--banner-color); + text-decoration: none; +} + +.data-cascade-button-group { + display: flex; + justify-content: flex-end; +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +.header-content { + flex: 1; + min-height: 180px; + padding-right: .5rem; + padding-left: clamp(20px, 3vw, 50px); +} + +.header-content > *:first-child { + margin-top: 0; +} + +.header-content > *:last-child { + margin-bottom: 0; +} + +/* Data Cascade 2025 */ + +.data-cascade-wrapper { + flex: 1; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + max-width: 100%; + height: calc(var(--dc-row-height) * 9); /* 204px */ + overflow: hidden; + padding-right: .5rem; + padding-left: clamp(20px, 3vw, 50px); + column-gap: .5rem; +} + +.data-column { + display: grid; + grid-template-columns: 1fr; + margin-top: 1px; + text-align: right; + font-size: var(--dc-font-size); /* .938 */ + line-height: 1; + text-box: trim-both cap alphabetic; + color: black; +} + +.dc-row-1, +.dc-row-2, +.dc-row-3, +.dc-row-4, +.dc-row-5, +.dc-row-6, +.dc-row-7 { + text-box: trim-both cap alphabetic; + height: var(--dc-row-height); +} + +@media (max-width: 850px) { + .data-cascade-wrapper { + display: none; + } +} + + +@keyframes data-group-1 { + + 0%, + 3.99% { + color: black; + } + + 4%, + 45.99% { + color: var(--data-cascade-color); + } + + 46%, + 49.99% { + color: var(--light-color); + } + + 50%, + 63.99% { + color: var(--data-cascade-color); + } + + 64%, + 67.99% { + color: var(--light-color); + } + + 68%, + 100% { + color: var(--data-cascade-color); + } + + +} + +@keyframes data-group-1a { + + 0%, + 4.99% { + color: black; + } + + 5%, + 45.99% { + color: var(--data-cascade-color); + } + + 46%, + 49.99% { + color: var(--light-color); + } + + 50%, + 63.99% { + color: var(--data-cascade-color); + } + + 64%, + 67.99% { + color: var(--light-color); + } + + 68%, + 100% { + color: var(--data-cascade-color); + } + + +} + +@keyframes data-group-2 { + + 0%, + 12.99% { + color: black; + } + + 13%, + 49.99% { + color: var(--data-cascade-color); + } + + 50%, + 53.99% { + color: var(--light-color); + } + + 54%, + 67.99% { + color: var(--data-cascade-color); + } + + 68%, + 71.99% { + color: var(--light-color); + } + + 72%, + 100% { + color: var(--data-cascade-color); + } + + +} + +@keyframes data-group-2b { + + 0%, + 14.99% { + color: black; + } + + 15%, + 49.99% { + color: var(--data-cascade-color); + } + + 50%, + 53.99% { + color: var(--light-color); + } + + 54%, + 67.99% { + color: var(--data-cascade-color); + } + + 68%, + 71.99% { + color: var(--light-color); + } + + 72%, + 81.99% { + color: var(--data-cascade-color); + } + + 82%, + 100% { + color: var(--light-color); + } + + +} + +@keyframes data-group-3 { + + 0%, + 26.99% { + color: black; + } + + 27%, + 40.99% { + color: var(--light-color); + } + + 41%, + 53.99% { + color: var(--data-cascade-color); + } + + 54%, + 57.99% { + color: var(--light-color); + } + + 58%, + 71.99% { + color: var(--data-cascade-color); + } + + 72%, + 75.99% { + color: var(--light-color); + } + + 76%, + 100% { + color: var(--data-cascade-color); + } + +} + +.dc-row-1 { + animation: data-group-1 6000ms ease 200ms infinite; +} + +.dc-row-2 { + animation: data-group-1a 6000ms ease 200ms infinite; +} + +.dc-row-3 { + animation: data-group-2 6000ms ease 200ms infinite; +} + +.dc-row-4 { + animation: data-group-2b 6000ms ease 200ms infinite; +} + +.dc-row-5 { + animation: data-group-3 6000ms ease 200ms infinite; +} + +.dc-row-6 { + animation: data-group-3 6000ms ease 200ms infinite; +} + +.dc-row-7 { + animation: data-group-3 6000ms ease 200ms infinite; +} + + +/* Static data cascade */ + +.data-cascade-wrapper#frozen .dc-row-1 { + animation: none; + color: var(--data-cascade-color); +} + +.data-cascade-wrapper#frozen .dc-row-2 { + animation: none; + color: var(--data-cascade-color); +} + +.data-cascade-wrapper#frozen .dc-row-3 { + animation: none; + color: var(--data-cascade-color); +} + +.data-cascade-wrapper#frozen .dc-row-4 { + animation: none; + color: var(--data-cascade-color); +} + +.data-cascade-wrapper#frozen .dc-row-5 { + animation: none; + color: var(--light-color); +} + +.data-cascade-wrapper#frozen .dc-row-6 { + animation: none; + color: var(--light-color); +} + +.data-cascade-wrapper#frozen .dc-row-7 { + animation: none; + color: var(--light-color); +} + +/* Navigation & Buttons */ + +.lcars-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + margin-block: 1rem; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1 a { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + height: clamp(90px, 11vw, 160px); + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + transition: width 1s; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-1-button { + display: flex; + width: var(--lfw); + justify-content: flex-end; + align-items: flex-end; + background-color: var(--panel-1-color); + min-height: clamp(90px, 11vw, 160px); + overflow: hidden; + padding: var(--left-frame-padding); + border-radius: 0; + border-bottom: var(--panel-border); + text-decoration: none; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-2 a { + display: flex; + justify-content: flex-end; + align-items: flex-end; + min-height: 3.75rem; + padding: var(--left-frame-padding); + background-color: var(--panel-2-color); + border-bottom: var(--panel-border); +} + +nav { + display: flex; + flex-wrap: wrap; + align-self: center; + width: calc(var(--nav-width) + var(--nav-width) + 1rem); + justify-content: flex-end; + column-gap: .5rem; + row-gap: .65rem; +} + +@media (max-width: 1500px) { + nav { + column-gap: .375rem; + row-gap: .5rem; + } +} + +@media (max-width: 1440px) { + .data-cascade-button-group:has(.header-content) { + row-gap: 1rem; + } + + .data-cascade-button-group:has(.header-content) > nav { + width: 100%; + } +} + +nav a, +nav button, +.buttons button { + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + width: var(--nav-width); + height: calc(var(--nav-width) / 2.8); + padding-inline: 1.5rem; + padding-bottom: .7rem; + border-radius: 100vmax; + background-color: var(--button-color); + text-align: right; + line-height: 1.175; + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +nav a:nth-child(1), +nav button:nth-child(1) { + background-color: var(--nav-1-color); +} + +nav a:nth-child(2), +nav button:nth-child(2) { + background-color: var(--nav-2-color); +} + +nav a:nth-child(3), +nav button:nth-child(3) { + background-color: var(--nav-3-color); +} + +nav a:nth-child(4), +nav button:nth-child(4) { + background-color: var(--nav-4-color); +} + +@media (max-width: 1300px) { + nav { + padding-left: .5rem; + gap: .5rem; + } + + nav button { + padding-bottom: .5rem; + font-size: .875rem; + padding-inline: 1.25rem; + } +} + +@media (max-width: 780px) { + nav { + flex: 1; + } + + .data-cascade-button-group:has(.header-content) > *:nth-child(2) { + flex: none; + } +} + +@media (max-width: 450px) { + nav a, + nav button { + height: 63px; + } +} + +.buttons { + display: flex; + flex-wrap: wrap; + gap: .5rem; + margin-block: 2rem; +} + +.justify-space-between { + justify-content: space-between; +} + +.justify-center { + justify-content: center; +} + +.justify-flex-end { + justify-content: flex-end; +} + +.justify-space-around { + justify-content: space-around; +} + +.justify-space-evenly { + justify-content: space-evenly; +} + +.buttons a, +.buttons button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + width: 224px; + height: 80px; + padding-inline: 1.75rem; + padding-bottom: .675rem; + background-color: var(--button-color); + border-radius: 100vmax; + border-width: 0; + text-align: right; + line-height: 1.175; + text-decoration: none; + font-weight: bold; + text-transform: uppercase; + color: black; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.sidebar-nav button, +.sidebar-nav a, +.sidebar-button { + display: flex; + justify-content: flex-end; + align-items: flex-end; + min-height: 3.75rem; + width: var(--lfw); + background-color: var(--button-color-sidebar); + border-radius: 0; + border-bottom: var(--panel-border); + padding: var(--left-frame-padding); + text-decoration: none; + text-align: right; + word-break: break-all; + text-transform: uppercase; + color: black; +} + +@media (max-width: 1300px) { + .lcars-button, + .buttons a, + .buttons button { + width: 200px; + height: 74px; + } +} + +.panel-button { + display: flex; + justify-content: flex-end; + width: var(--lfw); + border-radius: 0; + padding: var(--left-frame-padding); + border-bottom: var(--panel-border); +} + +.pan-0 /* use this if you're not mimicking an established panel */ { + height: 18vh; + max-height: 240px; + background-color: var(--button-color-sidebar); +} + +.pan-4 { + height: 22vh; + max-height: 300px; + background-color: var(--panel-4-color) !important; +} + +.pan-5 { + height: 4.25rem; + background-color: var(--panel-5-color) !important; + align-items: center; +} + +.pan-6 { + height: 29vh; + max-height: 360px; + background-color: var(--panel-6-color) !important; +} + +.pan-7 { + height: 27vh; + max-height: 350px; + background-color: var(--panel-7-color) !important; +} + +.pan-8 { + height: 15vh; + background-color: var(--panel-8-color) !important; +} + +.pan-10 { + height: 30vh; + background-color: var(--panel-10-color) !important; +} + +.text-bottom { + align-items: flex-end; +} + +#topBtn { + display: none; + position: fixed; + bottom: 0; + z-index: 99; + border-radius: 0; + border-top: var(--panel-border); + border-right: none; + border-bottom: var(--panel-border); + border-left: none; + outline: none; + width: var(--lfw); + padding: var(--left-frame-padding); + padding-bottom: 10vh; + background-color: var(--panel-top-button-color); + text-align: right; + line-height: 1; + font-weight: bold; + text-transform: uppercase; + color: black; + cursor: pointer; +} + +#topBtn:hover { + filter: brightness(115%); +} + +#topBtn:active { + filter: brightness(80%); +} + +@media (max-width: 525px) { + .sidebar-button, + .sidebar-nav a, + .sidebar-nav button, + .panel-button { + font-size: .75rem; + } + + #topBtn { + padding-bottom: 6vh; + } +} + +/* --- Horizontal bar panels & sidebar panels --- */ + +.floor-text { + padding-top: .25rem; + font-size: 1.4rem; + text-align: right; + text-transform: uppercase; + color: var(--cool); +} + +.bar-panel { + display: flex; + height: var(--bar-height); +} + +.first-bar-panel { + margin-top: .5rem; +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-9, +.bar-10 { + height: var(--bar-height); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-6, +.bar-7, +.bar-8, +.bar-9 { + border-right: var(--bar-border); +} + +.bar-1 { + width: var(--bar-1-6-width); + background-color: var(--bar-1-color); +} + +.bar-2 { + width: var(--bar-2-7-width); + background-color: var(--bar-2-color); +} + +.bar-3 { + width: var(--bar-3-8-width); + background-color: var(--bar-3-color); +} + +.bar-4 { + flex: 1; + background-color: var(--bar-4-color); +} + +.bar-5 { + width: var(--bar-5-10-width); + background-color: var(--bar-5-color); +} + +.bar-6 { + width: var(--bar-1-6-width); + background-color: var(--bar-6-color); +} + +.bar-7 { + width: var(--bar-2-7-width); + background-color: var(--bar-7-color); +} + +.bar-8 { + width: var(--bar-3-8-width); + height: 50%; + background-color: var(--bar-8-color); +} + +.bar-9 { + flex: 1; + background-color: var(--bar-9-color); +} + +.bar-10 { + width: var(--bar-5-10-width); + background-color: var(--bar-10-color); +} + +/* LCARS bottom section */ + +#gap { + margin-top: var(--divider-height); +} + +.panel-3, +.panel-4, +.panel-5, +.panel-6, +.panel-7, +.panel-8 { + border-bottom: var(--panel-border); +} + +.panel-3, +.panel-4, +.panel-6, +.panel-7, +.panel-8, +.panel-10 { + padding: var(--left-frame-padding); +} + +.panel-4 { + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 22vh; + max-height: 300px; + background-color: var(--panel-4-color); +} + +.panel-5 { + display: flex; + justify-content: flex-end; + align-items: center; + height: 4.25rem; + padding: var(--left-frame-padding); + background-color: var(--panel-5-color); +} + +.panel-6 { + height: 29vh; + max-height: 360px; + background-color: var(--panel-6-color); +} + +.panel-7 { + height: 27vh; + max-height: 350px; + background-color: var(--panel-7-color); +} + +.panel-8 { + height: 15vh; + background-color: var(--panel-8-color); +} + +/* panel-9 height is fluid and governed by the amount of content on the page. Background color is inherited from :root --left-frame-color */ + +.panel-9 { + min-height: 27vh; + padding: var(--left-frame-padding); +} + +.panel-10 { + height: 30vh; + border-top: var(--panel-border); + background-color: var(--panel-10-color); +} + +@media (max-width: 525px) { + .panel-4, + .panel-6, + .panel-7 { + height: 18vh; + } +} + +.right-frame { + flex: 1; + position: relative; +} + +.right-frame:before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to bottom right, var(--corner-color-bottom) 50%, black 50%); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +.right-frame:after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: black; + border-radius: var(--radius-content-bottom); + position: absolute; + left: 0; + top: var(--bar-height); + z-index: -1; +} + +main { + padding-top: clamp(1rem, 4vw, 45px); + padding-bottom: .5rem; + padding-left: clamp(20px, 3vw, 50px); +} + +main > *:first-child, +article > *:first-child { + margin-top: 0; +} + +main:has(.floor-heading) > *:nth-child(2) { + margin-top: 0; +} + +.flexbox { + display: flex; + gap: 1.2rem; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3, h4 { + margin-block: 1.75rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; + text-box: trim-both cap alphabetic; +} + +h1 { + font-size: clamp(1.5rem, 1.25rem + 3.5vw, 4rem); + text-align: right; + color: var(--h1-color); +} + +h2 { + font-size: clamp(1.4rem, 1.1rem + 2.25vw, 2.3rem); + color: var(--h2-color); +} + +h3 { + font-size: clamp(1.15rem, 1.05rem + 1.25vw, 1.875rem); + color: var(--h3-color); +} + +h4 { + font-size: clamp(1.025rem, 1rem + 1.125vw, 1.575rem); + color: var(--h4-color); +} + +.floor-heading { + display: flex; + justify-content: flex-end; + width: 100%; + position: fixed; + left: 50%; + transform: translate(-50%, 0); + bottom: 10px; + z-index:4; +} + +.floor-heading > * { + margin-block: 0; + width: fit-content; + padding-inline: .5rem; + padding-bottom: .5rem; + background-color: black; +} + +p { + margin-block: 1.75rem; + text-box: trim-both cap alphabetic; +} + +.caption { + margin-top: -1rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.indent { + padding-left: 1.5rem; +} + +.postmeta { + margin-block: 1.25rem; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +hr { + margin-block: 1.5rem; + height: 6px; + border: none; + background-color: var(--font-color); + border-radius: 3px; +} + +blockquote { + margin-block: 1.75rem; + margin-left: 1.5rem; + padding-block: .25rem; + padding-left: 1.5rem; + position: relative; + text-box: trim-both cap alphabetic; +} + +blockquote::before { + content: ''; + display: block; + width: 10px; + height: 100%; + background-color: var(--font-color); + border-radius: 5px; + position: absolute; + left: 0; + top: 0; +} + +blockquote > *:first-child { + margin-top: 0; +} + +blockquote > * { + margin-bottom: 0; +} + +iframe { + display: block; + width: 100%; + border: none; +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin-block: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-big { + font-size: clamp(1.2rem, 1rem + 1vw, 1.275rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 5rem; +} + +.smoke-glass { + opacity: .35; +} + +strong { + font-weight: bold; +} + +code { + font-family: monospace; + font-size: .9rem; + color: var(--code-color); +} + +.code { + width: 100%; + min-height: 5rem; + padding-block: .5rem; + padding-inline: 1rem; + background-color: #232323; + border-color: #4c4c4c; + tab-size: 4; + font-family: monospace; + font-size: .85rem; + color: #dcdcdc; +} + +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +.blink-slow { + animation: blink 3500ms infinite; +} + +.blink { + animation: blink 2s infinite; +} + +.blink-fast { + animation: blink 1s infinite; +} + +@keyframes pulse { + 0% {filter: brightness(1.0)} + 50% {filter: brightness(.25)} +} + +.pulse { + animation: pulse 2s infinite; +} + +.pulse-rate-high { + animation: pulse 1s infinite; +} + +.pulse-rate-low { + animation: pulse 3s infinite; +} + +.accordion-wrapper { + display: block; + margin: 1.75rem auto; + width: 100%; +} + +.limit-width { + max-width: 1240px; +} + +.accordion { + display: flex; + align-items: center; + min-height: 3rem; + width: 100%; + padding-right: 2.75rem; + padding-left: 1rem; + border-radius: 100vmax; + background-color: var(--cool); + border-left: solid 3rem var(--evening); + text-align: left; + font-size: 1.25rem; + color: black; + cursor: pointer; + transition: 0.4s ease; + position: relative; +} + +.active, .accordion:hover { + background-color: var(--ghost); /* 8bf */ + border-left-color: var(--moonbeam); + filter: none; +} + +.accordion:before { + content: ''; + display: block; + width: .5rem; + height: 4rem; + background-color: black; + position: absolute; + top: 0; + left: 0; +} + +.accordion:after { + display: block; + content: '\276F'; + position: absolute; + right: 1.5rem; + top: 21%; + transform: rotate(90deg); + transition: 0.4s; + font-weight: bold; + color: black; +} + +.active:after { + content: "\276F"; + transform:rotate(-90deg); + transition: 0.4s ease; +} + +.accordionContent { + padding-block: .5rem; + padding-inline: 3.5rem; + max-height: 0; + overflow: hidden; + transition: max-height 0.25s ease-out; +} + +.accordionContent ul { + margin-left: 0; +} + +@media (max-width: 525px) { + .accordion { + min-height: 2.5rem; + font-size: 1rem; + border-left-width: 2.5rem; + } +} + +/* Images */ + +.pics-right { + float: right; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +.pics-left { + float: left; + margin-inline: 1rem; + margin-bottom: 2rem; + max-width: 500px; +} + +@media (max-width: 1060px) { + .pics-right, + .pics-left { + float: none; + margin-inline: auto; + } + + .pics-right img, + .pics-left img { + margin-inline: auto; + } +} + +.pics { + margin-block: 2rem; + margin-inline: auto; +} + +.border { + border: 2px solid var(--font-color); +} + +.lcars-list { + margin-block: 1.15rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-block: .45rem; + padding-left: 2.25rem; + text-box: trim-both cap alphabetic; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 34px; + height: 18px; + border-radius: 50%; + background-color: var(--font-color); + position: absolute; + top: .45rem; + left: 0; +} + +@media (max-width: 650px) { + + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + transform: scale(90%); + } +} + +.lcars-bar { + margin-block: 1.75rem; + height: clamp(15px, 2vh, 25px); + background: transparent; + border-right: clamp(15px, 2vh, 25px) solid var(--lcars-bar-end-color); + border-left: clamp(15px, 2vh, 25px) solid var(--lcars-bar-start-color); + border-radius: 100vmax; + position: relative; +} + +.lcars-bar::after { + content: ''; + display: block; + height: clamp(15px, 2vh, 25px); + width: 100%; + background-color: var(--lcars-bar-color); + border-right: .8vh solid black; + border-left: .8vh solid black; + position: absolute; + top: 0; + left: 0; +} + +.lcars-text-bar { + display: flex; + position: relative; + height: clamp(16px, 4vh, 41px); + margin-block: 2.75rem; + overflow: visible; + border-radius: 100vmax; + background-color: var(--lcars-bar-color); + border-right: clamp(16px, 4vh, 43px) solid var(--lcars-bar-end-color); + border-left: clamp(16px, 4vh, 43px) solid var(--lcars-bar-start-color); +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar h2, +.lcars-text-bar h3, +.lcars-text-bar h4, +.lcars-text-bar span { + margin-block: 0; + background-color: black; + height: clamp(20px, 5.5vh, 60px); /* Setting height is a Firefox fix */ + overflow: visible; + border-top: 1px solid black; + padding-inline: 1vh; + font-size: clamp(17px, 4.5vh, 46px); + line-height: 1; + text-transform: uppercase; + color: var(--lcars-bar-text-color); + z-index: 1; + text-box: trim-both cap alphabetic; +} + +.lcars-text-bar::before { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.lcars-text-bar::after { + content: ''; + background-color: black; + display: block; + width: 1vh; + height: 6vh; + position: absolute; + top: 0; + right: 0; + overflow: hidden; +} + +/* Image Frame */ + +.image-frame { + display: block; + margin: 2.75rem auto; + width: fit-content; + background: linear-gradient(var(--primary-color) 56%, var(--secondary-color) 44%); + border-radius: 50px 25px 0 50px; + position: relative; +} + +.image-frame::before { + content: ''; + display: block; + width: 40px; + height: 40px; + background-color: black; + position: absolute; + right: 0; + top: 0; +} + +.image-frame::after { + content: ''; + display: block; + border-top: var(--spacers) solid black; + border-bottom: var(--spacers) solid black; + width: 45px; + height: 80px; + background-color: var(--secondary-color); + position: absolute; + left: 0; + top: 56%; +} + +.imgf-title { + display: flex; + justify-content: flex-end; + height: 40px; + border-right: 40px solid var(--secondary-color); + border-radius: 25px 100vh 100vh 0; + position: relative; + z-index: 1; + text-align: right; +} + +.h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + border-right: var(--spacers) solid black; +} + +.imgf-title h4 { + margin-block: 0; + width: fit-content; + background-color: black; + padding-left: var(--spacers); + font-size: 2.05rem; + color: var(--title-color); + line-height: 40px; + text-transform: uppercase; +} + +.imgf-image-body { + margin-left: 45px; + background-color: black; + width: fit-content; + padding: 1rem; + border-radius: 28px 0 0 28px; + +} + +.image-holder { + width: fit-content; + padding: 1rem; + border: 2px solid var(--image-border-color); + border-radius: 20px; +} + +.imgf-base { + display: grid; + grid-template-columns: 20% 13% 35px 15% 1fr; + margin-left: 80px; + border-left: var(--spacers) solid black; + +} + +.imgf-block-1 { + height: var(--frame-height); + background-color: var(--accent-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-2 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-right: var(--spacers) solid black; +} + +.imgf-block-3 { + height: var(--frame-height); + background-color: black; + border-right: 10px solid var(--secondary-color); + border-left: 10px solid var(--accent-color); +} + +.imgf-block-4 { + height: var(--frame-height); + background-color: var(--secondary-color); + border-left: var(--spacers) solid black; +} + +.imgf-block-5 { + height: var(--frame-height); + background-color: black; +} + +@media (max-width: 750px) { + + .image-frame { + border-radius: 40px 25px 0 40px; + } + + .image-frame::after { + width: 25px; + height: 60px; + top: 50%; + } + + .imgf-title { + height: 25px; + border-right: 24px solid var(--secondary-color); + } + + .h4-wrapper { + width: fit-content; + height: var(--frame-height); + background-color: black; + } + + .imgf-title h4 { + font-size: 1.45rem; + } + + .imgf-image-body { + margin-left: 25px; + padding: .75rem; + border-radius: 20px 0 0 20px; + } + + .image-holder { + padding: .75rem; + border-radius: 10px; + } +} + +/* color styles */ + +.font-cardinal { + color: var(--cardinal) !important; +} + +.button-cardinal, +.background-cardinal, +.bullet-cardinal::before { + background-color: var(--cardinal) !important; +} + +.font-cool { + color: var(--cool) !important; +} + +.button-cool, +.background-cool, +.bullet-cool::before { + background-color: var(--cool) !important; +} + +.font-evening { + color: var(--evening) !important; +} + +.button-evening, +.background-evening, +.bullet-evening::before { + background-color: var(--evening) !important; +} + +.font-galaxy-gray { + color: var(--galaxy-gray) !important; +} + +.button-galaxy-gray, +.background-galaxy-gray, +.bullet-galaxy-gray::before { + background-color: var(--galaxy-gray) !important; +} + +.font-ghost { + color: var(--ghost) !important; +} + +.button-ghost, +.background-ghost, +.bullet-ghost::before { + background-color: var(--ghost) !important; +} + +.font-grape { + color: var(--grape) !important; +} + +.button-grape, +.background-grape, +.bullet-grape::before { + background-color: var(--grape) !important; +} + +.font-honey { + color: var(--honey) !important; +} + +.button-honey, +.background-honey, +.bullet-honey::before { + background-color: var(--honey) !important; +} + +.font-lawn { + color: var(--lawn) !important; +} + +.button-lawn, +.background-lawn, +.bullet-lawn::before { + background-color: var(--lawn) !important; +} + +.font-martian { + color: var(--martian) !important; +} + +.button-martian, +.background-martian, +.bullet-martian::before { + background-color: var(--martian) !important; +} + +.font-midnight { + color: var(--midnight) !important; +} + +.button-midnight, +.background-midnight, +.bullet-midnight::before { + background-color: var(--midnight) !important; +} + +.font-moonbeam { + color: var(--moonbeam) !important; +} + +.button-moonbeam, +.background-moonbeam, +.bullet-moonbeam::before { + background-color: var(--moonbeam) !important; +} + +.font-pumpkinshade { + color: var(--pumpkinshade) !important; +} + +.button-pumpkinshade, +.background-pumpkinshade, +.bullet-pumpkinshade::before { + background-color: var(--pumpkinshade) !important; +} + +.font-roseblush { + color: var(--roseblush) !important; +} + +.button-roseblush, +.background-roseblush, +.bullet-roseblush::before { + background-color: var(--roseblush) !important; +} + +.font-tangerine { + color: var(--tangerine) !important; +} + +.button-tangerine, +.background-tangerine, +.bullet-tangerine::before { + background-color: var(--tangerine) !important; +} + +.font-wheat { + color: var(--wheat) !important; +} + +.button-wheat, +.background-wheat, +.bullet-wheat::before { + background-color: var(--wheat) !important; +} + +/* Footer */ + +footer { + margin-top: 2.5vw; + padding-bottom: 3rem; + padding-left: clamp(20px, 3vw, 50px); + font-size: .875rem; +} + +.meta-data { + margin-bottom: 1rem; + width: fit-content; + font-size: 1.25rem; + border-right: 24px solid var(--cool); + border-left: 24px solid var(--cool); + border-radius: 0 100vmax 100vmax 0; + padding-inline: .375rem; + position: relative; + line-height: 1; + text-box: trim-both cap alphabetic; +} + +.meta-data:before { + content: ''; + display: block; + width: 5px; + height: 2rem; + background-color: black; + position: absolute; + top: 0; + left: -20px; +} + +.headtrim { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + top: 0; + left: 0; + z-index: 999; +} + +.baseboard { + height: 10px; + width: 100%; + background-color: black; + position: fixed; + bottom: 0; + left: 0; + z-index: 999; +} + +/* Grouped @media */ + +@media (max-width: 525px) { + + body { + padding: .25rem; + } + + .baseboard { + display: none; + } + + .wrap { + padding-left: 0; + padding-right: .25rem; + } + + .left-frame { + padding-top: 25px; + } + + .floor-heading { + bottom: 0; + } + + .hop { + display: none; + } + + .floor-text { + font-size: 1.125rem; + } + + blockquote { + margin-left: .75rem; + } +} + +@-moz-document url-prefix() { + + main { + padding-top: clamp(1rem, 4vw, 30px); + } + + h1, h2, h3, h4, p { + margin-block: 1.1rem; + } + + .lcars-text-bar h2, + .lcars-text-bar span { + position: absolute; + top: -.6vh; + } + + .meta-data { + height: 1.15rem; + line-height: 1rem; + } +} + +@-moz-document url-prefix() { + + main { + padding-top: clamp(1rem, 4vw, 30px); + } + + h1, h2, h3, h4, p { + margin-block: 1.15rem; + } + + .imgf-title h4 { + margin-top: -4px; + margin-bottom: 0; + } + + .postmeta { + margin-top: .75rem; + } + + .lcars-text-bar h2, + .lcars-text-bar h3, + .lcars-text-bar h4, + .lcars-text-bar span { + position: absolute; + top: -.7vh; + } + + .lcars-list li::before { + top: .85rem; + } + + .meta-data { + height: 1.15rem; + line-height: 1rem; + } +} \ No newline at end of file diff --git a/lcars/frontend/index copy 2.html b/lcars/frontend/index copy 2.html new file mode 100644 index 0000000..c80719d --- /dev/null +++ b/lcars/frontend/index copy 2.html @@ -0,0 +1,321 @@ + + + + + Lower Decks PADD + + + + + + + + + + + +
+
+
+ + +
02-262000
+
+
+ +
+
+
+
47
+
31
+
28
+
94
+
+
+
329
+
128
+
605
+
704
+
+
+
39725514862
+
51320259663
+
21857221984
+
40372566301
+
+
+
56
+
04
+
40
+
35
+
+
+
614
+
883
+
109
+
297
+
+
+
000
+
13
+
05
+
25
+
+
+
48
+
07
+
38
+
62
+
+
+
416
+
001
+
888
+
442
+
+
+
86225514862
+
31042009183
+
74882306985
+
54048523421
+
+
+
10
+
80
+
31
+
85
+
+
+
87
+
71
+
40
+
26
+
+
+
98
+
63
+
52
+
71
+
+
+
118
+
270
+
395
+
260
+
+
+
8675309
+
7952705
+
9282721
+
4981518
+
+
+
000
+
99
+
10
+
84
+
+
+
65821407321
+
54018820533
+
27174523016
+
38954062564
+
+
+
999
+
202
+
574
+
293
+
+
+
3872
+
1105
+
1106
+
7411
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + +
+
03-111968
+
04-041969
+
05-1701D
+
06-071984
+
+
+
07-081940
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+ CRITICAL: Core logic node recursion detected! ACK + required! +
+
+ + +
+
+ ALERT: Warp coil 7C emitting sparks +
+
+ + + + + + + + +
+
+ INFO: Crewman Mariner spilled coffee +
+
+ + +
+
+ CRITICAL: Warp field instability detected! Immediate + action! +
+
+ + +
+
+ ALERT: Transporter buffer overload +
+
+ + + + + + + + +
+
+ INFO: Crewman Boimler practicing tap-dancing in + holodeck +
+
+ +
+ + + + + +
+ +
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/lcars/frontend/index copy.html b/lcars/frontend/index copy.html new file mode 100644 index 0000000..1583566 --- /dev/null +++ b/lcars/frontend/index copy.html @@ -0,0 +1,235 @@ + + + + Lower Decks PADD + + + + + + + + + + +
+
+
+ + +
02-262000
+
+
+ +
+
+
+
47
+
31
+
28
+
94
+
+
+
329
+
128
+
605
+
704
+
+
+
39725514862
+
51320259663
+
21857221984
+
40372566301
+
+
+
56
+
04
+
40
+
35
+
+
+
614
+
883
+
109
+
297
+
+
+
000
+
13
+
05
+
25
+
+
+
48
+
07
+
38
+
62
+
+
+
416
+
001
+
888
+
442
+
+
+
86225514862
+
31042009183
+
74882306985
+
54048523421
+
+
+
10
+
80
+
31
+
85
+
+
+
87
+
71
+
40
+
26
+
+
+
98
+
63
+
52
+
71
+
+
+
118
+
270
+
395
+
260
+
+
+
8675309
+
7952705
+
9282721
+
4981518
+
+
+
000
+
99
+
10
+
84
+
+
+
65821407321
+
54018820533
+
27174523016
+
38954062564
+
+
+
999
+
202
+
574
+
293
+
+
+
3872
+
1105
+
1106
+
7411
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + +
+
03-111968
+
04-041969
+
05-1701D
+
06-071984
+
+
+
07-081940
+
+
+
+
+
+
+
+
+
+
+
+ + + +

Hello

+

Welcome to LCARS • Lower Decks PADD Theme

+

Version 24.2

+

Replace This Content With Your Own

+

Live long and prosper.

+ + + +
+ +
+
+
+ +
+
+ + \ No newline at end of file diff --git a/lcars/frontend/index.html b/lcars/frontend/index.html new file mode 100644 index 0000000..1963f18 --- /dev/null +++ b/lcars/frontend/index.html @@ -0,0 +1,345 @@ + + + + + Lower Decks PADD + + + + + + + + + + + +
+
+
+ + +
02-262000
+
+
+ +
+
+
+
47
+
31
+
28
+
94
+
+
+
329
+
128
+
605
+
704
+
+
+
39725514862
+
51320259663
+
21857221984
+
40372566301
+
+
+
56
+
04
+
40
+
35
+
+
+
614
+
883
+
109
+
297
+
+
+
000
+
13
+
05
+
25
+
+
+
48
+
07
+
38
+
62
+
+
+
416
+
001
+
888
+
442
+
+
+
86225514862
+
31042009183
+
74882306985
+
54048523421
+
+
+
10
+
80
+
31
+
85
+
+
+
87
+
71
+
40
+
26
+
+
+
98
+
63
+
52
+
71
+
+
+
118
+
270
+
395
+
260
+
+
+
8675309
+
7952705
+
9282721
+
4981518
+
+
+
000
+
99
+
10
+
84
+
+
+
65821407321
+
54018820533
+
27174523016
+
38954062564
+
+
+
999
+
202
+
574
+
293
+
+
+
3872
+
1105
+
1106
+
7411
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + +
+
03-111968
+
04-041969
+
05-1701D
+
06-071984
+
+
+
07-081940
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+ CRITICAL: Core logic node recursion detected! ACK + required! +
+ ×1 +
+
+ + +
+
+
+
+ ALERT: Warp coil 7C emitting sparks +
+ ×1 +
+
+ + + + + + + + +
+
+
+
+ INFO: Crewman Mariner spilled coffee +
+ ×1 +
+
+ +
+ + + +
+ +
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/lcars/go.mod b/lcars/go.mod new file mode 100644 index 0000000..5a773da --- /dev/null +++ b/lcars/go.mod @@ -0,0 +1,18 @@ +module ld + +go 1.25.0 + +require modernc.org/sqlite v1.39.0 + +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/sys v0.34.0 // indirect + modernc.org/libc v1.66.3 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect +) diff --git a/lcars/go.sum b/lcars/go.sum new file mode 100644 index 0000000..c46fb2d --- /dev/null +++ b/lcars/go.sum @@ -0,0 +1,49 @@ +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM= +modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU= +modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= +modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM= +modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.39.0 h1:6bwu9Ooim0yVYA7IZn9demiQk/Ejp0BtTjBWFLymSeY= +modernc.org/sqlite v1.39.0/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/lcars/interval/interval.go b/lcars/interval/interval.go new file mode 100644 index 0000000..e755d5e --- /dev/null +++ b/lcars/interval/interval.go @@ -0,0 +1,94 @@ +package interval + +import ( + "errors" + "math/rand" + "sync" + "time" +) + +type MutexMap[K comparable, V any] struct { + mutex sync.Mutex + m map[K]V +} + +func (m *MutexMap[K, V]) Get(key K) (V, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + v, ok := m.m[key] + if !ok { + return v, errors.New("unknown key") + } + return v, nil +} + +func (m *MutexMap[K, V]) Set(key K, value V) { + m.mutex.Lock() + defer m.mutex.Unlock() + + m.m[key] = value +} + +func (m *MutexMap[K, V]) Delete(key K) { + m.mutex.Lock() + defer m.mutex.Unlock() + + delete(m.m, key) +} + +var stopChannels = MutexMap[int, chan bool]{ + m: make(map[int]chan bool), +} + +// SetInterval schedules a repeating task to be executed at a specified interval. +func SetInterval(f func(), milliseconds int) (id int) { + for { + id = rand.Int() + if _, err := stopChannels.Get(id); err == nil { + continue // ID collision, keep looking for another unique random value + } + break + } + + stop := make(chan bool) + stopChannels.Set(id, stop) + + ticker := time.NewTicker(time.Duration(milliseconds) * time.Millisecond) + + go func() { + for { + select { + case <-stop: + ticker.Stop() + return + case <-ticker.C: + f() + } + } + }() + + return +} + +// ClearInterval stops a scheduled interval identified by the specified interval ID. +func ClearInterval(id int) error { + stop, err := stopChannels.Get(id) + if err != nil { + return err + } + stop <- true + stopChannels.Delete(id) + + return nil +} + +// SetTimeout schedules a one-time task to be executed after a specified interval. +func SetTimeout(f func(), milliseconds int) { + timer := time.NewTimer(time.Duration(milliseconds) * time.Millisecond) + go func() { + <-timer.C + timer.Stop() + f() + }() +} diff --git a/lcars/ld.log b/lcars/ld.log new file mode 100644 index 0000000..e69de29 diff --git a/lcars/main.go b/lcars/main.go new file mode 100644 index 0000000..8bf7efc --- /dev/null +++ b/lcars/main.go @@ -0,0 +1,153 @@ +package main + +import ( + "embed" + "fmt" + "ld/server" + "ld/sqlite" + "log" + "os" + "os/signal" + "path/filepath" + "strings" + "syscall" +) + +const ( + exitCodeErr = 1 + exitCodeInterrupt = 2 +) + +var AppRoot = "./" // path for supporting files that sit in app root folder in production + +//go:embed frontend/* +var frontend embed.FS + +//go:embed embed +var embedded embed.FS + +// main specific variables +var ExecutableName string + +func main() { + fmt.Println("Here") + err := run() + if err != nil { + os.Exit(exitCodeErr) + } + ExecutableName, err = getExecutableName() + if err != nil { + os.Exit(exitCodeErr) + } + + readCrew() + + readMessages() + + run() + +} + +func run() error { + + // setting up logging to file + logFileName := AppRoot + ExecutableName + ".log" + logFile, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Printf("error opening file: %v", err) + os.Exit(exitCodeErr) + } + defer logFile.Close() + log.SetOutput(logFile) + + stateDB, err := createStateDB(true) + if err != nil { + log.Fatalf("Failed to create internal StateDB: %v", err) + } + + return nil + // setting up the server + server, err := server.New( + logFileName, + stateDB, + embedded, + ) + + if err != nil { + log.Fatalf("server-app not created - error: %v", err) + } + + // tasks.SetupTasks(server) + + err = server.Start() + if err != nil { + fmt.Printf("server not started - error: %v \n", err) + log.Fatalf("server not started - error: %v", err) + } + + // listen for os shutdown events, report them into log file and exit application + chanOS := make(chan os.Signal, 2) + signal.Notify(chanOS, os.Interrupt, syscall.SIGTERM) + go func() { + <-chanOS + log.Println("shutting down request signal received") + server.Close() + os.Exit(exitCodeInterrupt) + }() + + // setting up the routes, hooking up API endpoints with backend functions + // routes.SetupRoutes(server) + + return nil + +} + +// some internal functions + +func getExecutableName() (string, error) { + name, err := os.Executable() + if err != nil { + return "", err + } + name = filepath.Base(name) + return strings.TrimSuffix(name, filepath.Ext(name)), nil +} + +func createStateDB(StateDBDelete bool) (*sqlite.Database, error) { + + // fileName := fmt.Sprintf("state-%s.db", ulid.Make()) + + fileName := "state.db" + + if StateDBDelete { + _, err := os.Stat(fileName) + if err == nil { + err := os.Remove(fileName) + if err != nil { + log.Fatal("error deleting statedb-file:", err) + } + } + } + + db, err := sqlite.New(fileName) + if err != nil { + return nil, err + } + + err = db.Open() + if err != nil { + return nil, err + } + + query, err := embedded.ReadFile("embed/create_state_db.sql") + if err != nil { + return nil, err + } + + _, err = db.DB().Exec(string(query)) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/lcars/server/server.go b/lcars/server/server.go new file mode 100644 index 0000000..8215953 --- /dev/null +++ b/lcars/server/server.go @@ -0,0 +1,103 @@ +// Copyright 2024 codeM GmbH +// Author: Thomas Hedeler +package server + +import ( + "embed" + "ld/interval" + "ld/sqlite" + "log" +) + +type Server struct { + SQLiteVersion string + ServerInfo map[string]any + StateDB *sqlite.Database + Embedded embed.FS + LogFileName string + TokenDuration int // TODO einbauen + Secret []byte + Header string + intervalID int + Tasks map[string]TaskFunc +} + +func New( + logfilename string, + StateDB *sqlite.Database, + embedded embed.FS, + +) (*Server, error) { + + // creating the server + return &Server{ + LogFileName: logfilename, + StateDB: StateDB, + Embedded: embedded, + Tasks: make(map[string]func(s *Server) error), + }, nil +} + +func (s *Server) Start() error { + + // query, err := s.Embedded.ReadFile("embed/win/server_info.sql") + // if err != nil { + // return err + // } + + // res, err := s.StundenDB.ReadRecords(string(query)) + // if err != nil { + // return err + // } + + // s.ServerInfo = res[0] + + // err = inits.LoadLogins(s.StundenDB, s.StateDB) + // if err != nil { + // return err + // } + + // err = inits.LoadTasks(s.StundenDB, s.StateDB) + // if err != nil { + // return err + // } + + // // start the task engine + // if s.Production { + // s.intervalID = interval.SetInterval(s.interval, 60000) // check for executable tasks every 60 seconds + // } else { + // s.intervalID = interval.SetInterval(s.interval, 30000) // check for executable tasks every 30 seconds + // } + return nil +} + +func (s *Server) Close() error { + + // stop the task engine + err := interval.ClearInterval(s.intervalID) + if err != nil { + log.Print(err) + } + + err = s.StateDB.Close() + if err != nil { + log.Print(err) + } + return err +} + +// func to dispatch routes to all parts of the application: +// they receive references to the server and the current fiber context via closures +// this way all functions have access to server properties and can handle the +// incoming requests themselves. + +// type HandlerFunc = func(s *Server, c *fiber.Ctx) error + +// func (s *Server) Handler(handler HandlerFunc) func(c *fiber.Ctx) error { +// return func(c *fiber.Ctx) error { +// return handler(s, c) +// } +// } + +// signature for internal tasks +type TaskFunc = func(s *Server) error diff --git a/lcars/server/taskengine.go b/lcars/server/taskengine.go new file mode 100644 index 0000000..7062e81 --- /dev/null +++ b/lcars/server/taskengine.go @@ -0,0 +1,118 @@ +package server + +import ( + "log" + "time" +) + +// this function schedules the tasks and will be called periodically, see server.Start() +func (s *Server) interval() { + + // read scheduled task list from stateDB + // check for next executable task: + // - if there is one or more tasks ready for execution then select one of them. + // - if there is a selected task, update its next execution field and execute the task + + defer func() { + if r := recover(); r != nil { + // fmt.Println("Recovered from panic in worker:", r) + log.Printf("recovered from panic in taskengine: %v ", r) + } + }() + + tasks, err := s.StateDB.ReadRecords("SELECT * FROM tasks ORDER by next_execution limit 1;") + + if err != nil { + log.Printf("error in taskengine: %s ", err) + return + } + + if len(tasks) < 1 { + log.Printf("error in taskengine: %s ", "found no task for execution") + return + } + + task := tasks[0] // pick the one task with the smallest next execution time, see previous sql statement + + task_name, haveTask := task["task_name"].(string) + if !haveTask { + log.Printf("error in taskengine: task %s is of wrong type", task["task_name"]) + return + } + + nextExecution := task["next_execution"].(int64) + startTime := task["start_time"].(int64) + execInterval := task["interval"].(int64) + nowSeconds := time.Now().Unix() + + if nowSeconds < nextExecution { // task execution is not yet due + return + } + + // calculate next execution time + for nextExecution = startTime; nowSeconds > nextExecution; nextExecution += execInterval { + // add as many intervals to the starttime until the next execution lies in the future + } + + task["start_time"] = task["next_execution"] + task["next_execution"] = nextExecution + + /* + no_executions INTEGER, -- how often executed + duration INTEGER, -- duration of the last exec in ms + no_errors INTEGER, -- error count + last_error_text TEXT, + + */ + + if count, ok := task["no_executions"].(int64); ok { + task["no_executions"] = count + 1 + } + + // update next_execution in state database + _, err = s.StateDB.UpsertRecord("tasks", "task_id", task) + if err != nil { + log.Printf("error in taskengine: cannot update task record - before execution %s ", err) + return + } + + task_func, haveTask := s.Tasks[task_name] // select the function with the matching name + + if !haveTask { + log.Printf("error in taskengine: task %s is not defined", task_name) + } + + if haveTask { + + start := time.Now() + // if !s.Production { + // fmt.Println("Taskengine: executing task:", task_name, start) + // } + err = task_func(s) // finally execute the task; attention: a task that panics will kill the server! + + task["duration"] = int(time.Since(start).Milliseconds()) + + if err != nil { + log.Printf("taskengine: execution task: %s failed with error: %s ", task_name, err) + task["last_error_text"] = err.Error() + if count, ok := task["no_errors"].(int64); ok { + task["no_errors"] = count + 1 + } + // if !s.Production { + // fmt.Println("Taskengine: failed task:", task_name, err) + // } + } else { + // if !s.Production { + // fmt.Println("Taskengine: successfully completed task:", task_name, time.Now()) + // } + } + + _, err = s.StateDB.UpsertRecord("tasks", "task_id", task) + if err != nil { + log.Printf("error in taskengine: cannot update task record - after execution %s ", err) + return + } + + } + +} diff --git a/lcars/sqlite/database.go b/lcars/sqlite/database.go new file mode 100644 index 0000000..f3c4b83 --- /dev/null +++ b/lcars/sqlite/database.go @@ -0,0 +1,428 @@ +package sqlite // name the package as you see fit + +import ( + "database/sql" + "errors" + "fmt" + "os" + "strconv" + "strings" + + _ "modernc.org/sqlite" +) + +// This is the data type to exchange data with the database +type Record = map[string]any + +type Database struct { + databaseName string + database *sql.DB +} + +type Transaction struct { + tx *sql.Tx + err error +} + +type Action func(tx *sql.Tx) error + +func New(DBName string) (*Database, error) { + return &Database{databaseName: DBName}, nil +} + +func (d *Database) Close() error { + return d.database.Close() +} + +// provides access to the internal database object +func (d *Database) DB() *sql.DB { + return d.database +} + +func (d *Database) Name() string { + return d.databaseName +} + +func (d *Database) Open() (err error) { + d.database, err = openSqliteDB(d.databaseName) + return err +} + +func (d *Database) OpenInMemory() (err error) { + d.database, err = sql.Open("sqlite", ":memory:") + return err +} + +func openSqliteDB(databasefilename string) (*sql.DB, error) { + + _, err := os.Stat(databasefilename) + if errors.Is(err, os.ErrNotExist) { + return createDB(databasefilename) + } + if err != nil { + return nil, err + } + return sql.Open("sqlite", databasefilename) + +} + +func createDB(dbfileName string) (*sql.DB, error) { + + query := ` + PRAGMA page_size = 4096; + PRAGMA synchronous = off; + PRAGMA foreign_keys = off; + PRAGMA journal_mode = WAL; + PRAGMA user_version = 1; + ` + db, err := sql.Open("sqlite", dbfileName) + if err != nil { + + return nil, err + } + _, err = db.Exec(query) + if err != nil { + return nil, err + } + return db, nil +} + +func (d *Database) TableList() (result []Record, err error) { + return d.ReadRecords("select name from sqlite_master where type='table';") +} + +func (d *Database) ReadTable(tablename string) (result []Record, err error) { + + return d.ReadRecords(fmt.Sprintf("select * from '%s';", tablename)) +} + +func (d *Database) ReadRecords(query string, args ...any) (result []Record, err error) { + + rows, err := d.DB().Query(query, args...) + if err != nil { + return result, err + } + defer rows.Close() + return Rows2records(rows) + +} + +func (d *Database) GetRecord(tablename string, idfield string, key any) (result Record, err error) { + + query := fmt.Sprintf("select * from %s where %s = ?;", tablename, idfield) + res, err := d.DB().Query(query, key) + if err != nil { + return result, err + } + defer res.Close() + return Rows2record(res) + +} + +func (d *Database) UpsertRecord(tablename string, idfield string, record Record) (result Record, err error) { + + return upsert(d.DB(), tablename, idfield, record) + +} + +func (d *Database) DeleteRecord(tablename string, idfield string, id any) (err error) { + + return deleteRecord(d.DB(), tablename, idfield, id) + +} + +// *sql.DB and *sql.Tx both have a method named 'Query', +// this way they can both be passed into upsert and deleteRecord function +type iquery interface { + Query(query string, args ...any) (*sql.Rows, error) +} + +func upsert(t iquery, tablename string, idfield string, record Record) (result Record, err error) { + + fields := []string{} + data := []any{} + for k, v := range record { + fields = append(fields, k) + data = append(data, v) + } + query, err := buildUpsertCommand(tablename, idfield, fields) + if err != nil { + return result, err + } + res, err := t.Query(query, data...) // res contains the full record - see SQLite: RETURNING * + if err != nil { + return result, err + } + defer res.Close() + return Rows2record(res) + +} + +func deleteRecord(t iquery, tablename string, idfield string, id any) (err error) { + + query := fmt.Sprintf("DELETE FROM \"%s\" WHERE \"%s\" = ?;", tablename, idfield) + _, err = t.Query(query, id) + return err + +} + +func buildUpsertCommand(tablename string, idfield string, fields []string) (string, error) { + var sb strings.Builder + sb.Grow(256 + len(fields)*20) // rough preallocation + + // INSERT INTO + sb.WriteString(`INSERT INTO "`) + sb.WriteString(tablename) + sb.WriteString(`"(`) + for i, f := range fields { + sb.WriteString(` "`) + sb.WriteString(f) + sb.WriteByte('"') + if i < len(fields)-1 { + sb.WriteByte(',') + } + } + sb.WriteString(")\n\tVALUES(") + + // VALUES + for i := 0; i < len(fields); i++ { + sb.WriteString(" ?") + sb.Write(strconv.AppendInt(nil, int64(i+1), 10)) + if i < len(fields)-1 { + sb.WriteByte(',') + } + } + sb.WriteString(")\n\tON CONFLICT(\"") + sb.WriteString(tablename) + sb.WriteString(`"."`) + sb.WriteString(idfield) + sb.WriteString("\")\n\tDO UPDATE SET ") + + // UPDATE SET + for i, f := range fields { + sb.WriteByte('"') + sb.WriteString(f) + sb.WriteString(`"= ?`) + sb.Write(strconv.AppendInt(nil, int64(i+1), 10)) + if i < len(fields)-1 { + sb.WriteByte(',') + } + } + sb.WriteString("\n\tRETURNING *;") + + return sb.String(), nil +} + +// func buildUpsertCommand(tablename string, idfield string, fields []string) (result string, err error) { + +// pname := map[string]string{} // assign correct index for parameter name +// // parameter position, starts at 1 in sql! So it needs to be calculated by function pname inside template + +// for i, k := range fields { +// pname[k] = strconv.Itoa(i + 1) +// } +// funcMap := template.FuncMap{ +// "pname": func(fieldname string) string { +// return pname[fieldname] +// }, +// } +// tableDef := struct { +// Tablename string +// KeyField string +// LastField int +// FieldNames []string +// }{ +// Tablename: tablename, +// KeyField: idfield, +// LastField: len(fields) - 1, +// FieldNames: fields, +// } +// var templString = `{{$last := .LastField}}INSERT INTO "{{ .Tablename }}"({{ range $i,$el := .FieldNames }} "{{$el}}"{{if ne $i $last}},{{end}}{{end}}) +// VALUES({{ range $i,$el := .FieldNames }} ?{{pname $el}}{{if ne $i $last}},{{end}}{{end}}) +// ON CONFLICT("{{ .Tablename }}"."{{.KeyField}}") +// DO UPDATE SET {{ range $i,$el := .FieldNames }}"{{$el}}"= ?{{pname $el}}{{if ne $i $last}},{{end}}{{end}} +// RETURNING *;` + +// dbTempl, err := template.New("upsertDB").Funcs(funcMap).Parse(templString) +// if err != nil { +// return result, err +// } +// var templBytes bytes.Buffer +// err = dbTempl.Execute(&templBytes, tableDef) +// if err != nil { +// return result, err +// } +// return templBytes.String(), nil +// } + +func Rows2record(rows *sql.Rows) (Record, error) { + columns, err := rows.Columns() + if err != nil { + return nil, err + } + values := make([]any, len(columns)) + valuePtrs := make([]any, len(columns)) + for i := range values { + valuePtrs[i] = &values[i] + } + result := Record{} + for rows.Next() { + if err := rows.Scan(valuePtrs...); err != nil { + return nil, err + } + for i, col := range columns { + result[col] = values[i] + } + } + if len(result) == 0 { + return nil, errors.New("no rows found") + } + return result, nil +} + +func Rows2records(rows *sql.Rows) ([]Record, error) { + columns, err := rows.Columns() + if err != nil { + return nil, err + } + recLength := len(columns) + results := []Record{} + for rows.Next() { + values := make([]any, recLength) + valuePtrs := make([]any, recLength) + for i := range values { + valuePtrs[i] = &values[i] + } + record := Record{} + if err := rows.Scan(valuePtrs...); err != nil { + return nil, err + } + for i, col := range columns { + record[col] = values[i] + } + results = append(results, record) + } + if len(results) == 0 { + return nil, errors.New("no rows found") + } + return results, nil +} + +func (d *Database) Version() (string, error) { + result := "" + sqliteversion, err := d.ReadRecords("SELECT sqlite_version();") + if len(sqliteversion) == 1 { + result = sqliteversion[0]["sqlite_version()"].(string) + } + return result, err +} + +func (d *Database) UserVersion() (int64, error) { + + var result int64 + userversion, err := d.ReadRecords("PRAGMA user_version;") + if len(userversion) == 1 { + result = userversion[0]["user_version"].(int64) + } + return result, err +} + +func (d *Database) Begin() *Transaction { + tx, err := d.database.Begin() + return &Transaction{tx, err} +} + +func (t *Transaction) Next(action Action) *Transaction { + if t.err != nil { + return t + } + t.err = action(t.tx) + return t +} + +func (t *Transaction) End() error { + + if t.err != nil { + err := t.tx.Rollback() + if err != nil { + t.err = errors.Join(t.err, err) + } + return t.err + } + t.err = t.tx.Commit() + return t.err +} + +func (t *Transaction) GetRecord(tablename string, idfield string, key any, output Record) *Transaction { + + if t.err != nil { + return t + } + query := fmt.Sprintf("select * from %s where %s = ?;", tablename, idfield) + res, err := t.tx.Query(query, key) + if err != nil { + t.err = err + return t + } + defer res.Close() + result, err := Rows2record(res) + if err != nil { + t.err = err + return t + } + for k := range output { + delete(output, k) + } + for k, v := range result { + output[k] = v + } + return t +} + +func (t *Transaction) UpsertRecord(tablename string, idfield string, record Record, output Record) *Transaction { + + if t.err != nil { + return t + } + result, err := upsert(t.tx, tablename, idfield, record) + if err != nil { + t.err = err + return t + } + for k := range output { + delete(output, k) + } + for k, v := range result { + output[k] = v + } + return t +} + +func (t *Transaction) DeleteRecord(tablename string, idfield string, id any) *Transaction { + + if t.err != nil { + return t + } + err := deleteRecord(t.tx, tablename, idfield, id) + if err != nil { + t.err = err + } + return t +} + +// returns a value of the provided type, if the field exist and if it can be cast into the provided type parameter +func Value[T any](rec Record, field string) (value T, ok bool) { + var v any + if v, ok = rec[field]; ok { + value, ok = v.(T) + } + return +} + +// don't report an error if there are simply just 'no rows found' +func NoRowsOk(recs []Record, err error) ([]Record, error) { + if err != nil && err.Error() != "no rows found" { + return recs, err + } + return recs, nil +} diff --git a/lcars/state.db b/lcars/state.db new file mode 100644 index 0000000..4db8e95 Binary files /dev/null and b/lcars/state.db differ diff --git a/lcars/state.db-shm b/lcars/state.db-shm new file mode 100644 index 0000000..22ce83b Binary files /dev/null and b/lcars/state.db-shm differ diff --git a/lcars/state.db-wal b/lcars/state.db-wal new file mode 100644 index 0000000..25c0e12 Binary files /dev/null and b/lcars/state.db-wal differ