From a22447185637fca761ded1ea2bec9b404fe20481 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 07:02:35 +0000 Subject: [PATCH 1/5] docs: the readme and home page lead with what a user gets, and name specsolve and linopy as engines The three design properties become five user benefits, shared with the home page as a README snippet. A new benefit links the PyPSA example pages. specsolve and linopy are named as engines, with support in both marked as work in progress. The home page's primary button is now the examples. The unused flow snippet markers are gone. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q8Y8AoPsJCyMsURHvgzm7h --- README.md | 43 ++++++++++++++++++++++++++++--------------- docs/index.md | 15 ++++++++------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d258e653..b9331493 100644 --- a/README.md +++ b/README.md @@ -31,19 +31,34 @@ solves nothing itself. Every tool reads the file through the same checked syntax tree, so an engine and a renderer cannot disagree about what the file means ([what counts as language](docs/about/what-counts-as-language.md)). -- **Nothing is guessed.** A misspelled name, a `where` string on an undeclared - parameter, a constraint whose dimensions do not match its `dims`: each fails - when the file loads, with a message that names the fix. A repository of models - checks in CI with no data ([errors](docs/reference/language/errors.md)). -- **The operators are a fixed set.** `sum`, `sum_back`, `at` and `shift`. A file - cannot add one, so a model never depends on what one engine registered. A - composition of them goes in `macros:` ([the limits](docs/about/limits.md)). -- **The file is the document.** `to_latex(spec)` prints the model as equations - from the file alone, so the math you publish is the math you solve - ([typeset](docs/reference/typeset.md)). The file diffs in review, and no - Python state changes what it means. - - + + +[specsolve](https://github.com/fluxopt/specsolve) and +[linopy](https://github.com/PyPSA/linopy) build and solve a math-spec model. +Support in both is work in progress. + + + + + +- **Check a model repository in CI with no data.** A misspelled name, a `where` + string on an undeclared parameter, or a constraint whose dimensions do not + match its `dims` fails when the file loads. The message names the fix + ([errors](https://math-spec.readthedocs.io/en/latest/reference/language/errors/)). +- **Publish the math you solve.** `to_latex(spec)` prints the model as equations + from the file alone, so the paper and the solver read one source + ([typeset](https://math-spec.readthedocs.io/en/latest/reference/typeset/)). +- **Change the engine and keep the model.** The operators are a fixed set: + `sum`, `sum_back`, `at` and `shift`. A file cannot add one, so a model does not + depend on what one engine registered ([limits](https://math-spec.readthedocs.io/en/latest/about/limits/)). +- **Review a model as a diff.** The file is plain YAML, and no Python state + changes what it means. +- **Write full-size models.** [PyPSA in one file](https://math-spec.readthedocs.io/en/latest/examples/pypsa/) states + the model that PyPSA's `n.optimize()` builds, with an index of each PyPSA row. + Five more pages add quadratic costs, relaxed unit commitment, line losses, + two-stage stochastic scenarios and investment periods. + + ```mermaid flowchart LR @@ -64,8 +79,6 @@ flowchart LR class ERR err ``` - - ## Example diff --git a/docs/index.md b/docs/index.md index 074ae7f3..636f1c2a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,8 +15,8 @@ with no data and no solver.** --8<-- "README.md:badges" -[Read the language](reference/language/index.md){ .md-button .md-button--primary } -[See the examples](examples/index.md){ .md-button } +[See the examples](examples/index.md){ .md-button .md-button--primary } +[Read the language](reference/language/index.md){ .md-button } @@ -24,6 +24,12 @@ with no data and no solver.**
+## What it is for + +--8<-- "README.md:benefits" + +--8<-- "README.md:engines" + ## A model is one file A file declares four things: the axes the model runs over, the data it @@ -32,11 +38,6 @@ The file below is a complete model. --8<-- "README.md:model" -Everything that can be checked without data is checked when the file loads. A -misspelled name, a `where:` on an undeclared parameter, or a constraint whose -dimensions do not match its `dims:` is refused with a message that names the -fix. - ## The math it prints Printed from the file above, with no data and no solver. **How** shows the From f7ff658d9ac364a63eb7bdb527670d6535066473 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 07:16:27 +0000 Subject: [PATCH 2/5] docs: the home page shows the benefits as cards Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q8Y8AoPsJCyMsURHvgzm7h --- docs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/index.md b/docs/index.md index 636f1c2a..becfc59c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,8 +26,12 @@ with no data and no solver.** ## What it is for +
+ --8<-- "README.md:benefits" +
+ --8<-- "README.md:engines" ## A model is one file From d492292f88bc22d2af5f71cc6e83a18a0f550ef7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 07:23:08 +0000 Subject: [PATCH 3/5] docs: the home page's benefit cards carry an icon, a headline and one short line Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q8Y8AoPsJCyMsURHvgzm7h --- README.md | 30 ++++++++++++++---------------- docs/static/extras.css | 28 +++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b9331493..009d3867 100644 --- a/README.md +++ b/README.md @@ -41,22 +41,20 @@ Support in both is work in progress. -- **Check a model repository in CI with no data.** A misspelled name, a `where` - string on an undeclared parameter, or a constraint whose dimensions do not - match its `dims` fails when the file loads. The message names the fix - ([errors](https://math-spec.readthedocs.io/en/latest/reference/language/errors/)). -- **Publish the math you solve.** `to_latex(spec)` prints the model as equations - from the file alone, so the paper and the solver read one source - ([typeset](https://math-spec.readthedocs.io/en/latest/reference/typeset/)). -- **Change the engine and keep the model.** The operators are a fixed set: - `sum`, `sum_back`, `at` and `shift`. A file cannot add one, so a model does not - depend on what one engine registered ([limits](https://math-spec.readthedocs.io/en/latest/about/limits/)). -- **Review a model as a diff.** The file is plain YAML, and no Python state - changes what it means. -- **Write full-size models.** [PyPSA in one file](https://math-spec.readthedocs.io/en/latest/examples/pypsa/) states - the model that PyPSA's `n.optimize()` builds, with an index of each PyPSA row. - Five more pages add quadratic costs, relaxed unit commitment, line losses, - two-stage stochastic scenarios and investment periods. +- :white_check_mark: **Check models in CI, with no data.** A wrong name or + dimension fails when the file loads, and the error names the fix. + [Errors →](https://math-spec.readthedocs.io/en/latest/reference/language/errors/) +- :page_facing_up: **Publish the math you solve.** The equations in the paper + print from the file the solver reads. + [Typeset →](https://math-spec.readthedocs.io/en/latest/reference/typeset/) +- :arrows_counterclockwise: **Switch engines, keep the model.** The operators + are a fixed set, so every engine reads the file the same way. + [Limits →](https://math-spec.readthedocs.io/en/latest/about/limits/) +- :mag: **Review a model as a diff.** The model is plain YAML, and no Python + state changes what it means. +- :electric_plug: **Write full-size models.** PyPSA's `n.optimize()` model is + one file, with stochastic, multi-period and quadratic variants. + [PyPSA in one file →](https://math-spec.readthedocs.io/en/latest/examples/pypsa/) diff --git a/docs/static/extras.css b/docs/static/extras.css index 2c589326..6d36af83 100644 --- a/docs/static/extras.css +++ b/docs/static/extras.css @@ -308,12 +308,38 @@ margin-left: 0.5rem; } +/* Benefit cards: the README bullet's icon and bold lead-in become the card's + * heading, since the README cannot carry card markup. */ +.md-typeset .landing .grid.cards > ul > li { + border-top: 0.2rem solid var(--md-accent-fg-color); +} + +.md-typeset .landing .grid.cards > ul > li > .twemoji:first-child { + display: block; + width: 2.4rem; + height: 2.4rem; + margin-bottom: 0.6rem; +} + +.md-typeset .landing .grid.cards > ul > li > strong:first-of-type { + display: block; + font-size: 1.05rem; + margin-bottom: 0.4rem; + padding-bottom: 0.4rem; + border-bottom: 0.05rem solid var(--md-default-fg-color--lightest); +} + +.md-typeset .landing .grid.cards > ul > li:hover { + transform: translateY(-0.15rem); +} + /* Grid card hover lift — small polish */ .md-typeset .grid.cards > ul > li, .md-typeset .grid > .card { transition: border-color 125ms, - box-shadow 125ms; + box-shadow 125ms, + transform 125ms; } .md-typeset .grid.cards > ul > li:hover, From cd8f58c6168ad5b7b7ada2c61d85d503a6f05418 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 07:26:14 +0000 Subject: [PATCH 4/5] docs: the home page's benefit cards are plain, and a click anywhere on one follows its link Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q8Y8AoPsJCyMsURHvgzm7h --- README.md | 10 +++++----- docs/static/extras.css | 32 ++++++++++++++++---------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 009d3867..03fa49a2 100644 --- a/README.md +++ b/README.md @@ -41,18 +41,18 @@ Support in both is work in progress. -- :white_check_mark: **Check models in CI, with no data.** A wrong name or +- **Check models in CI, with no data.** A wrong name or dimension fails when the file loads, and the error names the fix. [Errors →](https://math-spec.readthedocs.io/en/latest/reference/language/errors/) -- :page_facing_up: **Publish the math you solve.** The equations in the paper +- **Publish the math you solve.** The equations in the paper print from the file the solver reads. [Typeset →](https://math-spec.readthedocs.io/en/latest/reference/typeset/) -- :arrows_counterclockwise: **Switch engines, keep the model.** The operators +- **Switch engines, keep the model.** The operators are a fixed set, so every engine reads the file the same way. [Limits →](https://math-spec.readthedocs.io/en/latest/about/limits/) -- :mag: **Review a model as a diff.** The model is plain YAML, and no Python +- **Review a model as a diff.** The model is plain YAML, and no Python state changes what it means. -- :electric_plug: **Write full-size models.** PyPSA's `n.optimize()` model is +- **Write full-size models.** PyPSA's `n.optimize()` model is one file, with stochastic, multi-period and quadratic variants. [PyPSA in one file →](https://math-spec.readthedocs.io/en/latest/examples/pypsa/) diff --git a/docs/static/extras.css b/docs/static/extras.css index 6d36af83..8bfd0a75 100644 --- a/docs/static/extras.css +++ b/docs/static/extras.css @@ -308,29 +308,30 @@ margin-left: 0.5rem; } -/* Benefit cards: the README bullet's icon and bold lead-in become the card's - * heading, since the README cannot carry card markup. */ +/* Benefit cards: the README bullet's bold lead-in is the card's title, and its + * one link covers the whole card, since the README cannot carry card markup. */ .md-typeset .landing .grid.cards > ul > li { - border-top: 0.2rem solid var(--md-accent-fg-color); + position: relative; + color: var(--md-default-fg-color--light); } -.md-typeset .landing .grid.cards > ul > li > .twemoji:first-child { +.md-typeset .landing .grid.cards > ul > li > strong:first-child { display: block; - width: 2.4rem; - height: 2.4rem; - margin-bottom: 0.6rem; + margin-bottom: 0.3rem; + color: var(--md-default-fg-color); + font-size: 0.9rem; } -.md-typeset .landing .grid.cards > ul > li > strong:first-of-type { +.md-typeset .landing .grid.cards > ul > li > a:last-child { display: block; - font-size: 1.05rem; - margin-bottom: 0.4rem; - padding-bottom: 0.4rem; - border-bottom: 0.05rem solid var(--md-default-fg-color--lightest); + margin-top: 0.6rem; + font-weight: 700; } -.md-typeset .landing .grid.cards > ul > li:hover { - transform: translateY(-0.15rem); +.md-typeset .landing .grid.cards > ul > li > a:last-child::after { + content: ""; + position: absolute; + inset: 0; } /* Grid card hover lift — small polish */ @@ -338,8 +339,7 @@ .md-typeset .grid > .card { transition: border-color 125ms, - box-shadow 125ms, - transform 125ms; + box-shadow 125ms; } .md-typeset .grid.cards > ul > li:hover, From 509f456a933c8b34fe813cf3c12cd9e8b6d36210 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 07:36:06 +0000 Subject: [PATCH 5/5] docs: each home page benefit card carries an icon, and the third says every tool reads one public api The icons are Octicons (MIT, GitHub Inc.) and Material Design Icons (Apache-2.0, Pictogrammers), copied from the icon sets mkdocs-material bundles, with their licence in each file's header. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q8Y8AoPsJCyMsURHvgzm7h --- LICENSES/Apache-2.0.txt | 202 +++++++++++++++++++++++ README.md | 6 +- docs/static/extras.css | 31 ++++ docs/static/icons/checklist.svg | 5 + docs/static/icons/puzzle.svg | 5 + docs/static/icons/sigma.svg | 5 + docs/static/icons/transmission-tower.svg | 5 + 7 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 LICENSES/Apache-2.0.txt create mode 100644 docs/static/icons/checklist.svg create mode 100644 docs/static/icons/puzzle.svg create mode 100644 docs/static/icons/sigma.svg create mode 100644 docs/static/icons/transmission-tower.svg diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 03fa49a2..c20f12c8 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ Support in both is work in progress. - **Publish the math you solve.** The equations in the paper print from the file the solver reads. [Typeset →](https://math-spec.readthedocs.io/en/latest/reference/typeset/) -- **Switch engines, keep the model.** The operators - are a fixed set, so every engine reads the file the same way. - [Limits →](https://math-spec.readthedocs.io/en/latest/about/limits/) +- **One model, many tools.** Engines, renderers and analysers read the model + through one public API, so no two of them can read the file differently. + [Program API →](https://math-spec.readthedocs.io/en/latest/reference/program/) - **Review a model as a diff.** The model is plain YAML, and no Python state changes what it means. - **Write full-size models.** PyPSA's `n.optimize()` model is diff --git a/docs/static/extras.css b/docs/static/extras.css index 8bfd0a75..6d0d8530 100644 --- a/docs/static/extras.css +++ b/docs/static/extras.css @@ -334,6 +334,37 @@ inset: 0; } +/* A card's icon is chosen by where its link points, so reordering the README + * list cannot move an icon onto another card. */ +.md-typeset .landing .grid.cards > ul > li::before { + display: block; + width: 1.6rem; + height: 1.6rem; + margin-bottom: 0.6rem; + background-color: var(--md-accent-fg-color); + mask: center / contain no-repeat; +} + +.md-typeset .landing .grid.cards > ul > li:has(> a[href$="/reference/language/errors/"])::before { + content: ""; + mask-image: url("icons/checklist.svg"); +} + +.md-typeset .landing .grid.cards > ul > li:has(> a[href$="/reference/typeset/"])::before { + content: ""; + mask-image: url("icons/sigma.svg"); +} + +.md-typeset .landing .grid.cards > ul > li:has(> a[href$="/reference/program/"])::before { + content: ""; + mask-image: url("icons/puzzle.svg"); +} + +.md-typeset .landing .grid.cards > ul > li:has(> a[href$="/examples/pypsa/"])::before { + content: ""; + mask-image: url("icons/transmission-tower.svg"); +} + /* Grid card hover lift — small polish */ .md-typeset .grid.cards > ul > li, .md-typeset .grid > .card { diff --git a/docs/static/icons/checklist.svg b/docs/static/icons/checklist.svg new file mode 100644 index 00000000..0d3a114a --- /dev/null +++ b/docs/static/icons/checklist.svg @@ -0,0 +1,5 @@ + + diff --git a/docs/static/icons/puzzle.svg b/docs/static/icons/puzzle.svg new file mode 100644 index 00000000..aa67bfeb --- /dev/null +++ b/docs/static/icons/puzzle.svg @@ -0,0 +1,5 @@ + + diff --git a/docs/static/icons/sigma.svg b/docs/static/icons/sigma.svg new file mode 100644 index 00000000..44e67919 --- /dev/null +++ b/docs/static/icons/sigma.svg @@ -0,0 +1,5 @@ + + diff --git a/docs/static/icons/transmission-tower.svg b/docs/static/icons/transmission-tower.svg new file mode 100644 index 00000000..06f65ffc --- /dev/null +++ b/docs/static/icons/transmission-tower.svg @@ -0,0 +1,5 @@ + +