From da711e9ded2e58987b177ce6dbe3a5b3269dd8e7 Mon Sep 17 00:00:00 2001 From: EspenTinius Date: Mon, 25 May 2026 11:36:00 +0200 Subject: [PATCH] ny stil :) --- .../ntnu/idi/idatt2003/g40/mappe/Main.java | 12 + .../g40/mappe/utils/ThemeManager.java | 136 ++ .../mappe/view/creategame/CreateGameView.java | 16 +- .../g40/mappe/view/ingame/InGameView.java | 63 +- .../settings/InGameSettingsActions.java | 15 + .../settings/InGameSettingsController.java | 66 + .../ingame/settings/InGameSettingsView.java | 153 ++ .../g40/mappe/view/mainmenu/MainMenuView.java | 123 +- .../g40/mappe/view/playgame/PlayGameView.java | 67 +- .../g40/mappe/view/settings/SettingsView.java | 67 +- .../view/widgets/topbar/TopBarController.java | 14 + .../mappe/view/widgets/topbar/TopBarView.java | 2 +- src/main/resources/styles.css | 1845 +++++++++++++---- 13 files changed, 2043 insertions(+), 536 deletions(-) create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/ThemeManager.java create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsActions.java create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsController.java create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsView.java diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java index d6c8602..3caea4b 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java @@ -8,11 +8,14 @@ import edu.ntnu.idi.idatt2003.g40.mappe.service.SaveGameService; import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager; import edu.ntnu.idi.idatt2003.g40.mappe.utils.ConfigValues; +import edu.ntnu.idi.idatt2003.g40.mappe.utils.ThemeManager; import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager; import edu.ntnu.idi.idatt2003.g40.mappe.view.creategame.CreateGameController; import edu.ntnu.idi.idatt2003.g40.mappe.view.creategame.CreateGameView; import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameController; import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView; +import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.settings.InGameSettingsController; +import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.settings.InGameSettingsView; import edu.ntnu.idi.idatt2003.g40.mappe.view.mainmenu.MainMenuController; import edu.ntnu.idi.idatt2003.g40.mappe.view.mainmenu.MainMenuView; import edu.ntnu.idi.idatt2003.g40.mappe.view.playgame.PlayGameController; @@ -76,6 +79,9 @@ public void start(final Stage stage) throws Exception { stage.setWidth(ConfigValues.VIEWPORT_WIDTH.getValue()); stage.setHeight(ConfigValues.VIEWPORT_HEIGHT.getValue()); + // Register the scene with the theme manager so it can toggle dark/light. + ThemeManager.getInstance().registerScene(scene); + EventManager eventManager = new EventManager(); ViewManager viewManager = new ViewManager(stage, eventManager); @@ -198,6 +204,12 @@ public void start(final Stage stage) throws Exception { miniGamesView.getRootPane() ); + // In-game settings overlay (Dark / Light theme toggle). + InGameSettingsView inGameSettingsView = new InGameSettingsView(); + InGameSettingsController inGameSettingsController = + new InGameSettingsController(inGameSettingsView, eventManager, inGameView); + topBarController.setSettingsAction(inGameSettingsController::show); + // Register all views viewManager.addView(mainMenuView); viewManager.addView(playGameView); diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/ThemeManager.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/ThemeManager.java new file mode 100644 index 0000000..f5e1c58 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/utils/ThemeManager.java @@ -0,0 +1,136 @@ +package edu.ntnu.idi.idatt2003.g40.mappe.utils; + +import javafx.scene.Scene; + +/** + * Singleton utility for managing the active visual theme of the application. + * + *

The base stylesheet ({@code styles.css}) defines the dark theme as the + * default. When light mode is activated, this manager adds the + * {@code "light-mode"} style class on the scene's root node, which causes the + * light-mode CSS overrides to take effect for all descendant nodes.

+ * + *

The active scene is registered once from {@code Main} after the + * application has been initialized. After that, callers (e.g. the in-game + * settings panel) only need to call {@link #setTheme(Theme)} or + * {@link #toggleTheme()}.

+ */ +public final class ThemeManager { + + /** + * Style class added to the scene root to activate light mode. + * + *

Matches the {@code .light-mode} CSS rules in {@code styles.css}.

+ * */ + public static final String LIGHT_MODE_CLASS = "light-mode"; + + /** + * Available themes. + * */ + public enum Theme { + /** Default dark theme (no extra style class). */ + DARK, + + /** Light theme (adds the {@link #LIGHT_MODE_CLASS} style class). */ + LIGHT + } + + /** Singleton instance. */ + private static final ThemeManager INSTANCE = new ThemeManager(); + + /** The currently registered scene. */ + private Scene scene; + + /** The currently active theme. */ + private Theme currentTheme = Theme.DARK; + + /** + * Private constructor for singleton. + * */ + private ThemeManager() { + + } + + /** + * Getter method for the singleton instance. + * + * @return the {@link ThemeManager} singleton. + * */ + public static ThemeManager getInstance() { + return INSTANCE; + } + + /** + * Registers the active {@link Scene} with the theme manager. + * + *

Should be called once from {@code Main} after the scene is built. + * Re-registering with a new scene applies the current theme to it.

+ * + *

A listener is attached to the scene's root property so that the + * active theme is re-applied whenever the {@code ViewManager} swaps the + * scene root for a view change.

+ * + * @param scene the active scene. + * + * @throws IllegalArgumentException if scene is null. + * */ + public void registerScene(final Scene scene) { + if (scene == null) { + throw new IllegalArgumentException("Scene cannot be null!"); + } + this.scene = scene; + scene.rootProperty().addListener((obs, oldRoot, newRoot) -> applyCurrentTheme()); + applyCurrentTheme(); + } + + /** + * Getter method for the active theme. + * + * @return the currently active {@link Theme}. + * */ + public Theme getCurrentTheme() { + return currentTheme; + } + + /** + * Sets the active theme and applies it to the registered scene. + * + * @param theme the {@link Theme} to set. + * + * @throws IllegalArgumentException if theme is null. + * */ + public void setTheme(final Theme theme) { + if (theme == null) { + throw new IllegalArgumentException("Theme cannot be null!"); + } + this.currentTheme = theme; + applyCurrentTheme(); + } + + /** + * Toggles between {@link Theme#DARK} and {@link Theme#LIGHT}. + * */ + public void toggleTheme() { + setTheme(currentTheme == Theme.DARK ? Theme.LIGHT : Theme.DARK); + } + + /** + * Applies the current theme to the registered scene. + * + *

For light mode, the {@link #LIGHT_MODE_CLASS} style class is added + * to the scene root. For dark mode, it is removed.

+ * */ + private void applyCurrentTheme() { + if (scene == null || scene.getRoot() == null) { + return; + } + var styleClasses = scene.getRoot().getStyleClass(); + if (currentTheme == Theme.LIGHT) { + if (!styleClasses.contains(LIGHT_MODE_CLASS)) { + styleClasses.add(LIGHT_MODE_CLASS); + } + } else { + styleClasses.remove(LIGHT_MODE_CLASS); + } + } +} diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/creategame/CreateGameView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/creategame/CreateGameView.java index 4ee8f53..a64bec2 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/creategame/CreateGameView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/creategame/CreateGameView.java @@ -9,8 +9,6 @@ import javafx.scene.control.ChoiceBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; @@ -22,7 +20,6 @@ import java.io.File; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.util.Objects; /** * View shown after the player clicks "Create new game" in the @@ -72,9 +69,6 @@ public class CreateGameView extends ViewElement { /** "Create game" button - bottom-right corner. */ private Button createGameButton; - /** Background image displayed behind the panel. */ - private ImageView backgroundImage; - /** Central VBox stacking the input rows and bottom buttons. */ private VBox mainPanel; @@ -200,10 +194,6 @@ public void resetFields() { /** {@inheritDoc} */ @Override protected void initLayout() { - backgroundImage = new ImageView(new Image(Objects.requireNonNull( - getClass().getResourceAsStream("/millionsbackground.png")))); - backgroundImage.setPreserveRatio(false); - Text title = new Text("Create new game"); title.getStyleClass().add("create-game-title"); @@ -278,11 +268,7 @@ protected void initLayout() { HBox centerWrapper = new HBox(mainPanel); centerWrapper.setAlignment(Pos.CENTER); - getRootPane().getChildren().addAll(backgroundImage, centerWrapper); - - // Make the background fill the root pane. - backgroundImage.fitWidthProperty().bind(getRootPane().widthProperty()); - backgroundImage.fitHeightProperty().bind(getRootPane().heightProperty()); + getRootPane().getChildren().add(centerWrapper); // Hook listeners so the create-game button enables only when // every required field has a valid value. diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java index 29a298d..6ef94b2 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java @@ -5,6 +5,7 @@ import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.topbar.TopBarView; import javafx.scene.Node; import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; public class InGameView extends ViewElement { @@ -12,6 +13,18 @@ public class InGameView extends ViewElement { private final TopBarView topBarView; private Node centerView; + /** + * StackPane wrapping the active center view. Lets overlays (e.g. the + * in-game settings panel) sit on top of the current center widget while + * leaving the top bar visible. + * */ + private StackPane centerStack; + + /** + * Active settings overlay, or {@code null} if none is shown. + * */ + private Node settingsOverlay; + public InGameView(final TopBarView topBarView, final Node centerView) { this.topBarView = topBarView; this.centerView = centerView; @@ -20,19 +33,57 @@ public InGameView(final TopBarView topBarView, final Node centerView) { @Override protected void initLayout() { - getRootPane().getChildren().addAll(topBarView.getRootPane(), centerView); - VBox.setVgrow(centerView, Priority.ALWAYS); + centerStack = new StackPane(centerView); + getRootPane().getChildren().addAll(topBarView.getRootPane(), centerStack); + VBox.setVgrow(centerStack, Priority.ALWAYS); } @Override protected void initStyling() { - + getRootPane().getStyleClass().add("in-game-root"); } public void changeCenterView(final Node newCenterView) { this.centerView = newCenterView; - getRootPane().getChildren().clear(); - getRootPane().getChildren().addAll(topBarView.getRootPane(), centerView); - VBox.setVgrow(centerView, Priority.ALWAYS); + centerStack.getChildren().clear(); + centerStack.getChildren().add(centerView); + if (settingsOverlay != null) { + centerStack.getChildren().add(settingsOverlay); + } + } + + /** + * Shows a settings overlay on top of the current center view. + * + *

The top bar remains visible above the overlay. If an overlay is + * already shown, this is a no-op.

+ * + * @param overlay the overlay root node to show. + * */ + public void showSettingsOverlay(final Node overlay) { + if (settingsOverlay != null || overlay == null) { + return; + } + settingsOverlay = overlay; + centerStack.getChildren().add(settingsOverlay); + } + + /** + * Hides the active settings overlay if one is shown. + * */ + public void hideSettingsOverlay() { + if (settingsOverlay != null) { + centerStack.getChildren().remove(settingsOverlay); + settingsOverlay = null; + } + } + + /** + * Returns whether a settings overlay is currently shown. + * + * @return {@code true} if the settings overlay is visible. + * */ + public boolean isSettingsOverlayVisible() { + return settingsOverlay != null; } } diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsActions.java new file mode 100644 index 0000000..c801ea8 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsActions.java @@ -0,0 +1,15 @@ +package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.settings; + +/** + * User-triggered actions available in the in-game settings overlay. + * */ +public enum InGameSettingsActions { + /** Closes the settings overlay and returns to the game. */ + CLOSE, + + /** Selects the dark theme. */ + DARK_MODE, + + /** Selects the light theme. */ + LIGHT_MODE; +} diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsController.java new file mode 100644 index 0000000..54a1e53 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsController.java @@ -0,0 +1,66 @@ +package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.settings; + +import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager; +import edu.ntnu.idi.idatt2003.g40.mappe.utils.ThemeManager; +import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController; +import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView; + +/** + * Controller for {@link InGameSettingsView}. + * + *

Wires the close button to remove the overlay from the + * {@link InGameView}, and the theme toggle buttons to the global + * {@link ThemeManager}.

+ */ +public final class InGameSettingsController + extends ViewController { + + /** The in-game view hosting this overlay. */ + private final InGameView inGameView; + + /** + * Constructor. + * + * @param view the {@link InGameSettingsView} this controller is + * attached to. + * @param eventManager the active {@link EventManager}. + * @param inGameView the in-game view that hosts this settings overlay. + * */ + public InGameSettingsController(final InGameSettingsView view, + final EventManager eventManager, + final InGameView inGameView) { + this.inGameView = inGameView; + super(view, eventManager); + // Sync the highlighted button with the current theme on construction. + getViewElement().setActiveTheme(ThemeManager.getInstance().getCurrentTheme()); + } + + /** {@inheritDoc} */ + @Override + protected void initInteractions() { + getViewElement().setOnAction(InGameSettingsActions.CLOSE, + inGameView::hideSettingsOverlay); + + getViewElement().setOnAction(InGameSettingsActions.DARK_MODE, () -> { + ThemeManager.getInstance().setTheme(ThemeManager.Theme.DARK); + getViewElement().setActiveTheme(ThemeManager.Theme.DARK); + }); + + getViewElement().setOnAction(InGameSettingsActions.LIGHT_MODE, () -> { + ThemeManager.getInstance().setTheme(ThemeManager.Theme.LIGHT); + getViewElement().setActiveTheme(ThemeManager.Theme.LIGHT); + }); + } + + /** + * Shows the settings overlay on the host {@link InGameView}. + * + *

Re-syncs the active-theme highlight before showing, so that if the + * user has toggled the theme elsewhere, the panel reflects the current + * state.

+ * */ + public void show() { + getViewElement().setActiveTheme(ThemeManager.getInstance().getCurrentTheme()); + inGameView.showSettingsOverlay(getViewElement().getRootPane()); + } +} diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsView.java new file mode 100644 index 0000000..2b79504 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/settings/InGameSettingsView.java @@ -0,0 +1,153 @@ +package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.settings; + +import edu.ntnu.idi.idatt2003.g40.mappe.utils.ThemeManager; +import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + +/** + * Overlay shown when the player clicks the "Settings" button in the in-game + * top bar. + * + *

The root of this view is a dimmer {@link StackPane} that covers the + * current center widget. Inside, a centered panel hosts the actual settings + * controls.

+ * + *

Layout: a header row with the title and a close button, followed by a + * theme section containing a Dark / Light toggle and the currently selected + * theme label.

+ * + *

This view is purely presentational - the + * {@link InGameSettingsController} wires the buttons to the + * {@link ThemeManager} and to the host view's overlay show/hide methods.

+ */ +public final class InGameSettingsView + extends ViewElement { + + /** Close button shown in the panel's top-right corner. */ + private Button closeButton; + + /** Selects the dark theme. */ + private Button darkModeButton; + + /** Selects the light theme. */ + private Button lightModeButton; + + /** Modal-style card hosting the settings controls. */ + private VBox panel; + + /** + * Constructor. + * */ + public InGameSettingsView() { + super(new StackPane(), InGameSettingsActions.class); + } + + /** + * Getter for the dark-mode button. + * + * @return the dark-mode button. + * */ + public Button getDarkModeButton() { + return darkModeButton; + } + + /** + * Getter for the light-mode button. + * + * @return the light-mode button. + * */ + public Button getLightModeButton() { + return lightModeButton; + } + + /** + * Highlights the active theme button so the player always sees which + * theme is currently selected. + * + * @param theme the active {@link ThemeManager.Theme}. + * */ + public void setActiveTheme(final ThemeManager.Theme theme) { + darkModeButton.getStyleClass().remove("active"); + lightModeButton.getStyleClass().remove("active"); + if (theme == ThemeManager.Theme.LIGHT) { + lightModeButton.getStyleClass().add("active"); + } else { + darkModeButton.getStyleClass().add("active"); + } + } + + /** {@inheritDoc} */ + @Override + protected void initLayout() { + // Header row: title + close button. + Label title = new Label("Settings"); + title.getStyleClass().add("ingame-settings-title"); + + Region headerSpacer = new Region(); + HBox.setHgrow(headerSpacer, Priority.ALWAYS); + + closeButton = new Button("X"); + closeButton.setFocusTraversable(false); + closeButton.getStyleClass().add("ingame-settings-close-button"); + + HBox header = new HBox(12, title, headerSpacer, closeButton); + header.setAlignment(Pos.CENTER_LEFT); + + // Theme section: section label, current selection, two-button toggle. + Label themeSectionLabel = new Label("Theme"); + themeSectionLabel.getStyleClass().add("ingame-settings-section-label"); + + Label themeDescription = new Label( + "Choose between dark and light appearance for the game."); + themeDescription.getStyleClass().add("ingame-settings-description"); + themeDescription.setWrapText(true); + + darkModeButton = new Button("Dark mode"); + lightModeButton = new Button("Light mode"); + + darkModeButton.setFocusTraversable(false); + lightModeButton.setFocusTraversable(false); + + darkModeButton.getStyleClass().add("ingame-settings-toggle-button"); + lightModeButton.getStyleClass().add("ingame-settings-toggle-button"); + + HBox toggleRow = new HBox(12, darkModeButton, lightModeButton); + toggleRow.setAlignment(Pos.CENTER_LEFT); + + VBox themeSection = new VBox(10, themeSectionLabel, + themeDescription, toggleRow); + themeSection.setAlignment(Pos.TOP_LEFT); + + // Assemble panel. + panel = new VBox(22, header, themeSection); + panel.setAlignment(Pos.TOP_LEFT); + panel.setPadding(new Insets(28, 32, 32, 32)); + panel.setMaxWidth(440); + panel.setMaxHeight(280); + panel.setPrefWidth(440); + panel.getStyleClass().add("ingame-settings-panel"); + + // Dimmer wrapper. + getRootPane().getStyleClass().add("ingame-settings-overlay-dimmer"); + getRootPane().getChildren().add(panel); + StackPane.setAlignment(panel, Pos.CENTER); + + registerButton(InGameSettingsActions.CLOSE, closeButton); + registerButton(InGameSettingsActions.DARK_MODE, darkModeButton); + registerButton(InGameSettingsActions.LIGHT_MODE, lightModeButton); + } + + /** {@inheritDoc} */ + @Override + protected void initStyling() { + // Styling is applied via style classes assigned in initLayout(). + } +} diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/mainmenu/MainMenuView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/mainmenu/MainMenuView.java index c2fd089..63a1f5e 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/mainmenu/MainMenuView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/mainmenu/MainMenuView.java @@ -2,8 +2,12 @@ import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement; import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewEnum; +import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Button; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; @@ -11,41 +15,69 @@ /** * The main menu UI. * - *

Extends {@link ViewElement}, - * with a root pane of {@link StackPane}

- * */ + *

+ * Extends {@link ViewElement}, + * with a root pane of {@link StackPane} + *

+ * + *

+ * Layout: + *

+ *
    + *
  • Centered title block (title + tagline).
  • + *
  • Centered button stack ("Play", "Settings", "Exit").
  • + *
  • Bottom-anchored version footer.
  • + *
+ */ public class MainMenuView extends ViewElement { /** * Game title. - * */ + */ private Text titleText; + /** + * Small caption underneath the title. + */ + private Text subtitleText; + /** * "Play Game" Button. - * */ + */ private Button toGameButton; /** * "Settings" Button. - * */ + */ private Button settingsButton; /** * "Exit" Button. - * */ + */ private Button exitButton; /** * Container for button elements. - * */ + */ private VBox buttonContainer; + /** + * Container holding the title + subtitle. + */ + private VBox titleBlock; + + /** + * Footer label sitting at the bottom of the screen. + */ + private Text footerText; + /** * Constructor. * - *

Constructs with name "MainMenu"

- * */ + *

+ * Constructs with name "MainMenu" + *

+ */ public MainMenuView() { super(new StackPane(), ViewEnum.MAIN_MENU, MainMenuActions.class); } @@ -53,29 +85,64 @@ public MainMenuView() { /** * {@inheritDoc} * - *

Displays three buttons:

+ *

+ * Displays three buttons: + *

*
    - *
  • "Play"
  • - *
  • "Settings"
  • - *
  • "Exit"
  • + *
  • "Play"
  • + *
  • "Settings"
  • + *
  • "Exit"
  • *
- * */ + */ @Override protected void initLayout() { + titleText = new Text("Millions"); + subtitleText = new Text("TRADE · COMPETE · WIN"); + + titleBlock = new VBox(4, titleText, subtitleText); + titleBlock.setAlignment(Pos.CENTER); + toGameButton = new Button("Play"); settingsButton = new Button("Settings"); exitButton = new Button("Exit"); - buttonContainer = new VBox(); - titleText = new Text("Millions"); - buttonContainer.getChildren().addAll( - titleText, - toGameButton, - settingsButton, - exitButton - ); - getRootPane().getChildren().add(buttonContainer); - StackPane.setAlignment(buttonContainer, Pos.CENTER); + buttonContainer = new VBox( + toGameButton, + settingsButton, + exitButton); + buttonContainer.setAlignment(Pos.CENTER); + + // Centered column with title block on top, buttons below, with a + // bit of breathing room between them. + VBox centerColumn = new VBox(40, titleBlock, buttonContainer); + centerColumn.setAlignment(Pos.CENTER); + + footerText = new Text("Millions · v1.0 · IDATT2003 Group 40"); + HBox footerBar = new HBox(footerText); + footerBar.setAlignment(Pos.CENTER); + footerBar.setPadding(new Insets(0, 0, 18, 0)); + + // Anchor the footer at the bottom while keeping the column centred. + Region topSpacer = new Region(); + Region bottomSpacer = new Region(); + VBox.setVgrow(topSpacer, Priority.ALWAYS); + VBox.setVgrow(bottomSpacer, Priority.ALWAYS); + + VBox rootColumn = new VBox(topSpacer, centerColumn, bottomSpacer, footerBar); + rootColumn.setAlignment(Pos.CENTER); + + // Dark gradient overlay that dims the bg image so the UI stays + // readable on top. Bound to the root so it always fills the + // window regardless of resize. + Region overlay = new Region(); + overlay.getStyleClass().add("screen-overlay"); + overlay.prefWidthProperty().bind(getRootPane().widthProperty()); + overlay.prefHeightProperty().bind(getRootPane().heightProperty()); + overlay.setMouseTransparent(true); + + getRootPane().getChildren().addAll(overlay, rootColumn); + StackPane.setAlignment(rootColumn, Pos.CENTER); + registerButton(MainMenuActions.START_GAME, toGameButton); registerButton(MainMenuActions.SETTINGS, settingsButton); registerButton(MainMenuActions.EXIT, exitButton); @@ -83,15 +150,17 @@ protected void initLayout() { /** * {@inheritDoc} - * */ + */ @Override protected void initStyling() { getRootPane().getStyleClass().add("main-menu-bg"); titleText.getStyleClass().add("title-text"); + subtitleText.getStyleClass().add("title-subtitle"); buttonContainer.getStyleClass().add("button-container"); toGameButton.getStyleClass().add("menu-button"); settingsButton.getStyleClass().add("menu-button"); exitButton.getStyleClass().add("menu-button"); + footerText.getStyleClass().add("menu-footer"); } -} +} \ No newline at end of file diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java index 3403b68..13b93d4 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java @@ -7,8 +7,7 @@ import javafx.geometry.Pos; import javafx.scene.Cursor; import javafx.scene.control.Button; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; +import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; @@ -20,7 +19,6 @@ import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.function.Consumer; /** @@ -32,8 +30,9 @@ *

* *

- * Extends {@link ViewElement} with a {@link StackPane} root so a - * background image can sit behind the central panel. + * Extends {@link ViewElement} with a {@link StackPane} root. The + * background is rendered entirely via the {@code main-menu-bg} CSS + * class on the root pane, no image is used. *

*/ public class PlayGameView extends ViewElement { @@ -47,18 +46,21 @@ public class PlayGameView extends ViewElement { /** "Back" button. */ private Button backButton; + /** Title above the save list. */ + private Text titleText; + + /** Caption underneath the title. */ + private Text subtitleText; + /** Vertical container holding the save rows. Rebuilt on every update. */ private VBox saveListContainer; /** Bottom row with the three action buttons. */ private HBox bottomButtonRow; - /** Centered panel: save list + bottom buttons stacked. */ + /** Centered panel: title + save list + bottom buttons stacked. */ private VBox mainPanel; - /** Background image displayed behind the panel. */ - private ImageView backgroundImage; - /** Current saves to display. Replaced via {@link #setSaves}. */ private List saves = new ArrayList<>(); @@ -80,7 +82,9 @@ public PlayGameView() { /** * Sets the list of saves to display and rebuilds the rows. * - *

Replaces any saves currently displayed.

+ *

+ * Replaces any saves currently displayed. + *

* * @param saves saves to display. */ @@ -120,32 +124,30 @@ public void setOnSaveSelected(final Consumer handler) { /** {@inheritDoc} */ @Override protected void initLayout() { - backgroundImage = new ImageView(new Image(Objects.requireNonNull( - getClass().getResourceAsStream("/millionsbackground.png")))); - backgroundImage.setPreserveRatio(false); - - saveListContainer = new VBox(8); + titleText = new Text("Select save"); + titleText.getStyleClass().add("play-game-title"); + subtitleText = new Text("Pick a saved run to continue."); + subtitleText.getStyleClass().add("play-game-subtitle"); + VBox titleBlock = new VBox(4, titleText, subtitleText); + titleBlock.setAlignment(Pos.CENTER); + + saveListContainer = new VBox(6); saveListContainer.setAlignment(Pos.TOP_CENTER); - saveListContainer.setPadding(new Insets(20)); createNewGameButton = new Button("Create new game"); uploadSaveButton = new Button("Upload save"); backButton = new Button("Back"); - bottomButtonRow = new HBox(20, + bottomButtonRow = new HBox(16, createNewGameButton, uploadSaveButton, backButton); bottomButtonRow.setAlignment(Pos.CENTER); - mainPanel = new VBox(30, saveListContainer, bottomButtonRow); + mainPanel = new VBox(24, titleBlock, saveListContainer, bottomButtonRow); mainPanel.setAlignment(Pos.CENTER); - mainPanel.setPadding(new Insets(40)); - mainPanel.setMaxWidth(700); + mainPanel.setPadding(new Insets(36)); + mainPanel.setMaxWidth(720); - getRootPane().getChildren().addAll(backgroundImage, mainPanel); - - // Make the background fill the root pane. - backgroundImage.fitWidthProperty().bind(getRootPane().widthProperty()); - backgroundImage.fitHeightProperty().bind(getRootPane().heightProperty()); + getRootPane().getChildren().add(mainPanel); registerButton(PlayGameActions.NEW_GAME, createNewGameButton); registerButton(PlayGameActions.UPLOAD_SAVE, uploadSaveButton); @@ -170,12 +172,21 @@ public void onUpdate() { /** * Clears and recreates all save rows from the {@link #saves} list. + * Shows an empty-state label if the list is empty. */ private void rebuildSaveList() { if (saveListContainer == null || saves == null) { return; } saveListContainer.getChildren().clear(); + + if (saves.isEmpty()) { + Label empty = new Label("No saves yet. Create a new game to get started."); + empty.getStyleClass().add("play-game-empty"); + saveListContainer.getChildren().add(empty); + return; + } + for (SaveGame save : saves) { saveListContainer.getChildren().add(buildSaveRow(save)); } @@ -198,7 +209,7 @@ private HBox buildSaveRow(final SaveGame save) { HBox row = new HBox(20, nameText, spacer, balanceText); row.setAlignment(Pos.CENTER_LEFT); - row.setPadding(new Insets(12, 24, 12, 24)); + row.setPadding(new Insets(14, 22, 14, 22)); row.getStyleClass().add("save-row"); row.setCursor(Cursor.HAND); row.setOnMouseClicked(e -> onSaveSelected.accept(save)); @@ -214,6 +225,6 @@ private String formatBalance(final double balance) { symbols.setGroupingSeparator('.'); symbols.setDecimalSeparator(','); DecimalFormat df = new DecimalFormat("+#,##0.00;-#,##0.00", symbols); - return df.format(balance) + "kr"; + return df.format(balance) + " kr"; } -} +} \ No newline at end of file diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/settings/SettingsView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/settings/SettingsView.java index beb310d..d55c9ed 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/settings/SettingsView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/settings/SettingsView.java @@ -7,16 +7,12 @@ import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.Slider; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -import java.util.Objects; - /** * View shown when the player clicks "Settings" on the main menu. * @@ -40,9 +36,6 @@ public class SettingsView extends ViewElement { /** Master volume slider for the audio section. */ private Slider masterVolumeSlider; - /** Background image displayed behind the panel. */ - private ImageView backgroundImage; - /** Main border layout containing the sidebar and content area. */ private BorderPane mainPanel; @@ -63,16 +56,16 @@ public Slider getMasterVolumeSlider() { * Replaces the content area with the audio section (master volume). */ public void showAudioSection() { - Label title = new Label("master volume"); + Label title = new Label("Master volume"); title.getStyleClass().add("settings-title"); masterVolumeSlider = new Slider(0, 100, 50); masterVolumeSlider.setMaxWidth(360); masterVolumeSlider.getStyleClass().add("settings-slider"); - VBox audioBox = new VBox(20, title, masterVolumeSlider); - audioBox.setAlignment(Pos.TOP_CENTER); - audioBox.setPadding(new Insets(30)); + VBox audioBox = new VBox(24, title, masterVolumeSlider); + audioBox.setAlignment(Pos.TOP_LEFT); + audioBox.setPadding(new Insets(20, 30, 30, 30)); contentArea.getChildren().setAll(audioBox); } @@ -81,14 +74,14 @@ public void showAudioSection() { * Replaces the content area with the video section placeholder. */ public void showVideoSection() { - Label title = new Label("video"); + Label title = new Label("Video"); title.getStyleClass().add("settings-title"); Label placeholder = new Label("(video settings coming soon)"); placeholder.getStyleClass().add("settings-placeholder"); VBox videoBox = new VBox(20, title, placeholder); - videoBox.setAlignment(Pos.TOP_CENTER); - videoBox.setPadding(new Insets(30)); + videoBox.setAlignment(Pos.TOP_LEFT); + videoBox.setPadding(new Insets(20, 30, 30, 30)); contentArea.getChildren().setAll(videoBox); } @@ -97,14 +90,14 @@ public void showVideoSection() { * Replaces the content area with the hot keys section placeholder. */ public void showHotKeysSection() { - Label title = new Label("hot keys"); + Label title = new Label("Hot keys"); title.getStyleClass().add("settings-title"); Label placeholder = new Label("(hot key bindings coming soon)"); placeholder.getStyleClass().add("settings-placeholder"); VBox hotKeysBox = new VBox(20, title, placeholder); - hotKeysBox.setAlignment(Pos.TOP_CENTER); - hotKeysBox.setPadding(new Insets(30)); + hotKeysBox.setAlignment(Pos.TOP_LEFT); + hotKeysBox.setPadding(new Insets(20, 30, 30, 30)); contentArea.getChildren().setAll(hotKeysBox); } @@ -112,43 +105,43 @@ public void showHotKeysSection() { /** {@inheritDoc} */ @Override protected void initLayout() { - backgroundImage = new ImageView(new Image(Objects.requireNonNull( - getClass().getResourceAsStream("/millionsbackground.png")))); - backgroundImage.setPreserveRatio(false); - - audioButton = new Button("audio"); - videoButton = new Button("video"); - hotKeysButton = new Button("hot keys"); + audioButton = new Button("Audio"); + videoButton = new Button("Video"); + hotKeysButton = new Button("Hot keys"); backButton = new Button("Back"); + // Sidebar header so the panel doesn't feel anonymous. + Label sidebarHeader = new Label("Settings"); + sidebarHeader.getStyleClass().add("settings-title"); + VBox.setMargin(sidebarHeader, new Insets(0, 0, 8, 0)); + // Spacer pushes the Back button to the bottom of the sidebar. Region spacer = new Region(); VBox.setVgrow(spacer, javafx.scene.layout.Priority.ALWAYS); - VBox sidebar = new VBox(15, + VBox sidebar = new VBox(8, + sidebarHeader, audioButton, videoButton, hotKeysButton, spacer, backButton); sidebar.setAlignment(Pos.TOP_LEFT); - sidebar.setPadding(new Insets(30)); - sidebar.setPrefWidth(180); + sidebar.setPadding(new Insets(28, 22, 28, 22)); + sidebar.setPrefWidth(200); contentArea = new StackPane(); - contentArea.setPadding(new Insets(30)); + contentArea.setPadding(new Insets(10)); mainPanel = new BorderPane(); mainPanel.setLeft(sidebar); mainPanel.setCenter(contentArea); - mainPanel.setMaxWidth(800); - mainPanel.setMaxHeight(500); + mainPanel.setMaxWidth(820); + mainPanel.setMaxHeight(520); + mainPanel.setPrefWidth(820); + mainPanel.setPrefHeight(520); - // Center the BorderPane on top of the background. + // Center the BorderPane. HBox centerWrapper = new HBox(mainPanel); centerWrapper.setAlignment(Pos.CENTER); - getRootPane().getChildren().addAll(backgroundImage, centerWrapper); - - // Make the background fill the root pane. - backgroundImage.fitWidthProperty().bind(getRootPane().widthProperty()); - backgroundImage.fitHeightProperty().bind(getRootPane().heightProperty()); + getRootPane().getChildren().add(centerWrapper); // Default section shown when settings opens. showAudioSection(); @@ -178,4 +171,4 @@ public void onUpdate() { showAudioSection(); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java index 051368d..a785cd3 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java @@ -157,4 +157,18 @@ public void setMarketIntegration(final Consumer centerSwitcher, inMinigamesView = true; }); } + + /** + * Wires the in-game "Settings" button to a custom action. + * + *

By default the settings button has no useful behaviour in-game (it + * is left wired to a placeholder by {@link #initInteractions()}). This + * method lets the application install a real handler - typically one + * that opens the in-game settings overlay.

+ * + * @param onSettings runnable invoked when the settings button is pressed. + * */ + public void setSettingsAction(final Runnable onSettings) { + getViewElement().setOnAction(TopBarActions.SETTINGS, onSettings); + } } \ No newline at end of file diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java index 471dfbb..bf9beb6 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java @@ -82,7 +82,7 @@ protected void initLayout() { protected void initStyling() { getRootPane().getStyleClass().add("top-bar"); Stream.of(quitBtn, statsBtn, marketBtn, settingsBtn, transactionsBtn, minigamesBtn) - .forEach(b -> b.getStyleClass().add("menu-button")); + .forEach(b -> b.getStyleClass().add("top-bar-menu-button")); } /** diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css index 4a99938..57c3410 100644 --- a/src/main/resources/styles.css +++ b/src/main/resources/styles.css @@ -1,342 +1,497 @@ +/* ===================================================================== + MILLIONS - Stylesheet + --------------------------------------------------------------------- + Modern fintech-inspired dark theme. The whole app sits on a layered + dark gradient (no background image needed) and uses a small palette: + + accent-cyan #00d4ff primary interactive highlight + accent-cyan-soft #4ad9ff softer cyan for borders + surface-dark rgba(15,22,38,0.78) panel background + surface-darker rgba(10,15,28,0.88) nested panels / rows + surface-row rgba(20,28,46,0.78) table rows + surface-row-hover rgba(30,42,68,0.92) hover state + text-primary #f0f4ff + text-secondary #8b95b7 + text-muted #5d6889 + positive #2ee59d + negative #ff5470 + ===================================================================== */ + .root { -fx-font-family: "Aptos"; } -/* Container for the buttons */ +/* ======================================================== + BACKGROUND (shared by all out-of-game screens) + ======================================================== + Layered dark gradient. Top-center radial highlight gives a + subtle "horizon" glow so the screen doesn't feel flat. */ +.main-menu-bg { + -fx-background-color: + radial-gradient(center 50% 0%, radius 80%, + rgba(0, 212, 255, 0.10) 0%, + transparent 65%), + radial-gradient(center 90% 100%, radius 70%, + rgba(46, 229, 157, 0.05) 0%, + transparent 60%), + linear-gradient(to bottom right, + #0b1426 0%, + #060a18 50%, + #0a1530 100%); +} + +/* ======================================================== + MAIN MENU + ======================================================== */ + .button-container { - -fx-spacing: 20; + -fx-spacing: 16; -fx-alignment: center; } -/* Base buttons */ +.title-text { + -fx-font-family: "Aptos"; + -fx-font-weight: bold; + -fx-font-size: 96px; + -fx-fill: #f0f4ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.45), 24, 0.25, 0, 0); +} + +.title-subtitle { + -fx-font-family: "Aptos"; + -fx-font-size: 16px; + -fx-font-weight: bold; + -fx-fill: #4ad9ff; + -fx-letter-spacing: 6px; +} + +.menu-footer { + -fx-font-family: "Aptos"; + -fx-font-size: 11px; + -fx-fill: #5d6889; +} + .menu-button { - -fx-background-color: rgba(255, 255, 255, 0.7); - -fx-background-radius: 12; + -fx-background-color: + rgba(15, 22, 38, 0.78), + linear-gradient(to bottom, + rgba(255, 255, 255, 0.04), + rgba(255, 255, 255, 0)); + -fx-background-radius: 10; + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 10; + -fx-border-width: 1.2; - -fx-min-width: 50; - -fx-pref-width: 200; - -fx-max-width: 350; + -fx-min-width: 260; + -fx-pref-width: 320; + -fx-max-width: 360; - -fx-min-height: 50; - -fx-max-height: 70; + -fx-min-height: 54; + -fx-pref-height: 54; + -fx-max-height: 60; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 24px; - -fx-text-fill: black; + -fx-font-size: 18px; + -fx-text-fill: #f0f4ff; -fx-cursor: hand; } -/* Hover effect for interactivity */ .menu-button:hover { - -fx-background-color: rgba(255, 255, 255, 0.9); - -fx-scale-x: 1.05; - -fx-scale-y: 1.05; + -fx-background-color: + rgba(0, 212, 255, 0.12), + linear-gradient(to bottom, + rgba(255, 255, 255, 0.06), + rgba(255, 255, 255, 0)); + -fx-border-color: rgba(0, 212, 255, 0.7); + -fx-text-fill: #ffffff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.45), 14, 0.3, 0, 0); } -/* Background image styling */ -.main-menu-bg { - -fx-background-image: url("millionsbackground.png"); - -fx-background-size: cover; - -fx-background-position: center; +.menu-button:pressed { + -fx-background-color: rgba(0, 212, 255, 0.22); +} + +/* ======================================================== + PLAY GAME (save selector) + ======================================================== */ + +.play-game-title { + -fx-font-family: "Aptos"; + -fx-font-weight: bold; + -fx-font-size: 32px; + -fx-fill: #f0f4ff; +} + +.play-game-subtitle { + -fx-font-family: "Aptos"; + -fx-font-size: 12px; + -fx-fill: #8b95b7; } +.play-game-empty { + -fx-font-family: "Aptos"; + -fx-font-style: italic; + -fx-font-size: 14px; + -fx-text-fill: #8b95b7; + -fx-padding: 40 0 40 0; +} -/* The translucent grey panel containing all save rows */ .save-list { - -fx-background-color: rgba(220, 220, 220, 0.85); - -fx-background-radius: 12; - -fx-min-width: 600; - -fx-spacing: 8; + -fx-background-color: rgba(15, 22, 38, 0.78); + -fx-background-radius: 14; + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 14; + -fx-border-width: 1.2; + -fx-min-width: 640; + -fx-pref-width: 640; + -fx-spacing: 6; + -fx-padding: 16; } -/* Each clickable save row */ .save-row { - -fx-background-color: rgba(173, 216, 230, 0.85); - /* Light blue */ + -fx-background-color: rgba(20, 28, 46, 0.78); -fx-background-radius: 8; + -fx-border-color: rgba(0, 212, 255, 0.08); + -fx-border-radius: 8; + -fx-border-width: 1; -fx-cursor: hand; } .save-row:hover { - -fx-background-color: rgba(135, 206, 235, 0.95); + -fx-background-color: rgba(30, 42, 68, 0.92); + -fx-border-color: rgba(0, 212, 255, 0.55); + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.18), 10, 0.2, 0, 0); } -/* Save name (left side of the row) */ .save-name { - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; -fx-font-size: 18px; - -fx-fill: black; + -fx-fill: #f0f4ff; } -/* Save balance, color-coded by sign */ .save-balance-positive { - -fx-font-family: "System"; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 18px; - -fx-fill: black; + -fx-font-size: 17px; + -fx-fill: #2ee59d; } .save-balance-negative { - -fx-font-family: "System"; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 18px; - -fx-fill: black; + -fx-font-size: 17px; + -fx-fill: #ff5470; } +/* ======================================================== + SETTINGS + ======================================================== */ - -/* The translucent main panel containing sidebar + content */ .settings-panel { - -fx-background-color: rgba(220, 220, 220, 0.85); - -fx-background-radius: 12; - -fx-border-color: rgba(135, 206, 235, 0.9); - -fx-border-width: 3; - -fx-border-radius: 12; + -fx-background-color: rgba(15, 22, 38, 0.82); + -fx-background-radius: 14; + -fx-border-color: rgba(0, 212, 255, 0.3); + -fx-border-width: 1.5; + -fx-border-radius: 14; } -/* Sidebar buttons (audio, video, hot keys, back) */ .settings-tab-button { -fx-background-color: transparent; - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 22px; - -fx-text-fill: black; + -fx-font-size: 17px; + -fx-text-fill: #8b95b7; -fx-cursor: hand; - -fx-padding: 4 8 4 8; + -fx-padding: 8 14; + -fx-background-radius: 8; + -fx-border-color: transparent; + -fx-border-width: 1; + -fx-border-radius: 8; } .settings-tab-button:hover { - -fx-text-fill: #1976d2; + -fx-text-fill: #ffffff; + -fx-background-color: rgba(0, 212, 255, 0.1); + -fx-border-color: rgba(0, 212, 255, 0.35); } -/* Title in the right content area, e.g. "master volume" */ .settings-title { - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 22px; - -fx-text-fill: black; + -fx-font-size: 26px; + -fx-text-fill: #f0f4ff; } -/* Placeholder text in incomplete sections */ .settings-placeholder { - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-style: italic; - -fx-font-size: 14px; - -fx-text-fill: #555; + -fx-font-size: 13px; + -fx-text-fill: #8b95b7; } -/* Slider styling to match the cyan thumb */ .settings-slider .thumb { - -fx-background-color: #4dd0e1; + -fx-background-color: #00d4ff; -fx-background-radius: 50%; - -fx-padding: 8; + -fx-padding: 7; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.6), 8, 0.4, 0, 0); } .settings-slider .track { - -fx-background-color: rgba(0, 0, 0, 0.4); - -fx-pref-height: 2; + -fx-background-color: rgba(255, 255, 255, 0.15); + -fx-pref-height: 3; + -fx-background-radius: 3; } -.title-text { - -fx-font-size: 100px; -} +/* ======================================================== + CREATE GAME VIEW + ======================================================== */ -/* ------------- CREATE GAME VIEW ------------- */ -/* Central panel containing the create-game form. */ .create-game-panel { - -fx-background-color: rgba(220, 220, 220, 0.85); - -fx-background-radius: 12; - -fx-border-color: rgba(135, 206, 235, 0.9); - -fx-border-width: 3; - -fx-border-radius: 12; + -fx-background-color: rgba(15, 22, 38, 0.82); + -fx-background-radius: 14; + -fx-border-color: rgba(0, 212, 255, 0.3); + -fx-border-width: 1.5; + -fx-border-radius: 14; } -/* Title text at the top of the panel. */ .create-game-title { - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 30px; - -fx-fill: black; + -fx-font-size: 28px; + -fx-fill: #f0f4ff; } -/* Label above each input. */ .create-game-label { - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 16px; - -fx-text-fill: black; + -fx-font-size: 13px; + -fx-text-fill: #8b95b7; } -/* Filename TextField + starting-capital ChoiceBox. */ .create-game-input { - -fx-background-color: rgba(255, 255, 255, 0.9); - -fx-border-color: #bbbbbb; + -fx-background-color: rgba(10, 15, 28, 0.7); + -fx-border-color: rgba(0, 212, 255, 0.25); -fx-border-radius: 8; -fx-background-radius: 8; - -fx-padding: 6 10; - -fx-font-style: italic; + -fx-padding: 8 12; -fx-font-size: 14px; -fx-pref-width: 360; + -fx-text-fill: #f0f4ff; + -fx-prompt-text-fill: #5d6889; } .create-game-input:focused { - -fx-border-color: #333333; + -fx-border-color: rgba(0, 212, 255, 0.7); + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.3), 8, 0.3, 0, 0); +} + +.create-game-input.choice-box .label { + -fx-text-fill: #f0f4ff; +} + +.create-game-input.choice-box .open-button { + -fx-background-color: transparent; + -fx-padding: 0 4 0 4; +} + +.create-game-input.choice-box .arrow { + -fx-background-color: #4ad9ff; +} + +.create-game-input.choice-box .context-menu { + -fx-background-color: rgba(15, 22, 38, 0.98); + -fx-border-color: rgba(0, 212, 255, 0.35); + -fx-border-radius: 8; + -fx-background-radius: 8; +} + +.create-game-input.choice-box .menu-item { + -fx-background-color: transparent; + -fx-padding: 6 14; +} + +.create-game-input.choice-box .menu-item .label { + -fx-text-fill: #f0f4ff; + -fx-font-size: 13px; +} + +.create-game-input.choice-box .menu-item:focused { + -fx-background-color: rgba(0, 212, 255, 0.18); } -/* Stock-data label that mirrors the current selection. */ .create-game-selection-label { - -fx-font-family: "System"; + -fx-font-family: "Aptos"; -fx-font-style: italic; - -fx-font-size: 13px; - -fx-text-fill: #555555; + -fx-font-size: 12px; + -fx-text-fill: #8b95b7; } -/* The two stock-data choice buttons sit side by side. */ .create-game-stock-button { - -fx-background-color: rgba(255, 255, 255, 0.85); - -fx-background-radius: 10; - -fx-border-color: #cccccc; - -fx-border-radius: 10; + -fx-background-color: rgba(10, 15, 28, 0.7); + -fx-background-radius: 8; + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 8; + -fx-border-width: 1.2; -fx-padding: 10 16; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 14px; - -fx-text-fill: black; + -fx-font-size: 13px; + -fx-text-fill: #f0f4ff; -fx-cursor: hand; } .create-game-stock-button:hover { - -fx-background-color: white; + -fx-background-color: rgba(0, 212, 255, 0.12); + -fx-border-color: rgba(0, 212, 255, 0.6); } -/* Highlight on the currently-active stock choice. */ .create-game-stock-button.active { - -fx-background-color: rgba(135, 206, 235, 0.95); - -fx-border-color: #1976d2; + -fx-background-color: rgba(0, 212, 255, 0.18); + -fx-border-color: #00d4ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.35), 10, 0.3, 0, 0); } -/* Bottom-row "Avbryt" button (left corner). */ .create-game-cancel-button { - -fx-background-color: rgba(200, 200, 200, 0.95); - -fx-background-radius: 10; - -fx-padding: 10 24; + -fx-background-color: rgba(255, 255, 255, 0.06); + -fx-background-radius: 8; + -fx-border-color: rgba(255, 255, 255, 0.18); + -fx-border-radius: 8; + -fx-border-width: 1; + -fx-padding: 10 28; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 14px; - -fx-text-fill: black; + -fx-font-size: 13px; + -fx-text-fill: #f0f4ff; -fx-cursor: hand; } .create-game-cancel-button:hover { - -fx-background-color: rgba(220, 220, 220, 1.0); + -fx-background-color: rgba(255, 255, 255, 0.12); + -fx-border-color: rgba(255, 255, 255, 0.32); } -/* Bottom-row "Create game" button (right corner). Shared layout - regardless of enabled/disabled state. */ .create-game-create-button { - -fx-background-radius: 10; - -fx-padding: 10 24; + -fx-background-radius: 8; + -fx-padding: 10 28; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-font-size: 14px; - -fx-text-fill: black; + -fx-font-size: 13px; + -fx-border-radius: 8; + -fx-border-width: 1; } -/* Disabled state: dark grey, semi-transparent. */ .create-game-create-button.create-game-button-disabled { - -fx-background-color: rgba(80, 80, 80, 0.5); - -fx-text-fill: rgba(255, 255, 255, 0.7); + -fx-background-color: rgba(40, 50, 70, 0.45); + -fx-border-color: rgba(255, 255, 255, 0.06); + -fx-text-fill: rgba(240, 244, 255, 0.35); -fx-cursor: default; -fx-opacity: 1.0; } -/* Enabled state: light grey, matching the cancel button. */ .create-game-create-button.create-game-button-enabled { - -fx-background-color: rgba(200, 200, 200, 0.95); - -fx-text-fill: black; + -fx-background-color: rgba(0, 212, 255, 0.92); + -fx-border-color: rgba(0, 212, 255, 1.0); + -fx-text-fill: #07142a; -fx-cursor: hand; } .create-game-create-button.create-game-button-enabled:hover { - -fx-background-color: rgba(220, 220, 220, 1.0); -} + -fx-background-color: #00e6ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.55), 14, 0.35, 0, 0); +} + +/* ======================================================== + IN-GAME : ROOT + ======================================================== + Root container of every in-game scene. Provides the same + deep-space backdrop the menus use so widgets never sit on + the JavaFX default white surface. */ +.in-game-root { + -fx-background-color: + radial-gradient(center 50% 0%, radius 60%, + rgba(0, 130, 200, 0.10) 0%, + transparent 70%), + linear-gradient(to bottom, + #0a1224 0%, + #060a14 100%); +} + +/* ======================================================== + IN-GAME : TOP BAR + ======================================================== */ -/* ------------- TOP BAR ------------- */ .top-bar { - -fx-background-color: rgba(69, 69, 69, 0.7); - /* Nice */ - -fx-margin: 10; - -fx-padding: 20 1%; + -fx-background-color: rgba(10, 15, 28, 0.92); + -fx-border-color: transparent transparent rgba(0, 212, 255, 0.25) transparent; + -fx-border-width: 0 0 1 0; + -fx-padding: 14 24; -fx-min-width: 100%; -fx-pref-width: 100%; } - .top-bar-menu-button { - -fx-font-size: 18px; + -fx-font-family: "Aptos"; + -fx-font-size: 14px; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-background-color: #f0f0f0; - -fx-background-radius: 10; - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.2), 5, 0, 0, 2); + -fx-background-color: rgba(20, 28, 46, 0.85); + -fx-background-radius: 8; + -fx-border-color: rgba(0, 212, 255, 0.2); + -fx-border-radius: 8; + -fx-border-width: 1; + -fx-text-fill: #f0f4ff; + -fx-padding: 8 18; + -fx-cursor: hand; } .top-bar-menu-button:hover { - -fx-background-color: #d0d0d0; + -fx-background-color: rgba(0, 212, 255, 0.15); + -fx-border-color: rgba(0, 212, 255, 0.7); + -fx-text-fill: #ffffff; } -/* ------------- SUMMARY IN TOP BAR -----------*/ +/* ======================================================== + IN-GAME : SUMMARY (inside the top bar) + ======================================================== */ + .summary-container { - -fx-border-color: black; - -fx-border-width: 1 0 1 0; + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-width: 0 1 0 1; -fx-max-height: 100px; -fx-min-height: 100px; - -fx-padding: 10; + -fx-padding: 10 24; } .balance-title { -fx-font-family: "Aptos"; - -fx-font-style: italic; -fx-font-weight: bold; - -fx-font-size: 14; + -fx-font-size: 11px; + -fx-text-fill: #8b95b7; } .balance-value { - -fx-font-family: "Aptos"; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-size: 24; + -fx-font-size: 22px; + -fx-text-fill: #f0f4ff; -fx-min-width: 200; } -.chart-series-line { - -fx-stroke: green; -} - - .chart-plot-background { -fx-background-color: transparent; } - .axis { - -fx-tick-label-font-weight: bold; - -fx-tick-label-font-style: italic; - -fx-tick-label-fill: black; + -fx-tick-label-font-weight: normal; + -fx-tick-label-font-size: 10; + -fx-tick-label-fill: #8b95b7; } .axis:bottom { - -fx-border-color: black transparent transparent transparent; - -fx-border-width: 2px; + -fx-border-color: rgba(255, 255, 255, 0.1) transparent transparent transparent; + -fx-border-width: 1px; } .axis:left { @@ -344,76 +499,88 @@ } .chart-series-line { - -fx-stroke: #00ff00; + -fx-stroke: #2ee59d; -fx-stroke-width: 2px; } .next-button { - -fx-background-color: #e0e0e0; - -fx-background-radius: 5; + -fx-background-color: #00d4ff; + -fx-background-radius: 8; -fx-min-width: 60; -fx-pref-width: 100; -fx-max-width: 100; -fx-font-weight: bold; - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.2), 2, 0, 0, 1); + -fx-font-size: 13px; + -fx-text-fill: #07142a; + -fx-padding: 8 16; -fx-cursor: hand; } +.next-button:hover { + -fx-background-color: #00e6ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.5), 12, 0.3, 0, 0); +} + +/* ======================================================== + IN-GAME : DASHBOARD + ======================================================== */ -/* --------------- Dashboard widget ------------- */ .dashboard-complete-sidebar { - -fx-border-color: #000000; - -fx-border-width: 0 2 0 0; - -fx-border-style: solid; + -fx-background-color: rgba(10, 15, 28, 0.6); + -fx-border-color: transparent rgba(0, 212, 255, 0.18) transparent transparent; + -fx-border-width: 0 1 0 0; -fx-padding: 20; -fx-spacing: 10; } .dashboard-sidebar-content { -fx-padding: 10; - -fx-spacing: 10; + -fx-spacing: 8; -fx-alignment: TOP_CENTER; - -fx-min-width: 150; -fx-pref-width: 150; - } .dashboard-stock-button { - -fx-background-color: #e0e0e0; + -fx-background-color: rgba(20, 28, 46, 0.78); + -fx-background-radius: 8; + -fx-border-color: rgba(0, 212, 255, 0.12); + -fx-border-radius: 8; + -fx-border-width: 1; -fx-alignment: CENTER_LEFT; - -fx-padding: 10 15 10 15; + -fx-padding: 10 14; -fx-font-weight: bold; - -fx-font-style: italic; - -fx-text-fill: black; - -fx-font-size: 13; - + -fx-text-fill: #f0f4ff; + -fx-font-size: 13px; } .dashboard-stock-button:hover { -fx-cursor: hand; - -fx-scale-x: 1.05; - -fx-scale-y: 1.05; + -fx-background-color: rgba(0, 212, 255, 0.12); + -fx-border-color: rgba(0, 212, 255, 0.6); } .dashboard-selected-stock-pill { - -fx-background-color: #e0e0e0; + -fx-background-color: rgba(20, 28, 46, 0.85); -fx-background-radius: 10; + -fx-border-color: rgba(0, 212, 255, 0.35); + -fx-border-radius: 10; + -fx-border-width: 1; -fx-padding: 10 40; - -fx-font-size: 24; + -fx-font-size: 24px; -fx-font-weight: bold; - -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.2), 5, 0, 0, 2); + -fx-text-fill: #f0f4ff; } .dashboard-buy-button { -fx-graphic: url('Icons/plus2.png'); -fx-content-display: left; -fx-graphic-text-gap: 10; - -fx-background-color: #00c853; - -fx-background-radius: 30; - -fx-text-fill: black; - -fx-font-style: italic; + -fx-background-color: #2ee59d; + -fx-background-radius: 8; + -fx-text-fill: #07142a; -fx-font-weight: bold; + -fx-font-size: 14px; -fx-min-height: 30; -fx-pref-height: 45; @@ -426,11 +593,11 @@ .dashboard-sell-button { -fx-graphic: url('Icons/minus2.png'); - -fx-background-color: #d50000; - -fx-background-radius: 30; - -fx-text-fill: black; - -fx-font-style: italic; + -fx-background-color: #ff5470; + -fx-background-radius: 8; + -fx-text-fill: #2a0612; -fx-font-weight: bold; + -fx-font-size: 14px; -fx-min-height: 30; -fx-pref-height: 45; @@ -441,17 +608,23 @@ -fx-max-width: 200; } -.dashboard-buy-button:hover, .dashboard-sell-button:hover { +.dashboard-buy-button:hover { -fx-cursor: hand; - -fx-scale-x: 1.05; - -fx-scale-y: 1.05; + -fx-effect: dropshadow(gaussian, rgba(46, 229, 157, 0.5), 14, 0.3, 0, 0); } -.dashboard-qtyBtn { - -fx-background-color: rgba(140, 140, 140, 0.6); - -fx-background-radius: 50; +.dashboard-sell-button:hover { + -fx-cursor: hand; + -fx-effect: dropshadow(gaussian, rgba(255, 84, 112, 0.5), 14, 0.3, 0, 0); +} - -fx-text-fill: white; +.dashboard-qtyBtn { + -fx-background-color: rgba(20, 28, 46, 0.78); + -fx-background-radius: 50; + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 50; + -fx-border-width: 1; + -fx-text-fill: #f0f4ff; -fx-font-weight: bold; -fx-font-size: 14px; @@ -466,11 +639,19 @@ .dashboard-qtyBtn:hover { -fx-cursor: hand; - -fx-scale-x: 1.05; - -fx-scale-y: 1.05; + -fx-background-color: rgba(0, 212, 255, 0.18); + -fx-border-color: #00d4ff; } .dashboard-qtyTextField { + -fx-background-color: rgba(10, 15, 28, 0.7); + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 8; + -fx-background-radius: 8; + -fx-border-width: 1; + -fx-text-fill: #f0f4ff; + -fx-font-family: "Consolas, Menlo, monospace"; + -fx-font-weight: bold; -fx-alignment: CENTER; -fx-min-width: 50; @@ -482,15 +663,23 @@ -fx-max-height: 60; } +.dashboard-qtyTextField:focused { + -fx-border-color: rgba(0, 212, 255, 0.7); +} + .dashboard-combo-box { - -fx-background-color: #f4f4f4; - -fx-border-color: #d1d1d1; - -fx-border-radius: 5; - -fx-background-radius: 5; + -fx-background-color: rgba(20, 28, 46, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 8; + -fx-background-radius: 8; } .dashboard-combo-box .list-cell { - -fx-text-fill: #333333; + -fx-text-fill: #f0f4ff; +} + +.dashboard-combo-box .arrow { + -fx-background-color: #4ad9ff; } .dashboard-sidebar-scrollPane { @@ -550,48 +739,55 @@ .dashboard-tradeBtns { -fx-alignment: CENTER; } -/* ------------- MARKET VIEW ------------- */ -/* Root pane fills the center area with a light translucent background. */ + +/* ======================================================== + IN-GAME : MARKET VIEW + ======================================================== */ + .market-container { - -fx-background-color: rgba(245, 245, 245, 0.95); + -fx-background-color: rgba(8, 14, 26, 0.65); } -/* Search field. */ .market-search { - -fx-background-color: rgba(255, 255, 255, 0.9); - -fx-border-color: #bbbbbb; - -fx-border-radius: 12; - -fx-background-radius: 12; - -fx-padding: 7 14; - -fx-font-style: italic; + -fx-background-color: rgba(10, 15, 28, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.2); + -fx-border-radius: 10; + -fx-background-radius: 10; + -fx-padding: 8 16; -fx-font-size: 14; + -fx-text-fill: #f0f4ff; + -fx-prompt-text-fill: #5d6889; } .market-search:focused { - -fx-border-color: #333333; + -fx-border-color: rgba(0, 212, 255, 0.7); + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.25), 8, 0.3, 0, 0); } -/* Sort buttons (A-Z, price, change, owned). */ .market-filter-btn { - -fx-background-color: white; - -fx-border-color: #cccccc; - -fx-border-radius: 12; - -fx-background-radius: 12; - -fx-padding: 6 14; - -fx-font-style: italic; + -fx-background-color: rgba(20, 28, 46, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.18); + -fx-border-radius: 10; + -fx-background-radius: 10; + -fx-padding: 7 14; -fx-font-weight: bold; - -fx-font-size: 13; + -fx-font-size: 12px; + -fx-text-fill: #8b95b7; -fx-cursor: hand; - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.1), 2, 0, 0, 1); +} + +.market-filter-btn:hover { + -fx-background-color: rgba(0, 212, 255, 0.12); + -fx-border-color: rgba(0, 212, 255, 0.55); + -fx-text-fill: #f0f4ff; } .market-filter-btn.active { - -fx-background-color: #333333; - -fx-border-color: #333333; - -fx-text-fill: white; + -fx-background-color: rgba(0, 212, 255, 0.85); + -fx-border-color: #00d4ff; + -fx-text-fill: #07142a; } -/* Scroll area + tile pane around the cards. */ .market-scroll { -fx-background: transparent; -fx-background-color: transparent; @@ -606,41 +802,41 @@ -fx-background-color: transparent; } -/* Individual stock card. */ .market-stock-card { - -fx-background-color: rgba(255, 255, 255, 0.85); - -fx-background-radius: 14; - -fx-border-color: rgba(0, 0, 0, 0.12); - -fx-border-radius: 14; + -fx-background-color: rgba(15, 22, 38, 0.85); + -fx-background-radius: 12; + -fx-border-color: rgba(0, 212, 255, 0.15); + -fx-border-radius: 12; + -fx-border-width: 1; -fx-cursor: hand; } .market-stock-card:hover { - -fx-background-color: white; + -fx-background-color: rgba(20, 30, 50, 0.95); + -fx-border-color: rgba(0, 212, 255, 0.6); -fx-translate-y: -2; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.25), 12, 0.25, 0, 0); } .market-ticker { - -fx-font-style: italic; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-size: 22; - -fx-text-fill: black; + -fx-font-size: 22px; + -fx-text-fill: #f0f4ff; } .market-stock-name { - -fx-font-size: 11; - -fx-text-fill: #555555; - -fx-font-style: italic; + -fx-font-size: 11px; + -fx-text-fill: #8b95b7; } .market-price { - -fx-font-style: italic; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-size: 16; - -fx-text-fill: black; + -fx-font-size: 16px; + -fx-text-fill: #f0f4ff; } -/* Mini sparkline polyline. */ .market-mini-chart { -fx-stroke-width: 2.4; -fx-stroke-line-cap: round; @@ -648,134 +844,131 @@ } .market-mini-chart.up { - -fx-stroke: #27ae60; + -fx-stroke: #2ee59d; } .market-mini-chart.down { - -fx-stroke: #c0392b; + -fx-stroke: #ff5470; } -/* Change percentage badge (pill). */ .market-change { - -fx-font-style: italic; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-size: 13; + -fx-font-size: 12px; -fx-padding: 3 12; - -fx-background-radius: 10; - -fx-text-fill: white; + -fx-background-radius: 8; } .market-change.up { - -fx-background-color: #27ae60; + -fx-background-color: rgba(46, 229, 157, 0.18); + -fx-text-fill: #2ee59d; } .market-change.down { - -fx-background-color: #c0392b; + -fx-background-color: rgba(255, 84, 112, 0.18); + -fx-text-fill: #ff5470; } .market-owned-badge { - -fx-font-style: italic; - -fx-font-size: 11; - -fx-text-fill: #555555; + -fx-font-size: 11px; + -fx-text-fill: #4ad9ff; } -/* Empty-state label shown when no stocks match the search. */ .market-empty { -fx-font-style: italic; - -fx-text-fill: #555555; + -fx-text-fill: #8b95b7; -fx-padding: 40; } -/* ------------- STATS VIEW ------------- */ -/* Root pane fills the center area with a light translucent background. */ +/* ======================================================== + IN-GAME : STATS VIEW + ======================================================== */ + .stats-container { - -fx-background-color: rgba(245, 245, 245, 0.95); + -fx-background-color: rgba(8, 14, 26, 0.65); } -/* Generic panel (chart, allocation, holdings). */ .stats-panel { - -fx-background-color: rgba(255, 255, 255, 0.75); - -fx-background-radius: 14; - -fx-border-color: rgba(0, 0, 0, 0.12); - -fx-border-radius: 14; - -fx-padding: 10 14; + -fx-background-color: rgba(15, 22, 38, 0.78); + -fx-background-radius: 12; + -fx-border-color: rgba(0, 212, 255, 0.15); + -fx-border-radius: 12; + -fx-border-width: 1; + -fx-padding: 12 16; } .stats-panel-title { - -fx-font-style: italic; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-size: 14; - -fx-text-fill: #333333; - -fx-border-color: transparent transparent rgba(0, 0, 0, 0.15) transparent; + -fx-font-size: 12px; + -fx-text-fill: #4ad9ff; + -fx-border-color: transparent transparent rgba(0, 212, 255, 0.15) transparent; -fx-border-width: 0 0 1 0; - -fx-padding: 0 0 4 0; + -fx-padding: 0 0 6 0; } -/* KPI tiles in the top strip. */ .stats-kpi { - -fx-background-color: rgba(255, 255, 255, 0.75); - -fx-background-radius: 14; - -fx-border-color: rgba(0, 0, 0, 0.12); - -fx-border-radius: 14; - -fx-padding: 8 12; + -fx-background-color: rgba(15, 22, 38, 0.78); + -fx-background-radius: 12; + -fx-border-color: rgba(0, 212, 255, 0.15); + -fx-border-radius: 12; + -fx-border-width: 1; + -fx-padding: 10 14; } .stats-kpi-label { - -fx-font-style: italic; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-size: 11; - -fx-text-fill: #555555; + -fx-font-size: 11px; + -fx-text-fill: #8b95b7; } .stats-kpi-value { - -fx-font-style: italic; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-size: 20; - -fx-text-fill: black; + -fx-font-size: 22px; + -fx-text-fill: #f0f4ff; } .stats-kpi-value.up { - -fx-text-fill: #27ae60; + -fx-text-fill: #2ee59d; } .stats-kpi-value.down { - -fx-text-fill: #c0392b; + -fx-text-fill: #ff5470; } .stats-kpi-sub { - -fx-font-style: italic; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-size: 11; - -fx-text-fill: #555555; + -fx-font-size: 11px; + -fx-text-fill: #8b95b7; } .stats-kpi-sub.up { - -fx-text-fill: #27ae60; + -fx-text-fill: #2ee59d; } .stats-kpi-sub.down { - -fx-text-fill: #c0392b; + -fx-text-fill: #ff5470; } -/* Balance-over-time chart axis labels. */ .stats-chart-axis { - -fx-font-size: 9; - -fx-font-style: italic; - -fx-fill: #555555; + -fx-font-size: 9px; + -fx-fill: #8b95b7; } -/* Allocation legend rows. */ .stats-legend-label { - -fx-font-style: italic; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-size: 12; - -fx-text-fill: black; + -fx-font-size: 12px; + -fx-text-fill: #f0f4ff; } .stats-legend-pct { - -fx-font-style: italic; - -fx-font-size: 12; - -fx-text-fill: #555555; + -fx-font-family: "Consolas, Menlo, monospace"; + -fx-font-size: 12px; + -fx-text-fill: #8b95b7; } .stats-legend-scroll, @@ -790,116 +983,142 @@ -fx-background-color: transparent; } -/* A single row in the holdings list. */ .stats-holding { - -fx-background-color: rgba(255, 255, 255, 0.6); - -fx-background-radius: 10; - -fx-padding: 6 8; + -fx-background-color: rgba(20, 28, 46, 0.78); + -fx-background-radius: 8; + -fx-border-color: rgba(0, 212, 255, 0.1); + -fx-border-radius: 8; + -fx-border-width: 1; + -fx-padding: 8 10; } .stats-holding-ticker { - -fx-font-style: italic; + -fx-font-family: "Aptos"; -fx-font-weight: bold; - -fx-font-size: 16; - -fx-text-fill: black; + -fx-font-size: 15px; + -fx-text-fill: #f0f4ff; } .stats-holding-shares { - -fx-font-style: italic; - -fx-font-size: 11; - -fx-text-fill: #555555; + -fx-font-size: 11px; + -fx-text-fill: #8b95b7; } .stats-holding-value { - -fx-font-style: italic; + -fx-font-family: "Consolas, Menlo, monospace"; -fx-font-weight: bold; - -fx-font-size: 13; - -fx-text-fill: black; + -fx-font-size: 13px; + -fx-text-fill: #f0f4ff; } .stats-holding-pnl { - -fx-font-style: italic; - -fx-font-size: 12; - -fx-padding: 2 8; - -fx-background-radius: 8; - -fx-text-fill: white; + -fx-font-family: "Consolas, Menlo, monospace"; + -fx-font-weight: bold; + -fx-font-size: 11px; + -fx-padding: 3 10; + -fx-background-radius: 6; } .stats-holding-pnl.up { - -fx-background-color: #27ae60; + -fx-background-color: rgba(46, 229, 157, 0.18); + -fx-text-fill: #2ee59d; } .stats-holding-pnl.down { - -fx-background-color: #c0392b; + -fx-background-color: rgba(255, 84, 112, 0.18); + -fx-text-fill: #ff5470; } -/* Empty-state label shown when there are no holdings. */ .stats-empty { -fx-font-style: italic; - -fx-text-fill: #555555; + -fx-text-fill: #8b95b7; -fx-padding: 20; } -/* ---------------- TRANSACTIONS VIEW ---------------- */ +/* ======================================================== + IN-GAME : TRANSACTIONS VIEW + ======================================================== */ + .transactions-root { -fx-spacing: 20; - -fx-padding: 15; + -fx-padding: 20; -fx-alignment: TOP_CENTER; + -fx-background-color: rgba(8, 14, 26, 0.65); } .transactions-root .label { - -fx-text-fill: black; + -fx-text-fill: #f0f4ff; } .transactions-searchBar { - -fx-spacing: 10; + -fx-spacing: 12; -fx-alignment: CENTER_LEFT; - -fx-border-color: #000000; - -fx-border-width: 1.5; - -fx-background-color: #E0E0E0; - -fx-padding: 10; + -fx-background-color: rgba(15, 22, 38, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.18); + -fx-border-width: 1; + -fx-background-radius: 10; + -fx-border-radius: 10; + -fx-padding: 12 16; } .transactions-searchLabel { - -fx-font-size: 14; + -fx-font-size: 13px; + -fx-font-weight: bold; + -fx-text-fill: #8b95b7; } .transactions-searchField { - -fx-background-color: white; - -fx-border-color: #CCCCCC; + -fx-background-color: rgba(10, 15, 28, 0.7); + -fx-border-color: rgba(0, 212, 255, 0.2); + -fx-border-radius: 8; + -fx-background-radius: 8; + -fx-text-fill: #f0f4ff; + -fx-prompt-text-fill: #5d6889; + -fx-padding: 6 10; +} + +.transactions-searchField:focused { + -fx-border-color: rgba(0, 212, 255, 0.7); } .transactions-weekField { - -fx-pref-width: 75px; - -fx-min-width: 75px; - -fx-background-color: white; - -fx-border-color: #000000; - -fx-border-width: 1.5px; + -fx-pref-width: 80px; + -fx-min-width: 80px; + -fx-background-color: rgba(10, 15, 28, 0.7); + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-width: 1px; + -fx-background-radius: 8; + -fx-border-radius: 8; -fx-alignment: CENTER; } .transactions-weekField .list-cell { - -fx-text-fill: black; + -fx-text-fill: #f0f4ff; -fx-font-weight: bold; -fx-alignment: center; } +.transactions-weekField .arrow { + -fx-background-color: #4ad9ff; +} + .transactions-transactionCard { - -fx-spacing: 15; - -fx-padding: 25; + -fx-spacing: 14; + -fx-padding: 22; -fx-alignment: TOP_CENTER; -fx-pref-width: 260; -fx-pref-height: 320; - -fx-background-color: #D6D6D6; - -fx-background-radius: 35; - -fx-border-color: #000000; - -fx-border-radius: 35; - -fx-border-width: 1.5; + -fx-background-color: rgba(15, 22, 38, 0.85); + -fx-background-radius: 14; + -fx-border-color: rgba(0, 212, 255, 0.2); + -fx-border-radius: 14; + -fx-border-width: 1.2; } .transactions-typeLabel { - -fx-font-size: 28; + -fx-font-size: 24px; -fx-font-weight: bold; + -fx-text-fill: #f0f4ff; } .transactions-infoBox { @@ -908,11 +1127,13 @@ } .transactions-cardText { - -fx-font-size: 14; + -fx-font-family: "Consolas, Menlo, monospace"; + -fx-font-size: 13px; + -fx-text-fill: #f0f4ff; } .transactions-cardsContainer { - -fx-spacing: 25; + -fx-spacing: 18; -fx-alignment: CENTER_LEFT; -fx-padding: 10; } @@ -922,12 +1143,15 @@ -fx-background: transparent; -fx-background-color: transparent; } -/* -----------------------------------------------*/ -/* ------------------- MINIGAMES -----------------*/ + +/* ======================================================== + IN-GAME : MINIGAMES + ======================================================== */ + .minigames-root { -fx-padding: 30px; - -fx-background-color: #e0e0e0; - -fx-spacing: 40px; + -fx-background-color: rgba(8, 14, 26, 0.65); + -fx-spacing: 36px; } .minigames-headerBar { @@ -937,63 +1161,80 @@ .minigames-stockSelectionRow { -fx-alignment: CENTER_LEFT; + -fx-spacing: 12; } .minigames-titleLabel { - -fx-font-size: 48px; + -fx-font-size: 42px; -fx-font-family: "Aptos", "Segoe UI", sans-serif; - -fx-text-fill: #000000; + -fx-font-weight: bold; + -fx-text-fill: #f0f4ff; } .minigames-stockLabel { - -fx-font-size: 24px; - -fx-text-fill: #000000; + -fx-font-size: 18px; + -fx-font-weight: bold; + -fx-text-fill: #8b95b7; } .minigames-stockValue { - -fx-font-size: 24px; - -fx-text-fill: #000000; - -fx-border-color: #000000; - -fx-border-width: 1.5px; - -fx-padding: 2px 10px; - -fx-background-color: #d8d8d8; + -fx-font-family: "Consolas, Menlo, monospace"; + -fx-font-size: 18px; + -fx-font-weight: bold; + -fx-text-fill: #4ad9ff; + -fx-background-color: rgba(15, 22, 38, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-width: 1px; + -fx-background-radius: 8; + -fx-border-radius: 8; + -fx-padding: 6 14; } .minigames-helpBtn { - -fx-font-size: 28px; - -fx-pref-width: 50px; - -fx-pref-height: 50px; - -fx-background-color: #d8d8d8; - -fx-border-color: #000000; - -fx-border-width: 1.5px; - -fx-text-fill: #000000; + -fx-font-size: 22px; + -fx-font-weight: bold; + -fx-pref-width: 44px; + -fx-pref-height: 44px; + -fx-background-color: rgba(15, 22, 38, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-width: 1px; + -fx-background-radius: 22px; + -fx-border-radius: 22px; + -fx-text-fill: #f0f4ff; + -fx-cursor: hand; } .minigames-container { -fx-alignment: CENTER; - -fx-spacing: 30px; + -fx-spacing: 24px; -fx-padding: 10px 0px; } .minigames-cardBtn { -fx-alignment: CENTER; - -fx-background-color: #d8d8d8; - -fx-border-color: #000000; + -fx-background-color: rgba(15, 22, 38, 0.85); + -fx-border-color: rgba(0, 212, 255, 0.2); -fx-border-width: 1.5px; - -fx-font-size: 32px; - -fx-text-fill: #000000; + -fx-background-radius: 14px; + -fx-border-radius: 14px; + -fx-font-size: 26px; + -fx-font-weight: bold; + -fx-text-fill: #f0f4ff; -fx-text-alignment: center; -fx-pref-height: 250px; -fx-min-height: 100px; -fx-max-width: 350px; + -fx-cursor: hand; } .minigames-cardBtn:hover, .minigames-helpBtn:hover { - -fx-background-color: #c0c0c0; + -fx-background-color: rgba(0, 212, 255, 0.12); + -fx-border-color: rgba(0, 212, 255, 0.6); + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.3), 16, 0.3, 0, 0); } .minigames-help-overlay-dimmer { - -fx-background-color: rgba(0, 0, 0, 0.6); + -fx-background-color: rgba(0, 0, 0, 0.72); -fx-alignment: center; } @@ -1003,17 +1244,17 @@ -fx-max-height: 500px; -fx-pref-width: 700px; -fx-pref-height: 500px; - -fx-background-color: #ffffff; - -fx-border-color: #333333; - -fx-border-width: 2px; - -fx-border-radius: 5px; - -fx-background-radius: 5px; + -fx-background-color: rgba(15, 22, 38, 0.98); + -fx-border-color: rgba(0, 212, 255, 0.35); + -fx-border-width: 1.5px; + -fx-border-radius: 12px; + -fx-background-radius: 12px; } .minigames-help-text-vbox { -fx-spacing: 20px; -fx-alignment: TOP_LEFT; - -fx-padding: 20px, 20px, 20px,20px; + -fx-padding: 20px; -fx-background-color: transparent; } @@ -1024,17 +1265,21 @@ } .minigames-help-closeBtn { - -fx-pref-width: 40px; - -fx-pref-height: 40px; - -fx-background-color: #333333; - -fx-text-fill: white; + -fx-pref-width: 36px; + -fx-pref-height: 36px; + -fx-background-color: rgba(0, 212, 255, 0.85); + -fx-text-fill: #07142a; -fx-font-weight: bold; - -fx-font-size: 18px; - -fx-background-radius: 20px; - -fx-border-radius: 20px; + -fx-font-size: 16px; + -fx-background-radius: 18px; + -fx-border-radius: 18px; -fx-cursor: hand; } +.minigames-help-closeBtn:hover { + -fx-background-color: #00e6ff; +} + .minigames-help-textflow { -fx-pref-width: 600; } @@ -1042,16 +1287,20 @@ .minigames-help-header { -fx-font-weight: bold; -fx-font-size: 20px; + -fx-fill: #4ad9ff; } .minigames-help-description { - -fx-font-size: 16px; + -fx-font-size: 14px; + -fx-fill: #f0f4ff; } -/* --------------------------------------------- */ -/* --------- MINIGAMES ENGINE CONTEXT ---------- */ +/* ======================================================== + IN-GAME : MINIGAMES ENGINE CONTEXT + ======================================================== */ + .gameEngine-root { - -fx-background-color: rgba(180, 180, 180, 0.85); + -fx-background-color: rgba(8, 14, 26, 0.85); } .gameEngine-topBar { @@ -1059,42 +1308,60 @@ } .gameEngine-topBar-Label { - -fx-font-size: 24px; - -fx-text-fill: black; + -fx-font-size: 22px; + -fx-font-weight: bold; + -fx-text-fill: #f0f4ff; } .gameEngine-report-box { - -fx-spacing: 25px; + -fx-spacing: 22px; -fx-alignment: CENTER; - -fx-background-color: #ffffff; - -fx-border-color: #000000; - -fx-border-width: 2px; - -fx-padding: 40px; + -fx-background-color: rgba(15, 22, 38, 0.98); + -fx-border-color: rgba(0, 212, 255, 0.35); + -fx-border-width: 1.5px; + -fx-padding: 36px; -fx-max-width: 500px; -fx-max-height: 350px; - -fx-background-radius: 5px; - -fx-border-radius: 5px; + -fx-background-radius: 12px; + -fx-border-radius: 12px; } .gameEngine-report-title { - -fx-font-size: 32px; + -fx-font-size: 30px; -fx-font-weight: bold; + -fx-text-fill: #f0f4ff; } .gameEngine-report-rank-result { - -fx-font-size: 24px; + -fx-font-size: 22px; + -fx-text-fill: #4ad9ff; } .gameEngine-report-effect { - -fx-font-size: 18px; + -fx-font-size: 16px; + -fx-text-fill: #8b95b7; } .gameEngine-report-closeButton { -fx-pref-width: 200; -fx-pref-height: 50; + -fx-background-color: rgba(0, 212, 255, 0.92); + -fx-text-fill: #07142a; + -fx-font-weight: bold; + -fx-font-size: 14px; + -fx-background-radius: 8; + -fx-cursor: hand; +} + +.gameEngine-report-closeButton:hover { + -fx-background-color: #00e6ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.5), 12, 0.3, 0, 0); } -/* ----------------------------------------------*/ -/* --------------- FIND STOCK GAME ------------- */ + +/* ======================================================== + IN-GAME : FIND-STOCK MINIGAME + ======================================================== */ + .find-stock-minigame-root { -fx-spacing: 15; -fx-alignment: CENTER; @@ -1105,8 +1372,11 @@ -fx-vgap: 15px; -fx-alignment: center; } -/*----------------------------------------------*/ -/*--------------- CLICKER GAME -----------------*/ + +/* ======================================================== + IN-GAME : CLICKER MINIGAME + ======================================================== */ + .clicker-minigame-root { -fx-spacing: 20; -fx-alignment: CENTER; @@ -1115,10 +1385,741 @@ .clicker-minigame-clickBtn { -fx-pref-width: 80; -fx-pref-height: 80; + -fx-background-color: rgba(0, 212, 255, 0.85); + -fx-text-fill: #07142a; + -fx-font-weight: bold; + -fx-background-radius: 40; + -fx-cursor: hand; } -/*--------------- TIMED INPUT GAME -------------*/ + +.clicker-minigame-clickBtn:hover { + -fx-background-color: #00e6ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.55), 14, 0.35, 0, 0); +} + +/* ======================================================== + IN-GAME : TIMED-INPUT MINIGAME + ======================================================== */ + .time-inputs-minigame-root { -fx-background-color: transparent; -fx-focus-traversable: true; } -/*-----------------------------------------------*/ \ No newline at end of file + +/* ======================================================== + IN-GAME : SETTINGS OVERLAY + ======================================================== + Modal-style settings panel that opens on top of the active + center widget when the Settings button on the top bar is + pressed. Dims the center widget behind it. */ + +.ingame-settings-overlay-dimmer { + -fx-background-color: rgba(0, 0, 0, 0.55); + -fx-alignment: center; +} + +.ingame-settings-panel { + -fx-background-color: rgba(15, 22, 38, 0.98); + -fx-background-radius: 14; + -fx-border-color: rgba(0, 212, 255, 0.35); + -fx-border-radius: 14; + -fx-border-width: 1.5; + -fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.55), 24, 0.3, 0, 6); +} + +.ingame-settings-title { + -fx-font-family: "Aptos"; + -fx-font-weight: bold; + -fx-font-size: 24px; + -fx-text-fill: #f0f4ff; +} + +.ingame-settings-section-label { + -fx-font-family: "Aptos"; + -fx-font-weight: bold; + -fx-font-size: 13px; + -fx-text-fill: #4ad9ff; +} + +.ingame-settings-description { + -fx-font-family: "Aptos"; + -fx-font-size: 12px; + -fx-text-fill: #8b95b7; +} + +.ingame-settings-toggle-button { + -fx-background-color: rgba(20, 28, 46, 0.85); + -fx-background-radius: 8; + -fx-border-color: rgba(0, 212, 255, 0.25); + -fx-border-radius: 8; + -fx-border-width: 1.2; + -fx-padding: 10 22; + -fx-font-family: "Aptos"; + -fx-font-weight: bold; + -fx-font-size: 13px; + -fx-text-fill: #f0f4ff; + -fx-cursor: hand; +} + +.ingame-settings-toggle-button:hover { + -fx-background-color: rgba(0, 212, 255, 0.12); + -fx-border-color: rgba(0, 212, 255, 0.6); +} + +.ingame-settings-toggle-button.active { + -fx-background-color: rgba(0, 212, 255, 0.85); + -fx-border-color: #00d4ff; + -fx-text-fill: #07142a; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.35), 10, 0.3, 0, 0); +} + +.ingame-settings-close-button { + -fx-pref-width: 36px; + -fx-pref-height: 36px; + -fx-background-color: rgba(0, 212, 255, 0.85); + -fx-text-fill: #07142a; + -fx-font-weight: bold; + -fx-font-size: 14px; + -fx-background-radius: 18px; + -fx-border-radius: 18px; + -fx-cursor: hand; +} + +.ingame-settings-close-button:hover { + -fx-background-color: #00e6ff; + -fx-effect: dropshadow(gaussian, rgba(0, 212, 255, 0.45), 10, 0.3, 0, 0); +} + +/* ======================================================== + LIGHT MODE + ======================================================== + Activated by adding the ".light-mode" style class to the + scene root (handled by ThemeManager). + + Strategy: every visible surface, text color, border and + accent that exists in the dark theme above is overridden + here. We intentionally keep the same layout/spacing and + only change colors so the application feels identical + structurally - just bright. + + Light palette: + accent-blue #0a84d9 primary interactive highlight + accent-blue-soft #3aa0e5 softer blue for borders + surface #ffffff panels + surface-soft #f4f7fc nested panels / rows + surface-row #fbfcfe table rows + surface-row-hover #e6effa hover state + text-primary #0f1b34 + text-secondary #5b6b8a + text-muted #8a96b3 + positive #1d8a5f + negative #c8334e + ======================================================== */ + +/* ---------- BACKGROUNDS ---------- */ +.light-mode .main-menu-bg { + -fx-background-color: + radial-gradient(center 50% 0%, radius 80%, + rgba(10, 132, 217, 0.10) 0%, + transparent 65%), + radial-gradient(center 90% 100%, radius 70%, + rgba(29, 138, 95, 0.06) 0%, + transparent 60%), + linear-gradient(to bottom right, + #f4f7fc 0%, + #e8eef7 50%, + #eef2fa 100%); +} + +.light-mode .in-game-root { + -fx-background-color: + radial-gradient(center 50% 0%, radius 60%, + rgba(10, 132, 217, 0.08) 0%, + transparent 70%), + linear-gradient(to bottom, + #f4f7fc 0%, + #e8eef7 100%); +} + +/* ---------- MAIN MENU ---------- */ +.light-mode .title-text { + -fx-fill: #0f1b34; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.25), 18, 0.18, 0, 0); +} + +.light-mode .title-subtitle { + -fx-fill: #0a84d9; +} + +.light-mode .menu-footer { + -fx-fill: #8a96b3; +} + +.light-mode .menu-button { + -fx-background-color: + rgba(255, 255, 255, 0.95), + linear-gradient(to bottom, + rgba(10, 132, 217, 0.02), + rgba(255, 255, 255, 0)); + -fx-border-color: rgba(10, 132, 217, 0.35); + -fx-text-fill: #0f1b34; +} + +.light-mode .menu-button:hover { + -fx-background-color: + rgba(10, 132, 217, 0.10), + linear-gradient(to bottom, + rgba(255, 255, 255, 0.4), + rgba(255, 255, 255, 0)); + -fx-border-color: #0a84d9; + -fx-text-fill: #0f1b34; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.35), 12, 0.25, 0, 0); +} + +.light-mode .menu-button:pressed { + -fx-background-color: rgba(10, 132, 217, 0.22); +} + +/* ---------- PLAY GAME ---------- */ +.light-mode .play-game-title { -fx-fill: #0f1b34; } +.light-mode .play-game-subtitle { -fx-fill: #5b6b8a; } +.light-mode .play-game-empty { -fx-text-fill: #5b6b8a; } + +.light-mode .save-list { + -fx-background-color: rgba(255, 255, 255, 0.95); + -fx-border-color: rgba(10, 132, 217, 0.35); +} + +.light-mode .save-row { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.12); +} + +.light-mode .save-row:hover { + -fx-background-color: #e6effa; + -fx-border-color: rgba(10, 132, 217, 0.55); + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.18), 10, 0.2, 0, 0); +} + +.light-mode .save-name { -fx-fill: #0f1b34; } +.light-mode .save-balance-positive { -fx-fill: #1d8a5f; } +.light-mode .save-balance-negative { -fx-fill: #c8334e; } + +/* ---------- SETTINGS (main menu version) ---------- */ +.light-mode .settings-panel { + -fx-background-color: rgba(255, 255, 255, 0.97); + -fx-border-color: rgba(10, 132, 217, 0.4); +} + +.light-mode .settings-tab-button { + -fx-text-fill: #5b6b8a; +} + +.light-mode .settings-tab-button:hover { + -fx-text-fill: #0f1b34; + -fx-background-color: rgba(10, 132, 217, 0.10); + -fx-border-color: rgba(10, 132, 217, 0.45); +} + +.light-mode .settings-title { -fx-text-fill: #0f1b34; } +.light-mode .settings-placeholder { -fx-text-fill: #5b6b8a; } + +.light-mode .settings-slider .thumb { + -fx-background-color: #0a84d9; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.45), 8, 0.4, 0, 0); +} + +.light-mode .settings-slider .track { + -fx-background-color: rgba(10, 27, 52, 0.18); +} + +/* ---------- CREATE GAME ---------- */ +.light-mode .create-game-panel { + -fx-background-color: rgba(255, 255, 255, 0.97); + -fx-border-color: rgba(10, 132, 217, 0.4); +} + +.light-mode .create-game-title { -fx-fill: #0f1b34; } +.light-mode .create-game-label { -fx-text-fill: #5b6b8a; } + +.light-mode .create-game-input { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.35); + -fx-text-fill: #0f1b34; + -fx-prompt-text-fill: #8a96b3; +} + +.light-mode .create-game-input:focused { + -fx-border-color: #0a84d9; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.28), 8, 0.3, 0, 0); +} + +.light-mode .create-game-input.choice-box .label { -fx-text-fill: #0f1b34; } +.light-mode .create-game-input.choice-box .arrow { -fx-background-color: #0a84d9; } + +.light-mode .create-game-input.choice-box .context-menu { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.4); +} + +.light-mode .create-game-input.choice-box .menu-item .label { + -fx-text-fill: #0f1b34; +} + +.light-mode .create-game-input.choice-box .menu-item:focused { + -fx-background-color: rgba(10, 132, 217, 0.18); +} + +.light-mode .create-game-selection-label { -fx-text-fill: #5b6b8a; } + +.light-mode .create-game-stock-button { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.35); + -fx-text-fill: #0f1b34; +} + +.light-mode .create-game-stock-button:hover { + -fx-background-color: rgba(10, 132, 217, 0.10); + -fx-border-color: #0a84d9; +} + +.light-mode .create-game-stock-button.active { + -fx-background-color: rgba(10, 132, 217, 0.18); + -fx-border-color: #0a84d9; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.35), 10, 0.3, 0, 0); +} + +.light-mode .create-game-cancel-button { + -fx-background-color: rgba(10, 27, 52, 0.06); + -fx-border-color: rgba(10, 27, 52, 0.22); + -fx-text-fill: #0f1b34; +} + +.light-mode .create-game-cancel-button:hover { + -fx-background-color: rgba(10, 27, 52, 0.12); + -fx-border-color: rgba(10, 27, 52, 0.38); +} + +.light-mode .create-game-create-button.create-game-button-disabled { + -fx-background-color: rgba(180, 190, 210, 0.45); + -fx-border-color: rgba(10, 27, 52, 0.08); + -fx-text-fill: rgba(15, 27, 52, 0.4); +} + +.light-mode .create-game-create-button.create-game-button-enabled { + -fx-background-color: #0a84d9; + -fx-border-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .create-game-create-button.create-game-button-enabled:hover { + -fx-background-color: #1296ec; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.5), 14, 0.3, 0, 0); +} + +/* ---------- IN-GAME : TOP BAR ---------- */ +.light-mode .top-bar { + -fx-background-color: rgba(255, 255, 255, 0.92); + -fx-border-color: transparent transparent rgba(10, 132, 217, 0.35) transparent; +} + +.light-mode .top-bar-menu-button { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.3); + -fx-text-fill: #0f1b34; +} + +.light-mode .top-bar-menu-button:hover { + -fx-background-color: rgba(10, 132, 217, 0.12); + -fx-border-color: #0a84d9; + -fx-text-fill: #0f1b34; +} + +/* ---------- IN-GAME : SUMMARY ---------- */ +.light-mode .summary-container { + -fx-border-color: rgba(10, 132, 217, 0.35); +} + +.light-mode .balance-title { -fx-text-fill: #5b6b8a; } +.light-mode .balance-value { -fx-text-fill: #0f1b34; } + +.light-mode .axis { + -fx-tick-label-fill: #5b6b8a; +} + +.light-mode .axis:bottom { + -fx-border-color: rgba(10, 27, 52, 0.15) transparent transparent transparent; +} + +.light-mode .chart-series-line { + -fx-stroke: #1d8a5f; +} + +.light-mode .next-button { + -fx-background-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .next-button:hover { + -fx-background-color: #1296ec; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.5), 12, 0.3, 0, 0); +} + +/* ---------- IN-GAME : DASHBOARD ---------- */ +.light-mode .dashboard-complete-sidebar { + -fx-background-color: rgba(255, 255, 255, 0.85); + -fx-border-color: transparent rgba(10, 132, 217, 0.25) transparent transparent; +} + +.light-mode .dashboard-stock-button { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.18); + -fx-text-fill: #0f1b34; +} + +.light-mode .dashboard-stock-button:hover { + -fx-background-color: rgba(10, 132, 217, 0.10); + -fx-border-color: #0a84d9; +} + +.light-mode .dashboard-selected-stock-pill { + -fx-background-color: rgba(255, 255, 255, 0.95); + -fx-border-color: rgba(10, 132, 217, 0.45); + -fx-text-fill: #0f1b34; +} + +.light-mode .dashboard-buy-button { + -fx-background-color: #1d8a5f; + -fx-text-fill: #ffffff; +} + +.light-mode .dashboard-buy-button:hover { + -fx-effect: dropshadow(gaussian, rgba(29, 138, 95, 0.5), 14, 0.3, 0, 0); +} + +.light-mode .dashboard-sell-button { + -fx-background-color: #c8334e; + -fx-text-fill: #ffffff; +} + +.light-mode .dashboard-sell-button:hover { + -fx-effect: dropshadow(gaussian, rgba(200, 51, 78, 0.5), 14, 0.3, 0, 0); +} + +.light-mode .dashboard-qtyBtn { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.35); + -fx-text-fill: #0f1b34; +} + +.light-mode .dashboard-qtyBtn:hover { + -fx-background-color: rgba(10, 132, 217, 0.18); + -fx-border-color: #0a84d9; +} + +.light-mode .dashboard-qtyTextField { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.35); + -fx-text-fill: #0f1b34; +} + +.light-mode .dashboard-qtyTextField:focused { + -fx-border-color: #0a84d9; +} + +.light-mode .dashboard-combo-box { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.35); +} + +.light-mode .dashboard-combo-box .list-cell { -fx-text-fill: #0f1b34; } +.light-mode .dashboard-combo-box .arrow { -fx-background-color: #0a84d9; } + +/* ---------- IN-GAME : MARKET ---------- */ +.light-mode .market-container { + -fx-background-color: rgba(244, 247, 252, 0.65); +} + +.light-mode .market-search { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.3); + -fx-text-fill: #0f1b34; + -fx-prompt-text-fill: #8a96b3; +} + +.light-mode .market-search:focused { + -fx-border-color: #0a84d9; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.25), 8, 0.3, 0, 0); +} + +.light-mode .market-filter-btn { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.25); + -fx-text-fill: #5b6b8a; +} + +.light-mode .market-filter-btn:hover { + -fx-background-color: rgba(10, 132, 217, 0.10); + -fx-border-color: #0a84d9; + -fx-text-fill: #0f1b34; +} + +.light-mode .market-filter-btn.active { + -fx-background-color: #0a84d9; + -fx-border-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .market-stock-card { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.2); +} + +.light-mode .market-stock-card:hover { + -fx-background-color: #f4f9ff; + -fx-border-color: #0a84d9; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.25), 12, 0.25, 0, 0); +} + +.light-mode .market-ticker { -fx-text-fill: #0f1b34; } +.light-mode .market-stock-name { -fx-text-fill: #5b6b8a; } +.light-mode .market-price { -fx-text-fill: #0f1b34; } + +.light-mode .market-mini-chart.up { -fx-stroke: #1d8a5f; } +.light-mode .market-mini-chart.down { -fx-stroke: #c8334e; } + +.light-mode .market-change.up { + -fx-background-color: rgba(29, 138, 95, 0.15); + -fx-text-fill: #1d8a5f; +} + +.light-mode .market-change.down { + -fx-background-color: rgba(200, 51, 78, 0.15); + -fx-text-fill: #c8334e; +} + +.light-mode .market-owned-badge { -fx-text-fill: #0a84d9; } +.light-mode .market-empty { -fx-text-fill: #5b6b8a; } + +/* ---------- IN-GAME : STATS ---------- */ +.light-mode .stats-container { + -fx-background-color: rgba(244, 247, 252, 0.65); +} + +.light-mode .stats-panel { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.22); +} + +.light-mode .stats-panel-title { + -fx-text-fill: #0a84d9; + -fx-border-color: transparent transparent rgba(10, 132, 217, 0.22) transparent; +} + +.light-mode .stats-kpi { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.22); +} + +.light-mode .stats-kpi-label { -fx-text-fill: #5b6b8a; } +.light-mode .stats-kpi-value { -fx-text-fill: #0f1b34; } +.light-mode .stats-kpi-value.up { -fx-text-fill: #1d8a5f; } +.light-mode .stats-kpi-value.down { -fx-text-fill: #c8334e; } +.light-mode .stats-kpi-sub { -fx-text-fill: #5b6b8a; } +.light-mode .stats-kpi-sub.up { -fx-text-fill: #1d8a5f; } +.light-mode .stats-kpi-sub.down { -fx-text-fill: #c8334e; } + +.light-mode .stats-chart-axis { -fx-fill: #5b6b8a; } +.light-mode .stats-legend-label { -fx-text-fill: #0f1b34; } +.light-mode .stats-legend-pct { -fx-text-fill: #5b6b8a; } + +.light-mode .stats-holding { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.15); +} + +.light-mode .stats-holding-ticker { -fx-text-fill: #0f1b34; } +.light-mode .stats-holding-shares { -fx-text-fill: #5b6b8a; } +.light-mode .stats-holding-value { -fx-text-fill: #0f1b34; } + +.light-mode .stats-holding-pnl.up { + -fx-background-color: rgba(29, 138, 95, 0.15); + -fx-text-fill: #1d8a5f; +} + +.light-mode .stats-holding-pnl.down { + -fx-background-color: rgba(200, 51, 78, 0.15); + -fx-text-fill: #c8334e; +} + +.light-mode .stats-empty { -fx-text-fill: #5b6b8a; } + +/* ---------- IN-GAME : TRANSACTIONS ---------- */ +.light-mode .transactions-root { + -fx-background-color: rgba(244, 247, 252, 0.65); +} + +.light-mode .transactions-root .label { -fx-text-fill: #0f1b34; } + +.light-mode .transactions-searchBar { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.3); +} + +.light-mode .transactions-searchLabel { -fx-text-fill: #5b6b8a; } + +.light-mode .transactions-searchField { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.3); + -fx-text-fill: #0f1b34; + -fx-prompt-text-fill: #8a96b3; +} + +.light-mode .transactions-weekField { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.3); +} + +.light-mode .transactions-weekField .list-cell { -fx-text-fill: #0f1b34; } +.light-mode .transactions-weekField .arrow { -fx-background-color: #0a84d9; } + +.light-mode .transactions-transactionCard { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.25); +} + +.light-mode .transactions-typeLabel { -fx-text-fill: #0f1b34; } +.light-mode .transactions-cardText { -fx-text-fill: #0f1b34; } + +/* ---------- IN-GAME : MINIGAMES ---------- */ +.light-mode .minigames-root { + -fx-background-color: rgba(244, 247, 252, 0.7); +} + +.light-mode .minigames-titleLabel { -fx-text-fill: #0f1b34; } +.light-mode .minigames-stockLabel { -fx-text-fill: #5b6b8a; } + +.light-mode .minigames-stockValue { + -fx-text-fill: #0a84d9; + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.3); +} + +.light-mode .minigames-helpBtn { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.3); + -fx-text-fill: #0f1b34; +} + +.light-mode .minigames-cardBtn { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.25); + -fx-text-fill: #0f1b34; +} + +.light-mode .minigames-cardBtn:hover, +.light-mode .minigames-helpBtn:hover { + -fx-background-color: rgba(10, 132, 217, 0.10); + -fx-border-color: #0a84d9; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.3), 16, 0.3, 0, 0); +} + +.light-mode .minigames-help-overlay-dimmer { + -fx-background-color: rgba(10, 27, 52, 0.45); +} + +.light-mode .minigames-help-container { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.4); +} + +.light-mode .minigames-help-closeBtn { + -fx-background-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .minigames-help-closeBtn:hover { + -fx-background-color: #1296ec; +} + +.light-mode .minigames-help-header { -fx-fill: #0a84d9; } +.light-mode .minigames-help-description { -fx-fill: #0f1b34; } + +/* ---------- IN-GAME : MINIGAMES ENGINE / REPORT ---------- */ +.light-mode .gameEngine-root { + -fx-background-color: rgba(244, 247, 252, 0.85); +} + +.light-mode .gameEngine-topBar-Label { -fx-text-fill: #0f1b34; } + +.light-mode .gameEngine-report-box { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.4); +} + +.light-mode .gameEngine-report-title { -fx-text-fill: #0f1b34; } +.light-mode .gameEngine-report-rank-result { -fx-text-fill: #0a84d9; } +.light-mode .gameEngine-report-effect { -fx-text-fill: #5b6b8a; } + +.light-mode .gameEngine-report-closeButton { + -fx-background-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .gameEngine-report-closeButton:hover { + -fx-background-color: #1296ec; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.5), 12, 0.3, 0, 0); +} + +.light-mode .clicker-minigame-clickBtn { + -fx-background-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .clicker-minigame-clickBtn:hover { + -fx-background-color: #1296ec; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.55), 14, 0.35, 0, 0); +} + +/* ---------- IN-GAME : SETTINGS OVERLAY ---------- */ +.light-mode .ingame-settings-overlay-dimmer { + -fx-background-color: rgba(10, 27, 52, 0.35); +} + +.light-mode .ingame-settings-panel { + -fx-background-color: #ffffff; + -fx-border-color: rgba(10, 132, 217, 0.4); + -fx-effect: dropshadow(gaussian, rgba(10, 27, 52, 0.25), 24, 0.3, 0, 6); +} + +.light-mode .ingame-settings-title { -fx-text-fill: #0f1b34; } +.light-mode .ingame-settings-section-label { -fx-text-fill: #0a84d9; } +.light-mode .ingame-settings-description { -fx-text-fill: #5b6b8a; } + +.light-mode .ingame-settings-toggle-button { + -fx-background-color: #fbfcfe; + -fx-border-color: rgba(10, 132, 217, 0.35); + -fx-text-fill: #0f1b34; +} + +.light-mode .ingame-settings-toggle-button:hover { + -fx-background-color: rgba(10, 132, 217, 0.10); + -fx-border-color: #0a84d9; +} + +.light-mode .ingame-settings-toggle-button.active { + -fx-background-color: #0a84d9; + -fx-border-color: #0a84d9; + -fx-text-fill: #ffffff; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.35), 10, 0.3, 0, 0); +} + +.light-mode .ingame-settings-close-button { + -fx-background-color: #0a84d9; + -fx-text-fill: #ffffff; +} + +.light-mode .ingame-settings-close-button:hover { + -fx-background-color: #1296ec; + -fx-effect: dropshadow(gaussian, rgba(10, 132, 217, 0.45), 10, 0.3, 0, 0); +}