# Eternity Roundcube Skin `Eternity` is a sharp editorial skin for Roundcube, built in the visual language of Eternity Project: paper-white surfaces, ink-black structure, acid-green actions, and orange signals. It extends Roundcube's maintained Elastic skin, retaining Elastic's responsive layout and interaction model while changing the visual treatment. ## Requirements - Roundcube 1.6.x - The bundled `elastic` skin must remain installed - A web server able to serve static CSS files from Roundcube's `skins` directory The skin has no build step and no PHP dependencies. Its font stacks use `Space Grotesk` and `DM Mono` when those fonts are available, then fall back to locally installed system fonts. This keeps the login screen usable without a third-party font request. ## Install 1. Copy the `eternity` directory into the Roundcube installation's `skins` directory: ```sh cp -R eternity /var/www/roundcube/skins/ ``` 2. Ensure the web-server user can read the copied files: ```sh chown -R www-data:www-data /var/www/roundcube/skins/eternity find /var/www/roundcube/skins/eternity -type d -exec chmod 755 {} \; find /var/www/roundcube/skins/eternity -type f -exec chmod 644 {} \; ``` 3. Set the default skin in Roundcube's configuration. Add or update this line in `config/config.inc.php`: ```php $config['skin'] = 'eternity'; ``` 4. Clear the browser cache, then load Roundcube. The login view, mailbox list, compose view, menus, controls, and status messages should all use the new palette. ## Docker Install ### Docker Compose (persistent) Place this repository alongside the Compose file, then bind-mount the skin into the Roundcube service. The official `roundcube/roundcubemail` image exposes its application at `/var/www/html`. ```yaml services: roundcube: volumes: - ./ep-roundcube-skin/eternity:/var/www/html/skins/eternity:ro - ./roundcube-config/config.inc.php:/var/roundcube/config/config.inc.php:ro ``` Create `./roundcube-config/config.inc.php` if it does not already exist and include the skin setting with the rest of the deployment configuration: ```php /dev/null'` to identify the active configuration file. Restart the service after changing either mount: ```sh docker compose up -d --force-recreate roundcube ``` ### Existing Running Container Use this method to test the skin on a container that is already running. Replace `roundcube` with the container name or ID shown by `docker ps`. 1. Copy the skin from this repository into the container: ```sh docker cp ./eternity roundcube:/var/www/html/skins/eternity ``` 2. Confirm Roundcube can see the skin files: ```sh docker exec roundcube sh -c 'test -f /var/www/html/skins/eternity/meta.json && test -f /var/www/html/skins/eternity/styles/styles.css' ``` 3. Add `$config['skin'] = 'eternity';` to the active `config.inc.php` in the container, then restart it: ```sh docker restart roundcube ``` This live-container approach is not persistent: `docker compose up --force-recreate`, `docker rm`, or an image update removes the copied skin and in-container configuration change. Once the skin is confirmed, add the two bind mounts from the Compose example so both survive container recreation. After either deployment method, hard-refresh the browser or clear its cache. If the old appearance remains, inspect the browser network panel to confirm that `/skins/eternity/styles/styles.css` returns HTTP 200. If instead the page looks entirely unstyled — login credential fields stacked in the wrong place, an oversized logo, or mailbox toolbars/tabs scattered and hard to read — `styles/styles.css` is loading but its `@import` of `../../elastic/styles/styles.css` is not, so none of Elastic's layout rules apply. Confirm that file exists and is readable: ```sh docker exec roundcube sh -c 'test -f /var/www/html/skins/elastic/styles/styles.css && echo FOUND || echo MISSING' ``` If it is `MISSING`, the Elastic skin was installed from source without its LESS files being compiled (Elastic ships as `.less` sources and requires `make css-elastic` / `bin/updatecss.sh` to produce `styles/styles.css`). Reinstall Elastic from an official Roundcube release tarball, which ships the compiled CSS, rather than a bare git checkout. ### Verify A Running Container Run these commands on the Docker host, replacing `roundcube` with the container name or ID from `docker ps`. They distinguish an installation issue from an activation issue: ```sh docker exec roundcube sh -c 'for file in /var/www/html/skins/eternity/meta.json /var/www/html/skins/eternity/styles/styles.css /var/www/html/skins/elastic/styles/styles.css; do test -f "$file" && echo "FOUND $file" || echo "MISSING $file"; done' docker exec roundcube sh -c 'grep -RIn "\$config\[.skin.\]" /var/roundcube/config /var/www/html/config 2>/dev/null || true' ``` The first command must report all three paths as `FOUND`. The second must show `eternity` as the configured skin. On the official image, the equivalent persistent environment setting is: ```yaml environment: ROUNDCUBEMAIL_SKIN: eternity ``` Roundcube can store a skin preference for each user. A user who previously selected another appearance may continue to receive that preference instead of the newly configured default. Sign out and test in a private browser window or select **Eternity** from Roundcube's **Settings > Preferences > User Interface > Interface skin**, when the preference is available. For a browser-level check, open this URL directly, replacing the hostname with the Roundcube site: ```text https://webmail.example.com/skins/eternity/styles/styles.css ``` It must return CSS beginning with `@import url("../../elastic/styles/styles.css");`. A `404` means the skin is not mounted at the path served by the container. If it returns `200` but Roundcube still looks unchanged, inspect the mailbox page source: it must include a stylesheet URL containing `/skins/eternity/styles/styles.css`. If it instead contains `/skins/elastic/`, the active configuration or the user's stored preference still selects Elastic. ## Structure ```text eternity/ meta.json Skin registration and Elastic inheritance styles/styles.css Visual overrides for Elastic ``` `styles/styles.css` imports Elastic before applying Eternity's overrides. Do not remove the import: the base skin provides the complete component layout and image assets. ## Customize The visual palette is declared at the top of `eternity/styles/styles.css`: | Token | Value | Role | | --- | --- | --- | | `--ink` | `#11212b` | Primary text, borders, and primary controls | | `--paper` | `#f1f1e9` | Page and surface background | | `--acid` | `#c7ef4b` | Primary hover, selection, and success state | | `--orange` | `#ff6b35` | Links, secondary hover, quota, and error signal | | `--line` | `#b9c5bc` | Quiet dividers | | `--muted` | `#59706b` | Secondary text | Change these variables to retheme the interface while preserving the semantic states. Test login, inbox, compose, contacts, settings, search, and mobile navigation after any update to Roundcube or Elastic. ## Upgrade Notes This is an Elastic child skin. When updating Roundcube, keep the `eternity` directory in place and confirm that the upstream Elastic stylesheet remains at `skins/elastic/styles/styles.css`. Recopy the skin after deployments that replace the whole Roundcube `skins` directory. The skin intentionally uses direct CSS selectors for stable Roundcube surfaces and CSS custom properties for broad Elastic integration. If a future Roundcube release renames markup, inspect that release's Elastic stylesheet and update the matching override selector here. ## License Licensed under the GNU Affero General Public License, version 3 or later. See [LICENSE](LICENSE).