← back to Wallpaperglossary
initial scaffold: wallpaperglossary.com trade jargon reference
0b3a596d5b05b9f28864269da0a9aa62025a80bb · 2026-05-07 16:46:15 -0700 · Steve Abrams
Files touched
A .gitignoreA package-lock.jsonA package.jsonA public/index.htmlA server.js
Diff
commit 0b3a596d5b05b9f28864269da0a9aa62025a80bb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu May 7 16:46:15 2026 -0700
initial scaffold: wallpaperglossary.com trade jargon reference
---
.gitignore | 7 +
package-lock.json | 842 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
package.json | 12 +
public/index.html | 538 ++++++++++++++++++++++++++++++++++
server.js | 14 +
5 files changed, 1413 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..08240ae
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+.env*
+tmp/
+*.log
+.DS_Store
+dist/
+build/
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..91b7475
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,842 @@
+{
+ "name": "wallpaperglossary",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "wallpaperglossary",
+ "version": "0.1.0",
+ "dependencies": {
+ "express": "^4.22.1"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+ "license": "MIT"
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.5",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz",
+ "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "~1.2.0",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "on-finished": "~2.4.1",
+ "qs": "~6.15.1",
+ "raw-body": "~2.5.3",
+ "type-is": "~1.6.18",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/qs": {
+ "version": "6.15.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
+ "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
+ "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "~1.20.3",
+ "content-disposition": "~0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "~0.7.1",
+ "cookie-signature": "~1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.3.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "~2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "~0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "~6.14.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "~0.19.0",
+ "serve-static": "~1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "~2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
+ "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "~2.0.2",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
+ "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
+ "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==",
+ "license": "MIT"
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
+ "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
+ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/send": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
+ "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.1",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "~2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "~2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/serve-static": {
+ "version": "1.16.3",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
+ "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "~0.19.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "license": "MIT",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2f86b58
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "wallpaperglossary",
+ "version": "0.1.0",
+ "description": "Trade-jargon glossary for designers — wallpaperglossary.com",
+ "main": "server.js",
+ "scripts": {
+ "start": "node server.js"
+ },
+ "dependencies": {
+ "express": "^4.22.1"
+ }
+}
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..17dcbe7
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,538 @@
+<!DOCTYPE html>
+<html lang="en" data-theme="dark">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Wallpaper Glossary | Trade Terminology for Interior Designers | Designer Wallcoverings</title>
+<meta name="description" content="The definitive trade glossary for wallcovering professionals — 30+ terms from abrasion ratings to Type II specification. Free memo samples, trade accounts, and expert service at Designer Wallcoverings.">
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link href="https://fonts.googleapis.com/css2?family=Tenor+Sans&display=swap" rel="stylesheet">
+<script type="application/ld+json">
+{
+ "@context": "https://schema.org",
+ "@type": "WebSite",
+ "name": "Wallpaper Glossary",
+ "url": "https://wallpaperglossary.com",
+ "description": "Trade-jargon glossary of wallcovering terminology for interior design professionals",
+ "publisher": {
+ "@type": "Organization",
+ "name": "Designer Wallcoverings",
+ "url": "https://designerwallcoverings.com"
+ }
+}
+</script>
+<style>
+/* ===== THEME ===== */
+:root {
+ --bg: #0a0a0a;
+ --ink: #f5f1e8;
+ --ink-soft: rgba(245,241,232,0.72);
+ --ink-faint: rgba(245,241,232,0.38);
+ --line: rgba(245,241,232,0.10);
+ --card-bg: rgba(245,241,232,0.04);
+ --header-bg: rgba(10,10,10,0.92);
+ --accent: #8b1a3a;
+ --accent-light: #c4395a;
+ --accent-dim: rgba(139,26,58,0.22);
+ --accent-glow: rgba(139,26,58,0.32);
+ --rule: rgba(245,241,232,0.10);
+}
+[data-theme="light"] {
+ --bg: #f8f4f5;
+ --ink: #1a0810;
+ --ink-soft: rgba(26,8,16,0.72);
+ --ink-faint: rgba(26,8,16,0.38);
+ --line: rgba(26,8,16,0.10);
+ --card-bg: rgba(26,8,16,0.04);
+ --header-bg: rgba(248,244,245,0.92);
+ --accent: #8b1a3a;
+ --accent-light: #c4395a;
+}
+
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+html { scroll-behavior: smooth; }
+
+body {
+ background: var(--bg);
+ color: var(--ink);
+ font-family: 'Tenor Sans', -apple-system, system-ui, sans-serif;
+ line-height: 1.6;
+ transition: background 0.3s, color 0.3s;
+}
+
+/* ===== HEADER ===== */
+.header {
+ position: sticky; top: 0; z-index: 100;
+ background: var(--header-bg);
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+ border-bottom: 1px solid var(--line);
+ padding: 0 2rem; height: 64px;
+ display: flex; align-items: center; justify-content: space-between;
+}
+.header-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
+.brand-dot {
+ width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
+ background: radial-gradient(circle at 35% 35%, #c4395a 0%, #8b1a3a 60%, #4a0820 100%);
+ box-shadow: 0 0 0 1px var(--line), 0 2px 12px var(--accent-glow);
+}
+.brand-name {
+ font-family: 'Tenor Sans', system-ui, sans-serif;
+ font-size: 1.05rem; font-weight: 400; letter-spacing: 0.06em;
+ text-transform: uppercase; color: var(--ink);
+}
+.header-nav { display: flex; align-items: center; gap: 1.5rem; }
+.header-nav a {
+ color: var(--ink-soft); text-decoration: none; font-size: 0.8rem;
+ letter-spacing: 0.1em; text-transform: uppercase; transition: color 0.2s;
+}
+.header-nav a:hover { color: var(--accent-light); }
+.theme-toggle {
+ background: none; border: 1px solid var(--line); border-radius: 50%;
+ width: 36px; height: 36px; cursor: pointer; display: flex;
+ align-items: center; justify-content: center;
+ color: var(--ink-soft); transition: border-color 0.2s, color 0.2s;
+}
+.theme-toggle:hover { border-color: var(--accent-light); color: var(--accent-light); }
+
+/* ===== HERO ===== */
+.hero {
+ position: relative; height: 80vh; min-height: 520px;
+ overflow: hidden; display: flex; align-items: flex-end; justify-content: flex-start;
+}
+.hero-img {
+ position: absolute; inset: 0;
+ background-image: url('https://cdn.shopify.com/s/files/1/0015/4117/7456/files/P2022110_821_20f7858e-4602-4187-b2d1-282da682d37a.jpg');
+ background-size: cover; background-position: center 20%;
+}
+.hero-overlay {
+ position: absolute; inset: 0;
+ background: linear-gradient(to top,
+ rgba(10,10,10,0.92) 0%,
+ rgba(10,10,10,0.50) 45%,
+ rgba(10,10,10,0.20) 100%);
+}
+.hero-content {
+ position: relative; z-index: 2;
+ padding: 3rem 3rem; max-width: 720px;
+}
+.hero-eyebrow {
+ font-size: 0.68rem; letter-spacing: 0.3em; text-transform: uppercase;
+ color: var(--accent-light); margin-bottom: 0.8rem;
+}
+.hero h1 {
+ font-family: 'Tenor Sans', system-ui, sans-serif;
+ font-size: clamp(2.4rem, 5vw, 4.4rem);
+ font-weight: 400; line-height: 1.08; letter-spacing: -0.01em;
+ color: #f5f1e8; margin-bottom: 1rem;
+ text-shadow: 0 2px 24px rgba(0,0,0,0.6);
+}
+.hero-tagline {
+ font-size: 1rem; color: rgba(245,241,232,0.76);
+ max-width: 480px; line-height: 1.75;
+}
+
+/* ===== SECTION MARKER ===== */
+.section-marker {
+ position: sticky; top: 64px; z-index: 90;
+ background: rgba(10,10,10,0.85);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ border-bottom: 1px solid var(--rule);
+ padding: 0.5rem 2rem;
+ font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase;
+ color: var(--accent-light);
+}
+[data-theme="light"] .section-marker { background: rgba(248,244,245,0.88); }
+
+/* ===== SECTIONS ===== */
+.section { padding: 5rem 2rem; max-width: 1100px; margin: 0 auto; }
+.section-label {
+ font-size: 0.68rem; letter-spacing: 0.24em; text-transform: uppercase;
+ color: var(--accent-light); margin-bottom: 0.5rem;
+}
+.section h2 {
+ font-family: 'Tenor Sans', system-ui, sans-serif;
+ font-size: clamp(1.6rem, 3vw, 2.4rem);
+ font-weight: 400; margin-bottom: 1.5rem; letter-spacing: 0.02em;
+}
+.intro-text { font-size: 1rem; color: var(--ink-soft); max-width: 680px; line-height: 1.85; }
+
+/* ===== TWO-COLUMN GLOSSARY ===== */
+.glossary-header {
+ display: grid; grid-template-columns: 2fr 5fr;
+ gap: 0; padding: 0.5rem 1.2rem;
+ border-bottom: 2px solid var(--accent);
+ margin-bottom: 0.5rem;
+}
+.glossary-header-term {
+ font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent-light);
+}
+.glossary-header-def {
+ font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent-light);
+}
+
+.glossary-grid {
+ display: grid; grid-template-columns: 1fr;
+ gap: 0;
+}
+.glossary-row {
+ display: grid; grid-template-columns: 2fr 5fr;
+ gap: 1rem;
+ padding: 0.9rem 1.2rem;
+ border-bottom: 1px solid var(--line);
+ backdrop-filter: blur(20px) saturate(180%);
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
+ transition: background 0.15s;
+}
+.glossary-row:hover {
+ background: var(--accent-dim);
+}
+.glossary-term {
+ font-size: 0.92rem; font-weight: 400; color: var(--accent-light);
+ letter-spacing: 0.04em; line-height: 1.5;
+ display: flex; align-items: flex-start; padding-top: 0.05rem;
+}
+.glossary-def {
+ font-size: 0.9rem; color: var(--ink-soft); line-height: 1.75;
+}
+.tag {
+ display: inline-block; margin-left: 0.5rem; padding: 0.1rem 0.5rem;
+ border: 1px solid rgba(196,57,90,0.3); border-radius: 3px;
+ font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase;
+ color: var(--accent-light); vertical-align: middle; white-space: nowrap;
+}
+
+/* ===== IMAGE BREAK ===== */
+.image-break {
+ margin: 2.5rem 0; border-radius: 10px; overflow: hidden;
+ border: 1px solid var(--line); position: relative;
+}
+.image-break img {
+ width: 100%; height: 280px; object-fit: cover; display: block;
+}
+.image-break-caption {
+ position: absolute; bottom: 0; left: 0; right: 0;
+ background: rgba(10,10,10,0.80);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ padding: 0.8rem 1.2rem;
+ font-size: 0.8rem; color: var(--ink-soft);
+ font-style: italic;
+}
+[data-theme="light"] .image-break-caption { background: rgba(248,244,245,0.85); }
+
+/* ===== CTA ===== */
+.cta-section {
+ background: var(--card-bg);
+ border: 1px solid var(--line);
+ border-radius: 12px; padding: 3.5rem 3rem; text-align: center;
+ backdrop-filter: blur(20px) saturate(180%);
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
+ margin: 4rem auto; max-width: 760px;
+}
+.cta-section h2 {
+ font-family: 'Tenor Sans', system-ui, sans-serif;
+ font-size: 1.9rem; font-weight: 400; letter-spacing: 0.02em;
+ margin-bottom: 1rem;
+}
+.cta-section p { color: var(--ink-soft); margin-bottom: 2rem; line-height: 1.75; }
+.cta-btn {
+ display: inline-block; padding: 0.85rem 2.5rem;
+ background: var(--accent); color: #f5f1e8;
+ text-decoration: none; border-radius: 3px;
+ font-size: 0.82rem; letter-spacing: 0.12em; text-transform: uppercase;
+ transition: opacity 0.2s, transform 0.2s;
+}
+.cta-btn:hover { opacity: 0.88; transform: translateY(-1px); }
+
+/* ===== FOOTER ===== */
+.footer {
+ border-top: 1px solid var(--line);
+ padding: 2.5rem 2rem; text-align: center;
+ color: var(--ink-faint); font-size: 0.82rem;
+}
+.footer a { color: var(--accent-light); text-decoration: none; }
+
+@media (max-width: 640px) {
+ .header-nav { display: none; }
+ .glossary-row { grid-template-columns: 1fr; }
+ .glossary-header { display: none; }
+ .hero-content { padding: 2rem 1.5rem; }
+}
+</style>
+<script>
+(function(){
+ var t = localStorage.getItem('theme') || 'dark';
+ document.documentElement.setAttribute('data-theme', t);
+})();
+</script>
+</head>
+<body>
+
+<header class="header">
+ <a href="/" class="header-brand">
+ <div class="brand-dot"></div>
+ <span class="brand-name">Wallpaper Glossary</span>
+ </a>
+ <nav class="header-nav">
+ <a href="#glossary">Trade Terms</a>
+ <a href="#cta">Trade Account</a>
+ <a href="https://designerwallcoverings.com" target="_blank">DW</a>
+ </nav>
+ <button class="theme-toggle" id="themeToggle" aria-label="Toggle dark/light mode">
+ <svg id="iconSun" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:none"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
+ <svg id="iconMoon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
+ </button>
+</header>
+
+<section class="hero">
+ <div class="hero-img"></div>
+ <div class="hero-overlay"></div>
+ <div class="hero-content">
+ <p class="hero-eyebrow">For Interior Design Professionals</p>
+ <h1>Wallpaper<br>Glossary</h1>
+ <p class="hero-tagline">Thirty terms every designer specifying wallcoverings should know cold — from abrasion class to Type II, book match to zinc oxide ground.</p>
+ </div>
+</section>
+
+<div class="section-marker">Trade Reference</div>
+
+<section class="section" id="intro">
+ <p class="section-label">Professional Reference</p>
+ <h2>The working designer's vocabulary</h2>
+ <p class="intro-text">Wallcovering specifications live in a precise dialect shared between designers, installers, and contract reps. This glossary covers the thirty terms that appear most frequently on product data sheets, installation guides, and specification packages. Terms are organized thematically rather than alphabetically, so you can read straight through and build a coherent mental model of how the categories relate.</p>
+</section>
+
+<section class="section" id="glossary">
+ <p class="section-label">30 Trade Terms</p>
+ <h2>Trade Glossary</h2>
+
+ <!-- MATERIALS GROUP -->
+ <p class="section-label" style="margin-bottom:0.8rem;margin-top:0.5rem;">Materials</p>
+
+ <div class="glossary-header">
+ <div class="glossary-header-term">Term</div>
+ <div class="glossary-header-def">Definition</div>
+ </div>
+
+ <div class="glossary-grid">
+ <div class="glossary-row">
+ <div class="glossary-term">Non-Woven<span class="tag">Substrate</span></div>
+ <div class="glossary-def">A composite substrate of bonded natural and synthetic fibers. Dimensionally stable when wet; paste-the-wall compatible; dry-strippable on removal. Industry-standard backing for mid-to-premium residential and contract wallcovering since the early 2010s.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Type I Vinyl<span class="tag">Commercial</span></div>
+ <div class="glossary-def">Per ASTM F793: minimum face weight 7 oz/sq yd. Suitable for light commercial settings — offices, retail, boutique hotel guest rooms. Passes Class A fire rating; resists moderate traffic and cleaning.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Type II Vinyl<span class="tag">Commercial</span></div>
+ <div class="glossary-def">Per ASTM F793: minimum face weight 13 oz/sq yd. Specified for heavy commercial use — corridors, healthcare, schools, hospitality back-of-house. Scrubbable, impact-resistant; highest available abrasion and tear ratings.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Grasscloth<span class="tag">Natural</span></div>
+ <div class="glossary-def">Woven natural plant fiber — jute, seagrass, sisal, or abaca — laminated to a paper backing. Organic color variation between rolls is inherent and expected; book match is required. Not washable; requires breathable adhesive.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Flock<span class="tag">Textile</span></div>
+ <div class="glossary-def">Fine fibers adhered to an adhesive-printed pattern, creating a raised velvet pile surface. Originated 17th-century England as a silk-cut-velvet substitute. Contemporary versions range from historic reproductions to tonal sculptural patterns.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Mylar<span class="tag">Metallic</span></div>
+ <div class="glossary-def">Polyester film with a metallic coating laminated to a fabric or paper backing. Delivers reflective surfaces from satin to mirror-bright. Developed commercially in the 1960s; peaked in residential use in the 1970s; returns regularly in high-fashion interiors.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Cork<span class="tag">Natural</span></div>
+ <div class="glossary-def">Sliced natural cork bark laminated to a backing. Provides acoustic absorption and organic thermal warmth. Available in natural buff, stained, or printed variations. Requires moisture-resistant adhesive; not appropriate for high-humidity applications.</div>
+ </div>
+ </div>
+
+ <!-- IMAGE BREAK 1 -->
+ <div class="image-break" style="margin-top:2.5rem;">
+ <img src="https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Indienne_Agra_18310_Roomshot_Web_LR-og.jpg" alt="Arte International Agra wallcovering in a styled room setting" loading="lazy">
+ <div class="image-break-caption">Arte International "Agra Langsat" — a digitally printed non-directional pattern on non-woven backing; paste-the-wall compatible, dry-strippable.</div>
+ </div>
+
+ <!-- PATTERN & MATCH -->
+ <p class="section-label" style="margin-bottom:0.8rem;margin-top:2.5rem;">Pattern & Match</p>
+
+ <div class="glossary-header">
+ <div class="glossary-header-term">Term</div>
+ <div class="glossary-header-def">Definition</div>
+ </div>
+
+ <div class="glossary-grid">
+ <div class="glossary-row">
+ <div class="glossary-term">Vertical Repeat<span class="tag">Spec</span></div>
+ <div class="glossary-def">The distance along the roll length after which the pattern completes one full cycle. Printed on product labels as "V.R." A 27" repeat on 9-foot walls wastes approximately one full strip in trimming; calculate before ordering.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Horizontal Repeat<span class="tag">Spec</span></div>
+ <div class="glossary-def">The width of one complete pattern unit across the roll face. A horizontal repeat equal to the roll width produces a seamless tile; a repeat less than the roll width creates a multi-unit tile per strip.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Straight Match<span class="tag">Match Type</span></div>
+ <div class="glossary-def">Adjacent strips align identically at the same height. Zero offset between strips; no extra waste beyond standard cutting allowance. Also called flat match.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Drop Match<span class="tag">Match Type</span></div>
+ <div class="glossary-def">The pattern drops by a fraction of the vertical repeat between adjacent strips. Half-drop (most common) offsets by V.R. ÷ 2; quarter-drop by V.R. ÷ 4. Increases material requirement; use the manufacturer's coverage table, not raw square footage, for ordering.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Book Match<span class="tag">Installation</span></div>
+ <div class="glossary-def">Every other strip is reversed before hanging. Standard for grasscloth, sisal, seagrass, linen, and silk wallcoverings to mask directional shading between rolls. The reversed strip must still match the pattern; always confirm with a sample dry run before cutting.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Nondirectional<span class="tag">Pattern</span></div>
+ <div class="glossary-def">Pattern has no defined top or bottom. Strips may be alternated inverted without visible disruption. Reduces waste in rooms with multiple windows, doors, and interruptions. Common in texture, abstract, and geometric patterns.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Colorway<span class="tag">SKU</span></div>
+ <div class="glossary-def">A single color variation of a pattern design. Each colorway is a separate product number with its own dye lot. Confirm colorway number — not just pattern name — on every purchase order. Cross-colorway mixing is never correct.</div>
+ </div>
+ </div>
+
+ <!-- IMAGE BREAK 2 -->
+ <div class="image-break" style="margin-top:2.5rem;">
+ <img src="https://cdn.shopify.com/s/files/1/0015/4117/7456/files/EssentialsLuxor_Horus_19436_Roomshot_Web_LR-og.jpg" alt="Arte Horus Bone wallcovering in a warm modern interior" loading="lazy">
+ <div class="image-break-caption">Arte International "Horus Bone" — a nondirectional geometric; any strip can be inverted with no pattern interruption, minimizing jobsite waste.</div>
+ </div>
+
+ <!-- PRODUCTION -->
+ <p class="section-label" style="margin-bottom:0.8rem;margin-top:2.5rem;">Production & Specification</p>
+
+ <div class="glossary-header">
+ <div class="glossary-header-term">Term</div>
+ <div class="glossary-header-def">Definition</div>
+ </div>
+
+ <div class="glossary-grid">
+ <div class="glossary-row">
+ <div class="glossary-term">Screen Print<span class="tag">Production</span></div>
+ <div class="glossary-def">One mesh screen per color passes ink through a defined stencil onto the substrate. Maximum color fidelity; precise registration; premium cost. Each additional color requires setup of a new screen and increases per-yard price.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Digital Print<span class="tag">Production</span></div>
+ <div class="glossary-def">Large-format inkjet printing direct to substrate. No screen setup; unlimited color palette; enables custom scale and custom colorways at economical short-run quantities. Dominant production method for murals, custom work, and designer collections launched post-2010.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Block Print<span class="tag">Production</span></div>
+ <div class="glossary-def">Hand-applied printing using carved wooden or linoleum blocks. Each impression is individual; minute variation between blocks creates the signature character of hand-printed goods. Longest lead times; highest labor cost; bespoke and artisan collections only.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Dye Lot<span class="tag">QA</span></div>
+ <div class="glossary-def">Production batch identifier. All rolls from a single dye lot match; lots differ subtly. Always specify same-lot procurement on purchase orders and instruct clients to keep one surplus roll per lot for future repairs.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Roll Length<span class="tag">Spec</span></div>
+ <div class="glossary-def">Linear content per package. US residential standard single roll: approximately 11 yards / 10m. Double roll (most common retail unit): approximately 22 yards / 20.5m. Wide-width commercial goods: sold by the linear yard, cut to order. Always verify before calculating coverage.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Width<span class="tag">Spec</span></div>
+ <div class="glossary-def">Trimmed horizontal dimension. US residential standard: 20.5"–27". European standard: 20.5" (52cm). Commercial wide-width: 48"–54". Wider stock reduces seam count on large walls; confirm before specifying for panoramic or mural applications.</div>
+ </div>
+ </div>
+
+ <!-- IMAGE BREAK 3 -->
+ <div class="image-break" style="margin-top:2.5rem;">
+ <img src="https://cdn.shopify.com/s/files/1/0015/4117/7456/files/LesTapisseries_Bouquet_97910_Mood_Web_LR-hero_fbee8df6-a478-4711-bf0f-ad3cad8d696d.jpg" alt="Arte International Bouquet Emerald large-scale floral pattern" loading="lazy">
+ <div class="image-break-caption">Arte International "Bouquet Emerald" — a screen-printed large-format floral requiring careful drop-match installation.</div>
+ </div>
+
+ <!-- INSTALLATION -->
+ <p class="section-label" style="margin-bottom:0.8rem;margin-top:2.5rem;">Installation</p>
+
+ <div class="glossary-header">
+ <div class="glossary-header-term">Term</div>
+ <div class="glossary-header-def">Definition</div>
+ </div>
+
+ <div class="glossary-grid">
+ <div class="glossary-row">
+ <div class="glossary-term">Paste-the-Wall<span class="tag">Install</span></div>
+ <div class="glossary-def">Adhesive applied to the substrate wall surface; dry strip hung and slid into position. Non-woven backed goods only. Cleaner, faster than paste-the-paper; reduces risk of paste contaminating the face. Confirm manufacturer approval before specifying.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Paste-the-Paper<span class="tag">Install</span></div>
+ <div class="glossary-def">Adhesive applied to the back of the cut strip, which is then folded (booked) for soak time before hanging. Required for natural fiber, most paper-backed, and pre-trimmed antique wallcoverings. Paste type must match substrate: starch for paper, heavy-duty methylcellulose for grasscloth and vinyl.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Booking<span class="tag">Install</span></div>
+ <div class="glossary-def">Folding a pasted strip face-to-face (paste surfaces together) and allowing it to rest for the manufacturer's specified soak time — typically 3–8 minutes. Ensures the substrate absorbs moisture evenly before hanging; prevents edge-drying and bubbling.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Double Cut<span class="tag">Seaming</span></div>
+ <div class="glossary-def">Seaming technique where the two overlapping strips are cut simultaneously with a straight edge and sharp blade. Both waste pieces are removed, leaving a perfect butt seam. Required for heavy vinyl and embossed goods; optional but recommended for most types.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Strippable<span class="tag">Removal</span></div>
+ <div class="glossary-def">The decorative face and backing remove together, dry, in one piece. Leaves the wall surface clear for immediate re-priming. Standard on all non-woven backed goods. Confirm before specifying in rental or hospitality properties where lifecycle turnover is expected.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Peelable<span class="tag">Removal</span></div>
+ <div class="glossary-def">Decorative face peels away from the backing separately. Backing remains adhered and must be soaked and scraped off independently. More labor-intensive than strippable removal; factor into lifecycle cost on renovation-heavy projects.</div>
+ </div>
+ </div>
+
+ <!-- COMMERCIAL / PERFORMANCE -->
+ <p class="section-label" style="margin-bottom:0.8rem;margin-top:2.5rem;">Performance & Compliance</p>
+
+ <div class="glossary-header">
+ <div class="glossary-header-term">Term</div>
+ <div class="glossary-header-def">Definition</div>
+ </div>
+
+ <div class="glossary-grid">
+ <div class="glossary-row">
+ <div class="glossary-term">Class A / Class 1<span class="tag">Fire</span></div>
+ <div class="glossary-def">The most stringent surface-burning classification per ASTM E84. Flame spread index 0–25; smoke development index 0–450. Required by code for commercial occupancies, healthcare, education, and many hospitality applications. Confirm with AHJ before specifying.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Abrasion Resistance<span class="tag">Durability</span></div>
+ <div class="glossary-def">Measured by the Wyzenbeek or Martindale test; expressed as number of double-rubs without visible wear. Higher double-rub count = more durable surface. Minimum 50,000 double-rubs typically required for heavy commercial specification; 25,000 for light commercial.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Scrub Resistance<span class="tag">Durability</span></div>
+ <div class="glossary-def">Per ASTM D2486: number of wet-scrub cycles the face can endure without color loss or surface degradation. Type II commercial vinyl: minimum 300 cycles. Washable residential goods: typically 50–100 cycles. Confirm before specifying kitchens, bathrooms, or high-contact walls.</div>
+ </div>
+ <div class="glossary-row">
+ <div class="glossary-term">Memo Sample<span class="tag">Trade</span></div>
+ <div class="glossary-def">A full-width cutting distributed at no charge for client presentation and light evaluation. Standard memo is 8"–18" length, providing one full horizontal repeat. Designer Wallcoverings ships memo samples free of charge from its full catalog of 8,000+ SKUs.</div>
+ </div>
+ </div>
+
+</section>
+
+<div class="section-marker">Trade Accounts & Samples</div>
+
+<section class="section" id="cta">
+ <div class="cta-section">
+ <h2>Trade accounts, free samples, and hands-on specification support</h2>
+ <p>Designer Wallcoverings works directly with interior designers, architects, and commercial specifiers. Open a trade account, request memo samples on any of 8,000+ SKUs, and get yardage calculations from our dedicated specification team.</p>
+ <a href="https://designerwallcoverings.com" target="_blank" class="cta-btn">Open a Trade Account</a>
+ </div>
+</section>
+
+<footer class="footer">
+ <p>© 2026 Wallpaper Glossary — A trade resource by <a href="https://designerwallcoverings.com">Designer Wallcoverings</a></p>
+ <p style="margin-top:0.5rem;"><a href="mailto:info@wallpaperglossary.com">info@wallpaperglossary.com</a></p>
+</footer>
+
+<script>
+const toggle = document.getElementById('themeToggle');
+const sun = document.getElementById('iconSun');
+const moon = document.getElementById('iconMoon');
+function applyTheme(t) {
+ document.documentElement.setAttribute('data-theme', t);
+ localStorage.setItem('theme', t);
+ sun.style.display = t === 'light' ? 'block' : 'none';
+ moon.style.display = t === 'dark' ? 'block' : 'none';
+}
+applyTheme(localStorage.getItem('theme') || 'dark');
+toggle.addEventListener('click', () => {
+ const current = document.documentElement.getAttribute('data-theme');
+ applyTheme(current === 'dark' ? 'light' : 'dark');
+});
+</script>
+</body>
+</html>
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..4ce0c9c
--- /dev/null
+++ b/server.js
@@ -0,0 +1,14 @@
+const express = require('express');
+const path = require('path');
+const app = express();
+const PORT = process.env.PORT || 9902;
+
+app.use(express.static(path.join(__dirname, 'public')));
+
+app.get('/health', (req, res) => res.json({ status: 'ok', site: 'wallpaperglossary.com' }));
+
+app.get('/', (req, res) => {
+ res.sendFile(path.join(__dirname, 'public', 'index.html'));
+});
+
+app.listen(PORT, () => console.log(`wallpaperglossary.com :${PORT}`));
(oldest)
·
back to Wallpaperglossary
·
snapshot before hamburger nav rollout 0f17189 →