lsd0006

LSD0006: The 'taler' URI scheme
Log | Files | Refs

commit b73cdaed9b1c4cc6b5547aa78236779a84e4f96b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon,  6 Feb 2023 15:55:31 +0100

moving files from Taler marketing.git

Diffstat:
AMakefile | 8++++++++
Adraft-grothoff-taler.xml | 655+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ametadata.min.js | 2++
Astyle.css | 1145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1810 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,8 @@ +all: txt html + +html: + xml2rfc --html --css style.css draft-grothoff-taler.xml + +txt: + xml2rfc draft-grothoff-taler.xml + diff --git a/draft-grothoff-taler.xml b/draft-grothoff-taler.xml @@ -0,0 +1,655 @@ +<?xml version="1.0" encoding="US-ASCII"?> +<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [ +<!ENTITY RFC2119 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml"> +<!ENTITY RFC3986 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.3986.xml"> +<!ENTITY RFC5234 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5234.xml"> +<!ENTITY RFC8126 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8126.xml"> +<!ENTITY RFC8174 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8174.xml"> +]> +<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?> +<!-- SEE ALSO: https://docs.taler.net/core/taler-uri.html --> +<?rfc strict="yes" ?> +<?rfc toc="yes" ?> +<?rfc symrefs="yes"?> +<?rfc sortrefs="yes" ?> +<?rfc compact="yes" ?> +<?rfc subcompact="no" ?> + +<rfc category="info" + docName="draft-grothoff-taler-01" + ipr="trust200902"> + + <front> + <title abbrev="The 'taler' URI scheme"> + The 'taler' URI scheme for GNU Taler Wallet interactions + </title> + + <author fullname="Christian Grothoff" initials="C.G." surname="Grothoff"> + <organization>BFH</organization> + <address> + <postal> + <street>H&ouml;heweg 80</street> + <street></street> + <city>Biel/Bienne</city> + <code>CH-2501</code> + <country>CH</country> + </postal> + <email>christian.grothoff@bfh.ch</email> + </address> + </author> + + <author fullname="Florian Dold" initials="F.D." surname="Dold"> + <organization>Taler Systems SA</organization> + <address> + <postal> + <street>7, rue de Mondorf</street> + <city>Erpeldange</city> + <code>L-5421</code> + <country>LU</country> + </postal> + <email>dold@taler.net</email> + </address> + </author> + + <date day="16" month="November" year="2022" /> + + <!-- Meta-data Declarations --> + <area>General</area> + <workgroup>Independent Stream</workgroup> + <keyword>payments</keyword> + + <abstract> + + <t> + This document defines the 'taler' Uniform Resource Identifier (URI) scheme + for triggering interactions with a GNU Taler wallet. + </t> + + <t> + This URI scheme allows applications to trigger interactions with the GNU Taler wallet, + such as withdrawing money, making payments, receiving refunds and restoring a wallet + from a backup. Applications may receive such URIs in many ways (including via NFC, + QR codes, Web links or messaging applications), or might generate them internally to + interact with a wallet. By having a Taler wallet handle the respective URIs, + applications can integrate Taler payments without having to support the Taler protocol + directly. Furthermore, by passing control to a Taler wallet process, the wallet's + database with its financial data might be better protected from application failures. + </t> + + </abstract> + + </front> + + <middle> + +<section anchor="introduction" title="Introduction"> +<t> + This document defines the 'taler' Uniform Resource Identifier (URI) <xref target="RFC3986" /> scheme + for triggering interactions with GNU Taler wallets. +</t> + +<section title="Objective"> +<t> + A 'taler' URI always instructs a GNU Taler wallet to perform a particular operation. + A 'taler' URI consists of an action and optional parameters. +</t> +<t> + The interpretation of the optional parameters depends on the action. +</t> +</section> +<section title="Requirements Language"> +<t> + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in BCP 14 + <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, + they appear in all capitals, as shown here. +</t> +</section> + +</section> + +<section anchor="syntax" + title="Syntax of a 'taler' URI"> + <t> + This document uses the Augmented Backus-Naur Form (ABNF) of <xref target="RFC5234"/>. + </t> + <figure> + <artwork type="abnf"><![CDATA[ + taler-URI = ("taler://" / "TALER://" / "taler+http://" / "TALER+HTTP://" ) + action path-abempty [ "?" opts ] + action = ALPHA *( ALPHA / DIGIT / "-" / "." ) + opts = opt *( "&" opt ) + opt = opt-name "=" opt-value + opt-name = ALPHA *( ALPHA / DIGIT / "-" / "." / ":" ) + opt-value = *pchar +]]> + </artwork> + </figure> + <t> + 'path-abempty' is defined in <xref target="RFC3986" /> in Section 3.3. + 'pchar' is defined in <xref target="RFC3986" />, Appendix A. + </t> +</section> + +<section anchor="semantics" title="Semantics"> +<t> + The action of a Taler URI identifies the operation requested from the Taler + wallet. Actions are not case-sensitive. The actions are defined in the "Taler + URI Actions" sub-registry, see <xref target="taler-registry" />. + + The path component of the URI typically provides a network address needed to + locate additional information or services relevant to the requested operation. + Paths are case-sensitive, but may contain case-insensitive portions, such + as domain names. + + The query component of the URI provides immediate additional parameters or + options for the operation. The query is case-sensitive. + + The default operation of applications that invoke a URI with the taler + scheme MUST be to launch a Taler wallet (if available). If no taler URI + handler is available, an application SHOULD show a QR code with the contents + of the URI. If multiple Taler wallets are registered, the user SHOULD be + able to choose which application to launch. This allows users with multiple + wallets (each possibly with its own money) to choose which wallet to perform + the operation with. + + An application SHOULD allow dereferencing a "taler://" URI even + if the action of that URI is not registered in the "Taler URI Actions" sub-registry. + + Wallets seeing a "taler://" URI MUST use HTTP over TLS when talking + to the respective network service. + Wallets seeing a "taler+http://" URI MUST use HTTP without TLS when talking + to the respective network service. Wallets SHOULD support + "taler+http://"-URIs only when run in developer or debug mode. + +</t> +</section> + +<section anchor="examples" title="Examples"> +<figure> + <artwork><![CDATA[ + taler://pay/example.com/2022.268-03G33PTAY2C6T/\ + 00f68430-363a-46b7-8e33-241a0e49c430?c=KKBWMSTF4AZSP8XS0FFNE9KM5M + taler://pay-push/bank.example.com/\ + 3BBW6N8PVDYBRT0DERT8YYARQGFYHVQFG3WVAN1D58FRP5JG3M4G + TALER://PAY-PULL/BANK.EXAMPLE.COM/\ + WB361HXN7BZ9ND1B9YP1Y20NB4H5WS0RNM4K8AFZ5Q2VRW577BPG +]]> + </artwork> +</figure> + +</section> + +<section anchor="tracking" title="Tracking Taler URI Actions"> + <t> + A registry of Taler URI Actions is described in <xref target="taler-registry" />. + + The registration policy for this registry is "Expert Review", + as described in <xref target="RFC8126" />. +When requesting new entries, careful consideration of the following criteria is strongly advised: +<list style="numbers"> + <t>The description clearly defines the semantics of the action and optional parameters if applicable.</t> + <t>The name states the unique name for the action that must be part of the URI.</t> + <t>The syntax defines the format of the action-specific part of the URI.</t> + <t>Relevant references are provided if they are available.</t> + <t>The chosen name is appropriate for the operation, and avoids potential to confuse users.</t> + <t>A libre software reference implementation is available.</t> +</list> +</t> +<t> +Documents that support requests for new registry entries should + provide the following information for each entry: +<list style="symbols"> +<t>Description: A description of the action, including + the semantics of the path in the URI if applicable.</t> +<t>Name: The name of the Taler URI action (case insensitive ASCII string, restricted to alphanumeric characters, +dots and dashes)</t> +<t>Syntax: summary of the syntax of the URI as a one-liner.</t> +<t>Example: At least one example URI to illustrate the action.</t> +<t>Contact: The contact information of a person to contact for further information</t> +<t>References: Optionally, references describing the action (such as an RFC) and target-specific options.</t> +</list> +</t> +<t> +This document populates the registry with $COUNT entries as follows (see +also <xref target="taler-registry" />). +</t> + +<section anchor="registry-entry-withdraw" title="Action: withdraw"> +<t> + The action "withdraw" is used to trigger a bank-integrated withdrawal operation. + This means that the user has been interacting with some online banking App and + wants to instruct the bank to transfer money from the user's bank account into + a the GNU Taler wallet. The wallet now needs to allow the user to select the + GNU Taler exchange, and then ultimately provide the bank with its + reserve public key and await the completion of the wire transfer. +</t> +<t> + The specific arguments of a "withdraw" action are: + <list style="symbols"> + <t>bank_host: hostname of the bank (optionally including a port number)</t> + <t>bank_prefix_path: list of path components that identifies the path prefix of the bank integration API base URL</t> + <t>withdrawal_uid: the unique ID of the withdrawal operation</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: withdraw</t> +<t>Syntax: taler://withdraw/{bank_host}{/bank_prefix_path*}/{withdrawal_uid}</t> +<t>Example: taler://withdraw/bank.example.com/wid</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-pay" title="Action: pay"> +<t> + Payments are requested with the "pay" action. + The parameters are a hierarchical identifier for the requested payment, + and must include a hostname, order ID and session ID (which may be + an empty string). Additionally, a claim token and a prefix path to be used + as part of the HTTP REST API request to the hostname may be specified. +</t> +<t> + The specific arguments of a "pay" action are: + <list style="symbols"> + <t>merchant_host: hostname of the GNU Taler REST service of merchant (may optionally include a port number)</t> + <t>merchant_prefix_path: list of path components that identifies the path prefix of the merchant base URL</t> + <t>order_id: the order ID that the customer is asked to pay for</t> + <t>session_id: the session ID under which the payment takes place</t> + <t>ct: a high-entropy order "ClaimToken"</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: pay</t> +<t>Syntax: taler://pay/{merchant_host}{/merchant_prefix_path*}/{order_id}/{session_id}{?c=ct}</t> +<t>Example: taler://pay/merchant.example.com/42/</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-refund" title="Action: refund"> + <t> + A "refund" action instructs the wallet to download information about + an available refund. Wallet SHOULD consult the user about the refund and + then obtain the refund for an already paid order. + </t> + <t> + The specific arguments of a "refund" action are: + <list style="symbols"> + <t>merchant_host: hostname of the merchant (possibly including a port number)</t> + <t>merchant_prefix_path: list of path components that identifies the path prefix of the merchant base URL</t> + <t>order_id: the order ID to check for refunds</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: refund</t> +<t>Syntax: taler://refund/{merchant_host}{/merchant_prefix_path*}/{order_id}/</t> +<t>Example: taler://refund/shop.example.com/42/</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-tip" title="Action: tip"> + <t> + A tipping URI instructs the wallet to download information about a tip from + a merchant and to ask the user to accept/decline the tip. + </t> + <t> + The specific arguments of a "tip" action are: + <list style="symbols"> + <t>merchant_host: hostname of the merchant (possibly including a port number)</t> + <t>merchant_prefix_path: list of path components that identifies the path prefix of the merchant base URL</t> + <t>tip_id: identifier that uniquely identifies the tip</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: tip</t> +<t>Syntax: taler://tip/{merchant_host}{/merchant_prefix_path*}/{tip_id}/</t> +<t>Example: taler://tip/merchant.com/FIXME</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-pay-push" title="Action: pay-push"> + <t> + A pay-push URI instructs the wallet to ask the user about accepting a P2P + payment. The wallet should download, decrypt and display the underlying + contract and accept the offered money if the user agrees to the contract. + </t> + <t> + The specific arguments of a "pay-push" action are: + <list style="symbols"> + <t>exchange_host: the hostname of the exchange (possibly including a port number)</t> + <t>exchange_prefix_path: list of path components that identifies the path prefix of the exchange base URL</t> + <t>merge_priv: private key that grants the capability to take the money in the purse</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: pay-push</t> +<t>Syntax: taler://pay-push/{exchange_host}{/exchange_prefix_path*}/{merge_priv}</t> +<t>Example: taler://pay-push/exchange.example.com/KAMRGDM8FNQ82HSBVDEH8MCAF13Q0B51P4R35RFG2CBVHKGT321G</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-pay-pull" title="Action: pay-pull"> + <t> + A pay-pull URI instructs the wallet about a request made to the user to + pay an invoice (or to simply send money to another wallet). The wallet + should download, decrypt and display the underlying contract and ask the + user if they agree to pay the invoice. + </t> +<t> + The specific arguments of a "pay-pull" action are: + <list style="symbols"> + <t>exchange_host: the hostname of the exchange (possibly including a port number)</t> + <t>exchange_prefix_path: list of path components that identifies the path prefix of the exchange base URL</t> + <t>contract_priv: the private key of the peer push payment contract stored at the exchange</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: pay-pull</t> +<t>Syntax: taler://pay-pull/{exchange_host}{/exchange_prefix_path*}/{contract_priv}</t> +<t>Example: taler://pay-pull/exchange.example.com/PN3W8SN6N8V1V5MTEZRPJJ2ANY8GGZMB1MBXC7NMSRXJN6MZ5SWG</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + + +<section anchor="registry-entry-pay-template" title="Action: pay-template"> + <t> + A "pay-template" action instructs the wallet to ask its user to + manually complete an order template and submit the information + to the merchant to obtain a "pay" request. Contract fields that + are not specified in the argument list must not be submitted. + </t> + <t> + Wallets MAY to support users entering all possible fields + of a contract. Keys that MUST be supported at this time are the + "amount" and the "summary" fields. The wallet MUST validate that + the amount entered by the user is well-formed. For the amount, + it is possible that the QR code already specifies the currency + (e.g. "amount=CHF" or "amount=CHF:5") in which case the wallet + MUST only allow the user to enter an amount in that currency. + If the amount entered by the user exceeds the wallet balance, + the wallet SHOULD NOT allow the user to submit the action. + </t> + <t> + A QR code may not specify any keys for manual entry. In this case, + the wallet MUST immediately submit the request (with an empty body) + to the merchant to obtain a dynamically generated "taler://pay/" URI + based on the template. + </t> + <t> + The specific arguments of a "pay-template" action is: + <list style="symbols"> + <t>merchant_host: hostname of the merchant</t> + <t>merchant_prefix_path: list of path components that identifies the path prefix of the merchant base URL</t> + <t>template_id: identifier that uniquely identifies the template</t> + <t>key: possible contract detail to prompt the user for</t> + <t>value: default value to use for the respective key</t> + </list> + </t> +<t> + <list style="symbols"> + <t>Name: pay-template</t> + <t>Syntax: taler://pay-template/{merchant_host}{/merchant_prefix_path*}/{template_id}[?key[=value]}{&amp;key[=value]}* + </t> + <t>Example: taler://pay-template/merchant.example.com/FEGHYJY48FEGU6WETYIOIDEDE2QW3OCZVY?amount=KUDOS:5</t> + <t>Contact: N/A</t> + <t>References: [this.I-D]</t> + </list> +</t> +</section> + + +<section anchor="registry-entry-exchange" title="Action: exchange"> +<t> + An "exchange" action instructs the wallet to display a prompt to the user, asking + the user to confirm/decline adding the exchange to the list of trusted exchanges. +</t> +<t> + The specific arguments of an "exchange" action are: + <list style="symbols"> + <t>exchange_host: hostname of the exchange (possibly including a port number)</t> + <t>exchange_prefix_path: list of path components that identifies the path prefix of the exchange base URL</t> + <t>exchange_pub: the public key of the exchange</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: exchange</t> +<t>Syntax: taler://exchange/{exchange_host}{/exchange_prefix_path*}/{exchange_pub}</t> +<t>Example: taler://exchange/exchange.example.com/ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOP</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-auditor" title="Action: auditor"> +<t> + An "auditor" action instructs the wallet to display a prompt to the user, asking + the user to confirm/decline adding the auditor to the list of trusted auditors. +</t> +<t> + The specific arguments of an "auditor" action are: + <list style="symbols"> + <t>auditor_host: the hostname of the auditor (possibly including a port number)</t> + <t>auditor_prefix_path: list of path components that identifies the path prefix of the auditor base URL</t> + <t>auditor_pub: the public key of the auditor</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: auditor</t> +<t>Syntax: taler://auditor/{auditor_host}{/auditor_prefix_path*}/{auditor_pub}</t> +<t>Example: taler://auditor/auditor.example.com/ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOP</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + + + +<section anchor="registry-entry-restore" title="Action: restore"> +<t> + A "restore" action instructs the wallet to restore a wallet backup + and merge it into its current state. +</t> +<t> + The specific arguments of a "restore" action are: + <list style="symbols"> + <t>sync_rootkey: Root sync key of the wallet, used to derive the symmetric key to encrypt the backup with individual providers.</t> + <t>sync_provider_list: Comma-separated list of provider http or https URLs. If no scheme part is specified, https is assumed. Each URL is URI-encoded for all characters except "A-Z a-z 0-9 - _ . ! ~ * ' ( )" (matching the HTML5 encodeURIComponent).</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: restore</t> +<t>Syntax: taler://auditor/{sync_rootkey}/{sync_provider_list}</t> +<t>Example: taler://restore/backup.example.com/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0/prov1.example.com,prov2.example.com</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + +<section anchor="registry-entry-dev-experiment" title="Action: dev-experiment"> +<t> + An "dev-experiment" action instructs the wallet to simulate a particular + error scenario. This action can be used to test the user interface. + Wallets that are not in developer mode should not run + the specified action and instead inform the user that "dev-experiment" + actions are only supported in developer mode. +</t> +<t> + The specific arguments of a "dev-experiment" action are: + <list style="symbols"> + <t>name: specifies the specific type of dev experiment</t> + </list> +</t> +<t> +<list style="symbols"> +<t>Name: dev-experiment</t> +<t>Syntax: payto://dev-experiment/{name}</t> +<t>Example: payto://dev-experiment/xxx</t> +<t>Contact: N/A</t> +<t>References: [this.I-D]</t> +</list> +</t> +</section> + + + + +</section><!-- tracking --> + +<section anchor="security" title="Security Considerations"> +<t> + Interactive applications handling the taler URI scheme MUST NOT initiate any + unsafe payment operations prior review and confirmation from the user, + and MUST take measures to prevent clickjacking <xref target="HMW12"/>. +</t> +<t> + The authentication/authorization mechanisms and transport security services + used to process a payment encoded in a taler URI + are handled by the application and are not in scope of this document. +</t> +</section> + +<section anchor="iana" title="IANA Considerations"> + +<t> +IANA maintains a registry called the "Uniform Resource Identifier +(URI) Schemes" registry. +</t> + +<section anchor="payto-uri" title="URI Scheme Registration"> +<t> + IANA maintains the "Uniform Resource Identifier (URI) Schemes" + registry that contains an entry for the 'taler' URI scheme. IANA is + requested to update that entry to reference this document when + published as an RFC. +</t> +</section> +</section> + +<section anchor="taler-registry" title="Taler URI Actions"> +<t> + This document specifies a list of Taler URI Actions. It is + possible that future work will need to specify additional + actions. The GNUnet Assigned Numbers Authority (GANA) <xref target="GANA" /> + operates the "taler-uri-actions" registry to track + the following information for each payment target type: +<list style="symbols"> +<t>Name: The name of the action (case insensitive ASCII string, restricted to alphanumeric characters, +dots and dashes)</t> +<t>Contact: The contact information of a person to contact for further information</t> +<t>References: Optionally, references describing the payment target type (such as an RFC) and target-specific options, + or references describing the payment system underlying the payment target type.</t> +</list> +</t> +<t> + The entries that have been made for the "taler-uri-actions" + defined in this document are as follows: +</t> +<figure> + <artwork> + Name | Contact | Reference + ---------------+-------------------------+------------ + pay | N/A | [This.I-D] + withdraw | N/A | [This.I-D] + refund | N/A | [This.I-D] + tip | N/A | [This.I-D] + pay-pull | N/A | [This.I-D] + pay-push | N/A | [This.I-D] + pay-template | N/A | [This.I-D] + exchange | N/A | [This.I-D] + auditor | N/A | [This.I-D] + restore | N/A | [This.I-D] + dev-experiment | N/A | [This.I-D] + </artwork> +</figure> + +</section><!-- taler-registry --> + +</middle> + +<back> + + <references title="Normative References"> + + &RFC2119; + + &RFC3986; + + &RFC5234; + + &RFC8126; + + &RFC8174; + + + </references> + + <references title="Informational References"> + + <reference anchor="HMW12" target="https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final39.pdf"> + <front> + <title>Clickjacking: Attacks and Defenses</title> + <author initials="L.S." surname="Huang" + fullname="Lin-Shung Huang"> + </author> + <author initials="A." surname="Moshchuk" + fullname="Alexander, Moshchuk"> + </author> + <author initials="H.J." surname="Wang" + fullname="Helen J. Wang"> + </author> + <author initials="S." surname="Schecter" + fullname="Stuart Schecter"> + </author> + <author initials="C." surname="Jackson" + fullname="Collin Jackson"> + </author> + + <date month="January" year="2012" /> + </front> + </reference> + + <reference anchor="GANA" target="https://gana.gnunet.org/"> + <front> + <title>GNUnet Assigned Numbers Authority (GANA)</title> + <author><organization>GNUnet e.V.</organization> + </author> + <date month="April" year="2020" /> + </front> + </reference> + + </references> + +<!-- Change Log +v00 2022-11-11 CG Initial version + --> +</back> +</rfc> diff --git a/metadata.min.js b/metadata.min.js @@ -0,0 +1 @@ +async function addMetadata(){try{const e=document.styleSheets[0].cssRules;for(let t=0;t<e.length;t++)if(/#identifiers/.exec(e[t].selectorText)){const a=e[t].cssText.replace("#identifiers","#external-updates");document.styleSheets[0].insertRule(a,document.styleSheets[0].cssRules.length)}}catch(e){console.log(e)}const e=document.getElementById("external-metadata");if(e)try{var t,a="",o=function(e){const t=document.getElementsByTagName("meta");for(let a=0;a<t.length;a++)if(t[a].getAttribute("name")===e)return t[a].getAttribute("content");return""}("rfc.number");if(o){t="https://www.rfc-editor.org/rfc/rfc"+o+".json";try{const e=await fetch(t);a=await e.json()}catch(e){t=document.URL.indexOf("html")>=0?document.URL.replace(/html$/,"json"):document.URL+".json";const o=await fetch(t);a=await o.json()}}if(!a)return;e.style.display="block";const s="",d="https://datatracker.ietf.org/doc",n="https://datatracker.ietf.org/ipr/search",c="https://www.rfc-editor.org/info",l=a.doc_id.toLowerCase(),i=a.doc_id.slice(0,3).toLowerCase(),f=a.doc_id.slice(3).replace(/^0+/,""),u={status:"Status",obsoletes:"Obsoletes",obsoleted_by:"Obsoleted By",updates:"Updates",updated_by:"Updated By",see_also:"See Also",errata_url:"Errata"};let h="<dl style='overflow:hidden' id='external-updates'>";["status","obsoletes","obsoleted_by","updates","updated_by","see_also","errata_url"].forEach(e=>{if("status"==e){a[e]=a[e].toLowerCase();var t=a[e].split(" "),o=t.length,w="",p=1;for(let e=0;e<o;e++)p<o?w=w+r(t[e])+" ":w+=r(t[e]),p++;a[e]=w}else if("obsoletes"==e||"obsoleted_by"==e||"updates"==e||"updated_by"==e){var g,m="",b=1;g=a[e].length;for(let t=0;t<g;t++)a[e][t]&&(a[e][t]=String(a[e][t]).toLowerCase(),m=b<g?m+"<a href='"+s+"/rfc/".concat(a[e][t])+"'>"+a[e][t].slice(3)+"</a>, ":m+"<a href='"+s+"/rfc/".concat(a[e][t])+"'>"+a[e][t].slice(3)+"</a>",b++);a[e]=m}else if("see_also"==e){var y,L="",C=1;y=a[e].length;for(let t=0;t<y;t++)if(a[e][t]){a[e][t]=String(a[e][t]);var _=a[e][t].slice(0,3),v=a[e][t].slice(3).replace(/^0+/,"");L=C<y?"RFC"!=_?L+"<a href='"+s+"/info/"+_.toLowerCase().concat(v.toLowerCase())+"'>"+_+" "+v+"</a>, ":L+"<a href='"+s+"/info/"+_.toLowerCase().concat(v.toLowerCase())+"'>"+v+"</a>, ":"RFC"!=_?L+"<a href='"+s+"/info/"+_.toLowerCase().concat(v.toLowerCase())+"'>"+_+" "+v+"</a>":L+"<a href='"+s+"/info/"+_.toLowerCase().concat(v.toLowerCase())+"'>"+v+"</a>",C++}a[e]=L}else if("errata_url"==e){var R="";R=a[e]?R+"<a href='"+a[e]+"'>Errata exist</a> | <a href='"+d+"/"+l+"'>Datatracker</a>| <a href='"+n+"/?"+i+"="+f+"&submit="+i+"'>IPR</a> | <a href='"+c+"/"+l+"'>Info page</a>":"<a href='"+d+"/"+l+"'>Datatracker</a> | <a href='"+n+"/?"+i+"="+f+"&submit="+i+"'>IPR</a> | <a href='"+c+"/"+l+"'>Info page</a>",a[e]=R}""!=a[e]?"Errata"==u[e]?h+=`<dt>More info:</dt><dd>${a[e]}</dd>`:h+=`<dt>${u[e]}:</dt><dd>${a[e]}</dd>`:"Errata"==u[e]&&(h+=`<dt>More info:</dt><dd>${a[e]}</dd>`)}),h+="</dl>",e.innerHTML=h}catch(e){console.log(e)}else console.log("Could not locate metadata <div> element");function r(e){return e.charAt(0).toUpperCase()+e.slice(1)}}window.removeEventListener("load",addMetadata),window.addEventListener("load",addMetadata); +\ No newline at end of file diff --git a/style.css b/style.css @@ -0,0 +1,1145 @@ +/* This is the built-in CSS used by xml2rfc without Google Fonts. */ + +/* + + NOTE: Changes at the bottom of this file overrides some earlier settings. + + Once the style has stabilized and has been adopted as an official RFC style, + this can be consolidated so that style settings occur only in one place, but + for now the contents of this file consists first of the initial CSS work as + provided to the RFC Formatter (xml2rfc) work, followed by itemized and + commented changes found necssary during the development of the v3 + formatters. + +*/ + +/* fonts */ +/* @import url('https://fonts.googleapis.com/css?family=Noto+Sans'); /\* Sans-serif *\/ */ +/* @import url('https://fonts.googleapis.com/css?family=Noto+Serif'); /\* Serif (print) *\/ */ +/* @import url('https://fonts.googleapis.com/css?family=Roboto+Mono'); /\* Monospace *\/ */ + +@viewport { + zoom: 1.0; + width: extend-to-zoom; +} +@-ms-viewport { + width: extend-to-zoom; + zoom: 1.0; +} +/* general and mobile first */ +html { +} +body { + max-width: 90%; + margin: 1.5em auto; + color: #222; + background-color: #fff; + font-size: 14px; + font-family: 'Noto Sans', Arial, Helvetica, sans-serif; + line-height: 1.6; + scroll-behavior: smooth; +} +.ears { + display: none; +} + +/* headings */ +#title, h1, h2, h3, h4, h5, h6 { + margin: 1em 0 0.5em; + font-weight: bold; + line-height: 1.3; +} +#title { + clear: both; + border-bottom: 1px solid #ddd; + margin: 0 0 0.5em 0; + padding: 1em 0 0.5em; +} +.author { + padding-bottom: 4px; +} +h1 { + font-size: 26px; + margin: 1em 0; +} +h2 { + font-size: 22px; + margin-top: -20px; /* provide offset for in-page anchors */ + padding-top: 33px; +} +h3 { + font-size: 18px; + margin-top: -36px; /* provide offset for in-page anchors */ + padding-top: 42px; +} +h4 { + font-size: 16px; + margin-top: -36px; /* provide offset for in-page anchors */ + padding-top: 42px; +} +h5, h6 { + font-size: 14px; +} +#n-copyright-notice { + border-bottom: 1px solid #ddd; + padding-bottom: 1em; + margin-bottom: 1em; +} +/* general structure */ +p { + padding: 0; + margin: 0 0 1em 0; + text-align: left; +} +div, span { + position: relative; +} +div { + margin: 0; +} +.alignRight.art-text { + background-color: #f9f9f9; + border: 1px solid #eee; + border-radius: 3px; + padding: 1em 1em 0; + margin-bottom: 1.5em; +} +.alignRight.art-text pre { + padding: 0; +} +.alignRight { + margin: 1em 0; +} +.alignRight > *:first-child { + border: none; + margin: 0; + float: right; + clear: both; +} +.alignRight > *:nth-child(2) { + clear: both; + display: block; + border: none; +} +svg { + display: block; +} +.alignCenter.art-text { + background-color: #f9f9f9; + border: 1px solid #eee; + border-radius: 3px; + padding: 1em 1em 0; + margin-bottom: 1.5em; +} +.alignCenter.art-text pre { + padding: 0; +} +.alignCenter { + margin: 1em 0; +} +.alignCenter > *:first-child { + border: none; + /* this isn't optimal, but it's an existence proof. PrinceXML doesn't + support flexbox yet. + */ + display: table; + margin: 0 auto; +} + +/* lists */ +ol, ul { + padding: 0; + margin: 0 0 1em 2em; +} +ol ol, ul ul, ol ul, ul ol { + margin-left: 1em; +} +li { + margin: 0 0 0.25em 0; +} +.ulCompact li { + margin: 0; +} +ul.empty, .ulEmpty { + list-style-type: none; +} +ul.empty li, .ulEmpty li { + margin-top: 0.5em; +} +ul.ulBare, li.ulBare { + margin-left: 0em !important; +} +ul.compact, .ulCompact, +ol.compact, .olCompact { + line-height: 100%; + margin: 0 0 0 2em; +} + +/* definition lists */ +dl { +} +dl > dt { + float: left; + margin-right: 1em; +} +/* +dl.nohang > dt { + float: none; +} +*/ +dl > dd { + margin-bottom: .8em; + min-height: 1.3em; +} +dl.compact > dd, .dlCompact > dd { + margin-bottom: 0em; +} +dl > dd > dl { + margin-top: 0.5em; + margin-bottom: 0em; +} + +/* links */ +a { + text-decoration: none; +} +a[href] { + color: #22e; /* Arlen: WCAG 2019 */ +} +a[href]:hover { + background-color: #f2f2f2; +} +figcaption a[href], +a[href].selfRef { + color: #222; +} +/* XXX probably not this: +a.selfRef:hover { + background-color: transparent; + cursor: default; +} */ + +/* Figures */ +tt, code, pre, code { + background-color: #f9f9f9; + font-family: 'Roboto Mono', monospace; +} +pre { + border: 1px solid #eee; + margin: 0; + padding: 1em; +} +img { + max-width: 100%; +} +figure { + margin: 0; +} +figure blockquote { + margin: 0.8em 0.4em 0.4em; +} +figcaption { + font-style: italic; + margin: 0 0 1em 0; +} +@media screen { + pre { + overflow-x: auto; + max-width: 100%; + max-width: calc(100% - 22px); + } +} + +/* aside, blockquote */ +aside, blockquote { + margin-left: 0; + padding: 1.2em 2em; +} +blockquote { + background-color: #f9f9f9; + color: #111; /* Arlen: WCAG 2019 */ + border: 1px solid #ddd; + border-radius: 3px; + margin: 1em 0; +} +cite { + display: block; + text-align: right; + font-style: italic; +} + +/* tables */ +table { + width: 100%; + margin: 0 0 1em; + border-collapse: collapse; + border: 1px solid #eee; +} +th, td { + text-align: left; + vertical-align: top; + padding: 0.5em 0.75em; +} +th { + text-align: left; + background-color: #e9e9e9; +} +tr:nth-child(2n+1) > td { + background-color: #f5f5f5; +} +table caption { + font-style: italic; + margin: 0; + padding: 0; + text-align: left; +} +table p { + /* XXX to avoid bottom margin on table row signifiers. If paragraphs should + be allowed within tables more generally, it would be far better to select on a class. */ + margin: 0; +} + +/* pilcrow */ +a.pilcrow { + color: #666; /* Arlen: AHDJ 2019 */ + text-decoration: none; + visibility: hidden; + user-select: none; + -ms-user-select: none; + -o-user-select:none; + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; +} +@media screen { + aside:hover > a.pilcrow, + p:hover > a.pilcrow, + blockquote:hover > a.pilcrow, + div:hover > a.pilcrow, + li:hover > a.pilcrow, + pre:hover > a.pilcrow { + visibility: visible; + } + a.pilcrow:hover { + background-color: transparent; + } +} + +/* misc */ +hr { + border: 0; + border-top: 1px solid #eee; +} +.bcp14 { + font-variant: small-caps; +} + +.role { + font-variant: all-small-caps; +} + +/* info block */ +#identifiers { + margin: 0; + font-size: 0.9em; +} +#identifiers dt { + width: 3em; + clear: left; +} +#identifiers dd { + float: left; + margin-bottom: 0; +} +/* Fix PDF info block run off issue */ +@media print { + #identifiers dd { + float: none; + } +} +#identifiers .authors .author { + display: inline-block; + margin-right: 1.5em; +} +#identifiers .authors .org { + font-style: italic; +} + +/* The prepared/rendered info at the very bottom of the page */ +.docInfo { + color: #666; /* Arlen: WCAG 2019 */ + font-size: 0.9em; + font-style: italic; + margin-top: 2em; +} +.docInfo .prepared { + float: left; +} +.docInfo .prepared { + float: right; +} + +/* table of contents */ +#toc { + padding: 0.75em 0 2em 0; + margin-bottom: 1em; +} +nav.toc ul { + margin: 0 0.5em 0 0; + padding: 0; + list-style: none; +} +nav.toc li { + line-height: 1.3em; + margin: 0.75em 0; + padding-left: 1.2em; + text-indent: -1.2em; +} +/* references */ +.references dt { + text-align: right; + font-weight: bold; + min-width: 7em; +} +.references dd { + margin-left: 8em; + overflow: auto; +} + +.refInstance { + margin-bottom: 1.25em; +} + +.references .ascii { + margin-bottom: 0.25em; +} + +/* index */ +.index ul { + margin: 0 0 0 1em; + padding: 0; + list-style: none; +} +.index ul ul { + margin: 0; +} +.index li { + margin: 0; + text-indent: -2em; + padding-left: 2em; + padding-bottom: 5px; +} +.indexIndex { + margin: 0.5em 0 1em; +} +.index a { + font-weight: 700; +} +/* make the index two-column on all but the smallest screens */ +@media (min-width: 600px) { + .index ul { + -moz-column-count: 2; + -moz-column-gap: 20px; + } + .index ul ul { + -moz-column-count: 1; + -moz-column-gap: 0; + } +} + +/* authors */ +address.vcard { + font-style: normal; + margin: 1em 0; +} + +address.vcard .nameRole { + font-weight: 700; + margin-left: 0; +} +address.vcard .label { + font-family: "Noto Sans",Arial,Helvetica,sans-serif; + margin: 0.5em 0; +} +address.vcard .type { + display: none; +} +.alternative-contact { + margin: 1.5em 0 1em; +} +hr.addr { + border-top: 1px dashed; + margin: 0; + color: #ddd; + max-width: calc(100% - 16px); +} + +/* temporary notes */ +.rfcEditorRemove::before { + position: absolute; + top: 0.2em; + right: 0.2em; + padding: 0.2em; + content: "The RFC Editor will remove this note"; + color: #9e2a00; /* Arlen: WCAG 2019 */ + background-color: #ffd; /* Arlen: WCAG 2019 */ +} +.rfcEditorRemove { + position: relative; + padding-top: 1.8em; + background-color: #ffd; /* Arlen: WCAG 2019 */ + border-radius: 3px; +} +.cref { + background-color: #ffd; /* Arlen: WCAG 2019 */ + padding: 2px 4px; +} +.crefSource { + font-style: italic; +} +/* alternative layout for smaller screens */ +@media screen and (max-width: 1023px) { + body { + padding-top: 2em; + } + #title { + padding: 1em 0; + } + h1 { + font-size: 24px; + } + h2 { + font-size: 20px; + margin-top: -18px; /* provide offset for in-page anchors */ + padding-top: 38px; + } + #identifiers dd { + max-width: 60%; + } + #toc { + position: fixed; + z-index: 2; + top: 0; + right: 0; + padding: 0; + margin: 0; + background-color: inherit; + border-bottom: 1px solid #ccc; + } + #toc h2 { + margin: -1px 0 0 0; + padding: 4px 0 4px 6px; + padding-right: 1em; + min-width: 190px; + font-size: 1.1em; + text-align: right; + background-color: #444; + color: white; + cursor: pointer; + } + #toc h2::before { /* css hamburger */ + float: right; + position: relative; + width: 1em; + height: 1px; + left: -164px; + margin: 6px 0 0 0; + background: white none repeat scroll 0 0; + box-shadow: 0 4px 0 0 white, 0 8px 0 0 white; + content: ""; + } + #toc nav { + display: none; + padding: 0.5em 1em 1em; + overflow: auto; + height: calc(100vh - 48px); + border-left: 1px solid #ddd; + } +} + +/* alternative layout for wide screens */ +@media screen and (min-width: 1024px) { + body { + max-width: 724px; + margin: 42px auto; + padding-left: 1.5em; + padding-right: 29em; + } + #toc { + position: fixed; + top: 42px; + right: 42px; + width: 25%; + margin: 0; + padding: 0 1em; + z-index: 1; + } + #toc h2 { + border-top: none; + border-bottom: 1px solid #ddd; + font-size: 1em; + font-weight: normal; + margin: 0; + padding: 0.25em 1em 1em 0; + } + #toc nav { + display: block; + height: calc(90vh - 84px); + bottom: 0; + padding: 0.5em 0 0; + overflow: auto; + } + img { /* future proofing */ + max-width: 100%; + height: auto; + } +} + +/* pagination */ +@media print { + body { + + width: 100%; + } + p { + orphans: 3; + widows: 3; + } + #n-copyright-notice { + border-bottom: none; + } + #toc, #n-introduction { + page-break-before: always; + } + #toc { + border-top: none; + padding-top: 0; + } + figure, pre { + page-break-inside: avoid; + } + figure { + overflow: scroll; + } + h1, h2, h3, h4, h5, h6 { + page-break-after: avoid; + } + h2+*, h3+*, h4+*, h5+*, h6+* { + page-break-before: avoid; + } + pre { + white-space: pre-wrap; + word-wrap: break-word; + font-size: 10pt; + } + table { + border: 1px solid #ddd; + } + td { + border-top: 1px solid #ddd; + } +} + +/* This is commented out here, as the string-set: doesn't + pass W3C validation currently */ +/* +.ears thead .left { + string-set: ears-top-left content(); +} + +.ears thead .center { + string-set: ears-top-center content(); +} + +.ears thead .right { + string-set: ears-top-right content(); +} + +.ears tfoot .left { + string-set: ears-bottom-left content(); +} + +.ears tfoot .center { + string-set: ears-bottom-center content(); +} + +.ears tfoot .right { + string-set: ears-bottom-right content(); +} +*/ + +@page :first { + padding-top: 0; + @top-left { + content: normal; + border: none; + } + @top-center { + content: normal; + border: none; + } + @top-right { + content: normal; + border: none; + } +} + +@page { + size: A4; + margin-bottom: 45mm; + padding-top: 20px; + /* The follwing is commented out here, but set appropriately by in code, as + the content depends on the document */ + /* + @top-left { + content: 'Internet-Draft'; + vertical-align: bottom; + border-bottom: solid 1px #ccc; + } + @top-left { + content: string(ears-top-left); + vertical-align: bottom; + border-bottom: solid 1px #ccc; + } + @top-center { + content: string(ears-top-center); + vertical-align: bottom; + border-bottom: solid 1px #ccc; + } + @top-right { + content: string(ears-top-right); + vertical-align: bottom; + border-bottom: solid 1px #ccc; + } + @bottom-left { + content: string(ears-bottom-left); + vertical-align: top; + border-top: solid 1px #ccc; + } + @bottom-center { + content: string(ears-bottom-center); + vertical-align: top; + border-top: solid 1px #ccc; + } + @bottom-right { + content: '[Page ' counter(page) ']'; + vertical-align: top; + border-top: solid 1px #ccc; + } + */ + +} + +/* Changes introduced to fix issues found during implementation */ +/* Make sure links are clickable even if overlapped by following H* */ +a { + z-index: 2; +} +/* Separate body from document info even without intervening H1 */ +section { + clear: both; +} + + +/* Top align author divs, to avoid names without organization dropping level with org names */ +.author { + vertical-align: top; +} + +/* Leave room in document info to show Internet-Draft on one line */ +#identifiers dt { + width: 8em; +} + +/* Don't waste quite as much whitespace between label and value in doc info */ +#identifiers dd { + margin-left: 1em; +} + +/* Give floating toc a background color (needed when it's a div inside section */ +#toc { + background-color: white; +} + +/* Make the collapsed ToC header render white on gray also when it's a link */ +@media screen and (max-width: 1023px) { + #toc h2 a, + #toc h2 a:link, + #toc h2 a:focus, + #toc h2 a:hover, + #toc a.toplink, + #toc a.toplink:hover { + color: white; + background-color: #444; + text-decoration: none; + } +} + +/* Give the bottom of the ToC some whitespace */ +@media screen and (min-width: 1024px) { + #toc { + padding: 0 0 1em 1em; + } +} + +/* Style section numbers with more space between number and title */ +.section-number { + padding-right: 0.5em; +} + +/* prevent monospace from becoming overly large */ +tt, code, pre, code { + font-size: 95%; +} + +/* Fix the height/width aspect for ascii art*/ +pre.sourcecode, +.art-text pre { + line-height: 1.12; +} + + +/* Add styling for a link in the ToC that points to the top of the document */ +a.toplink { + float: right; + margin-right: 0.5em; +} + +/* Fix the dl styling to match the RFC 7992 attributes */ +dl > dt, +dl.dlParallel > dt { + float: left; + margin-right: 1em; +} +dl.dlNewline > dt { + float: none; +} + +/* Provide styling for table cell text alignment */ +table td.text-left, +table th.text-left { + text-align: left; +} +table td.text-center, +table th.text-center { + text-align: center; +} +table td.text-right, +table th.text-right { + text-align: right; +} + +/* Make the alternative author contact informatio look less like just another + author, and group it closer with the primary author contact information */ +.alternative-contact { + margin: 0.5em 0 0.25em 0; +} +address .non-ascii { + margin: 0 0 0 2em; +} + +/* With it being possible to set tables with alignment + left, center, and right, { width: 100%; } does not make sense */ +table { + width: auto; +} + +/* Avoid reference text that sits in a block with very wide left margin, + because of a long floating dt label.*/ +.references dd { + overflow: visible; +} + +/* Control caption placement */ +caption { + caption-side: bottom; +} + +/* Limit the width of the author address vcard, so names in right-to-left + script don't end up on the other side of the page. */ + +address.vcard { + max-width: 30em; + margin-right: auto; +} + +/* For address alignment dependent on LTR or RTL scripts */ +address div.left { + text-align: left; +} +address div.right { + text-align: right; +} + +/* Provide table alignment support. We can't use the alignX classes above + since they do unwanted things with caption and other styling. */ +table.right { + margin-left: auto; + margin-right: 0; +} +table.center { + margin-left: auto; + margin-right: auto; +} +table.left { + margin-left: 0; + margin-right: auto; +} + +/* Give the table caption label the same styling as the figcaption */ +caption a[href] { + color: #222; +} + +@media print { + .toplink { + display: none; + } + + /* avoid overwriting the top border line with the ToC header */ + #toc { + padding-top: 1px; + } + + /* Avoid page breaks inside dl and author address entries */ + .vcard { + page-break-inside: avoid; + } + +} +/* Tweak the bcp14 keyword presentation */ +.bcp14 { + font-variant: small-caps; + font-weight: bold; + font-size: 0.9em; +} +/* Tweak the invisible space above H* in order not to overlay links in text above */ + h2 { + margin-top: -18px; /* provide offset for in-page anchors */ + padding-top: 31px; + } + h3 { + margin-top: -18px; /* provide offset for in-page anchors */ + padding-top: 24px; + } + h4 { + margin-top: -18px; /* provide offset for in-page anchors */ + padding-top: 24px; + } +/* Float artwork pilcrow to the right */ +@media screen { + .artwork a.pilcrow { + display: block; + line-height: 0.7; + margin-top: 0.15em; + } +} +/* Make pilcrows on dd visible */ +@media screen { + dd:hover > a.pilcrow { + visibility: visible; + } +} +/* Make the placement of figcaption match that of a table's caption + by removing the figure's added bottom margin */ +.alignLeft.art-text, +.alignCenter.art-text, +.alignRight.art-text { + margin-bottom: 0; +} +.alignLeft, +.alignCenter, +.alignRight { + margin: 1em 0 0 0; +} +/* In print, the pilcrow won't show on hover, so prevent it from taking up space, + possibly even requiring a new line */ +@media print { + a.pilcrow { + display: none; + } +} +/* Styling for the external metadata */ +div#external-metadata { + background-color: #eee; + padding: 0.5em; + margin-bottom: 0.5em; + display: none; +} +div#internal-metadata { + padding: 0.5em; /* to match the external-metadata padding */ +} +/* Styling for title RFC Number */ +h1#rfcnum { + clear: both; + margin: 0 0 -1em; + padding: 1em 0 0 0; +} +/* Make .olPercent look the same as <ol><li> */ +dl.olPercent > dd { + margin-bottom: 0.25em; + min-height: initial; +} +/* Give aside some styling to set it apart */ +aside { + border-left: 1px solid #ddd; + margin: 1em 0 1em 2em; + padding: 0.2em 2em; +} +aside > dl, +aside > ol, +aside > ul, +aside > table, +aside > p { + margin-bottom: 0.5em; +} +/* Additional page break settings */ +@media print { + figcaption, table caption { + page-break-before: avoid; + } +} +/* Font size adjustments for print */ +@media print { + body { font-size: 10pt; line-height: normal; max-width: 96%; } + h1 { font-size: 1.72em; padding-top: 1.5em; } /* 1*1.2*1.2*1.2 */ + h2 { font-size: 1.44em; padding-top: 1.5em; } /* 1*1.2*1.2 */ + h3 { font-size: 1.2em; padding-top: 1.5em; } /* 1*1.2 */ + h4 { font-size: 1em; padding-top: 1.5em; } + h5, h6 { font-size: 1em; margin: initial; padding: 0.5em 0 0.3em; } +} +/* Sourcecode margin in print, when there's no pilcrow */ +@media print { + .artwork, + .sourcecode { + margin-bottom: 1em; + } +} +/* Avoid narrow tables forcing too narrow table captions, which may render badly */ +table { + min-width: 20em; +} +/* ol type a */ +ol.type-a { list-style-type: lower-alpha; } +ol.type-A { list-style-type: upper-alpha; } +ol.type-i { list-style-type: lower-roman; } +ol.type-I { list-style-type: lower-roman; } +/* Apply the print table and row borders in general, on request from the RPC, +and increase the contrast between border and odd row background sligthtly */ +table { + border: 1px solid #ddd; +} +td { + border-top: 1px solid #ddd; +} +tr:nth-child(2n+1) > td { + background-color: #f8f8f8; +} +/* Use style rules to govern display of the TOC. */ +@media screen and (max-width: 1023px) { + #toc nav { display: none; } + #toc.active nav { display: block; } +} +/* Add support for keepWithNext */ +.keepWithNext { + break-after: avoid-page; + break-after: avoid-page; +} +/* Add support for keepWithPrevious */ +.keepWithPrevious { + break-before: avoid-page; +} +/* Change the approach to avoiding breaks inside artwork etc. */ +figure, pre, table, .artwork, .sourcecode { + break-before: auto; + break-after: auto; +} +/* Avoid breaks between <dt> and <dd> */ +dl { + break-before: auto; + break-inside: auto; +} +dt { + break-before: auto; + break-after: avoid-page; +} +dd { + break-before: avoid-page; + break-after: auto; + orphans: 3; + widows: 3 +} +span.break, dd.break { + margin-bottom: 0; + min-height: 0; + break-before: auto; + break-inside: auto; + break-after: auto; +} +/* Undo break-before ToC */ +@media print { + #toc { + break-before: auto; + } +} +/* Text in compact lists should not get extra bottim margin space, + since that would makes the list not compact */ +ul.compact p, .ulCompact p, +ol.compact p, .olCompact p { + margin: 0; +} +/* But the list as a whole needs the extra space at the end */ +section ul.compact, +section .ulCompact, +section ol.compact, +section .olCompact { + margin-bottom: 1em; /* same as p not within ul.compact etc. */ +} +/* The tt and code background above interferes with for instance table cell + backgrounds. Changed to something a bit more selective. */ +tt, code { + background-color: transparent; +} +p tt, p code, li tt, li code { + background-color: #f8f8f8; +} +/* Tweak the pre margin -- 0px doesn't come out well */ +pre { + margin-top: 0.5px; +} +/* Tweak the comact list text */ +ul.compact, .ulCompact, +ol.compact, .olCompact, +dl.compact, .dlCompact { + line-height: normal; +} +/* Don't add top margin for nested lists */ +li > ul, li > ol, li > dl, +dd > ul, dd > ol, dd > dl, +dl > dd > dl { + margin-top: initial; +} +/* Elements that should not be rendered on the same line as a <dt> */ +/* This should match the element list in writer.text.TextWriter.render_dl() */ +dd > div.artwork:first-child, +dd > aside:first-child, +dd > figure:first-child, +dd > ol:first-child, +dd > div:first-child > pre.sourcecode, +dd > table:first-child, +dd > ul:first-child { + clear: left; +} +/* fix for weird browser behaviour when <dd/> is empty */ +dt+dd:empty::before{ + content: "\00a0"; +} +/* Make paragraph spacing inside <li> smaller than in body text, to fit better within the list */ +li > p { + margin-bottom: 0.5em +} +/* Don't let p margin spill out from inside list items */ +li > p:last-of-type { + margin-bottom: 0; +}