mobile friendly

This commit is contained in:
Sebastian 2023-07-12 15:42:27 -03:00
parent 8c2fed4e1c
commit b7823407c0
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
11 changed files with 283 additions and 332 deletions

View File

@ -63,20 +63,29 @@ export function LangSelectorLikePy(): VNode {
}, []); }, []);
return ( return (
<Fragment> <Fragment>
<button <a
href="#"
class="pure-button"
name="language" name="language"
onClick={(ev) => { onClick={(ev) => {
ev.preventDefault();
setHidden((h) => !h); setHidden((h) => !h);
ev.stopPropagation(); ev.stopPropagation();
}} }}
> >
{getLangName(lang)} {getLangName(lang)}
</button> </a>
<div id="lang" class={hidden ? "hide" : ""}> <div
id="lang"
class={hidden ? "hide" : ""}
style={{
display: "inline-block",
}}
>
<div style="position: relative; overflow: visible;"> <div style="position: relative; overflow: visible;">
<div <div
class="nav" class="nav"
style="position: absolute; max-height: 60vh; overflow-y: scroll" style="position: absolute; max-height: 60vh; overflow-y: auto; margin-left: -120px; margin-top: 20px"
> >
{Object.keys(messages) {Object.keys(messages)
.filter((l) => l !== lang) .filter((l) => l !== lang)

View File

@ -683,8 +683,14 @@ export function ShowAccountDetails({
onChange={(a) => setSubmitAccount(a)} onChange={(a) => setSubmitAccount(a)}
/> />
<p> <p class="buttons-account">
<div style={{ display: "flex", justifyContent: "space-between" }}> <div
style={{
display: "flex",
justifyContent: "space-between",
flexFlow: "wrap-reverse",
}}
>
<div> <div>
{onClear ? ( {onClear ? (
<input <input

View File

@ -49,7 +49,6 @@ function MaybeBusinessButton({
const result = useBusinessAccountDetails(account); const result = useBusinessAccountDetails(account);
if (!result.ok) return <Fragment />; if (!result.ok) return <Fragment />;
return ( return (
<div class="some-space">
<a <a
href="#" href="#"
class="pure-button pure-button-primary" class="pure-button pure-button-primary"
@ -58,7 +57,6 @@ function MaybeBusinessButton({
onClick(); onClick();
}} }}
>{i18n.str`Business Profile`}</a> >{i18n.str`Business Profile`}</a>
</div>
); );
} }
@ -88,7 +86,7 @@ export function BankFrame({
style="display: flex; flex-direction: row; justify-content: space-between;" style="display: flex; flex-direction: row; justify-content: space-between;"
> >
<a href="#main" class="skip">{i18n.str`Skip to main content`}</a> <a href="#main" class="skip">{i18n.str`Skip to main content`}</a>
<div style="max-width: 50em; margin-left: 2em;"> <div style="max-width: 50em; margin-left: 2em; margin-right: 2em;">
<h1> <h1>
<span class="it"> <span class="it">
<a href="/">{bankUiSettings.bankName}</a> <a href="/">{bankUiSettings.bankName}</a>
@ -112,35 +110,21 @@ export function BankFrame({
</p>, </p>,
)} )}
</div> </div>
<a href="https://taler.net/">
<img
src={talerLogo}
alt={i18n.str`Taler logo`}
height="100"
width="224"
style="margin: 2em 2em"
/>
</a>
</header> </header>
<div style="display:flex; flex-direction: column;" class="navcontainer"> <div style="display:flex; flex-direction: column;" class="navcontainer">
<nav class="demolist"> <nav class="demolist">
{maybeDemoContent(<Fragment>{demo_sites}</Fragment>)} {maybeDemoContent(<Fragment>{demo_sites}</Fragment>)}
<div class="right">
<LangSelector />
</div>
</nav>
</div>
<section id="main" class="content">
<StatusBanner />
{backend.state.status === "loggedIn" ? ( {backend.state.status === "loggedIn" ? (
<div class="top-right"> <Fragment>
{goToBusinessAccount && !backend.state.isUserAdministrator ? ( {goToBusinessAccount && !backend.state.isUserAdministrator ? (
<MaybeBusinessButton <MaybeBusinessButton
account={backend.state.username} account={backend.state.username}
onClick={goToBusinessAccount} onClick={goToBusinessAccount}
/> />
) : undefined} ) : undefined}
<div class="some-space">
<LangSelector />
<a <a
href="#" href="#"
class="pure-button logout-button" class="pure-button logout-button"
@ -149,13 +133,15 @@ export function BankFrame({
updateSettings("currentWithdrawalOperationId", undefined); updateSettings("currentWithdrawalOperationId", undefined);
}} }}
>{i18n.str`Logout`}</a> >{i18n.str`Logout`}</a>
</Fragment>
) : undefined}
</nav>
</div> </div>
</div> <section id="main" class="content">
) : null} <StatusBanner />
{children} {children}
</section> </section>
<section id="footer" class="footer"> <section id="footer" class="footer">
<div class="footer">
<hr /> <hr />
<div> <div>
<p> <p>
@ -168,7 +154,6 @@ export function BankFrame({
Copyright &copy; 2014&mdash;2022 Taler Systems SA. {versionText}{" "} Copyright &copy; 2014&mdash;2022 Taler Systems SA. {versionText}{" "}
<TestingTag /> <TestingTag />
</p> </p>
</div>
</section> </section>
</Fragment> </Fragment>
); );
@ -192,7 +177,7 @@ export function ErrorBannerFloat({
<div <div
style={{ style={{
position: "fixed", position: "fixed",
top: 0, top: 10,
zIndex: 200, zIndex: 200,
width: "90%", width: "90%",
}} }}
@ -262,7 +247,7 @@ function StatusBanner(): VNode | null {
<div <div
style={{ style={{
position: "fixed", position: "fixed",
top: 0, top: 10,
zIndex: 200, zIndex: 200,
width: "90%", width: "90%",
}} }}

View File

@ -47,6 +47,7 @@ import { LoginForm } from "./LoginForm.js";
import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js"; import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js";
import { handleNotOkResult } from "./HomePage.js"; import { handleNotOkResult } from "./HomePage.js";
import { ErrorMessage, notifyInfo } from "../hooks/notification.js"; import { ErrorMessage, notifyInfo } from "../hooks/notification.js";
import { Amount } from "./WalletWithdrawForm.js";
interface Props { interface Props {
onClose: () => void; onClose: () => void;
@ -345,34 +346,23 @@ function CreateCashout({
? i18n.str`Amount to send` ? i18n.str`Amount to send`
: i18n.str`Amount to receive`} : i18n.str`Amount to receive`}
</label> </label>
<div style={{ width: "max-content" }}> <div style={{ display: "flex" }}>
<input <Amount
type="text" currency={amount.currency}
readonly value={form.amount}
class="currency-indicator" onChange={(v) => {
size={amount?.currency.length ?? 0} form.amount = v;
maxLength={amount?.currency.length ?? 0}
tabIndex={-1}
value={amount?.currency ?? ""}
/>
&nbsp;
<input
type="number"
// ref={ref}
id="withdraw-amount"
name="withdraw-amount"
value={form.amount ?? ""}
onChange={(e): void => {
form.amount = e.currentTarget.value;
updateForm(structuredClone(form)); updateForm(structuredClone(form));
}} }}
error={errors?.amount}
/> />
&nbsp; <label class="toggle" style={{ marginLeft: 4, marginTop: 0 }}>
<label class="toggle">
<input <input
class="toggle-checkbox" class="toggle-checkbox"
type="checkbox" type="checkbox"
name="asd"
onChange={(e): void => { onChange={(e): void => {
console.log("asdasd", form.isDebit);
form.isDebit = !form.isDebit; form.isDebit = !form.isDebit;
updateForm(structuredClone(form)); updateForm(structuredClone(form));
}} }}
@ -380,10 +370,6 @@ function CreateCashout({
<div class="toggle-switch"></div> <div class="toggle-switch"></div>
</label> </label>
</div> </div>
<ShowInputErrorLabel
message={errors?.amount}
isDirty={form.amount !== undefined}
/>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label>{i18n.str`Conversion rate`}</label> <label>{i18n.str`Conversion rate`}</label>
@ -391,118 +377,43 @@ function CreateCashout({
</fieldset> </fieldset>
<fieldset> <fieldset>
<label>{i18n.str`Balance now`}</label> <label>{i18n.str`Balance now`}</label>
<div style={{ width: "max-content" }}> <Amount
<input currency={balance.currency}
type="text"
readonly
class="currency-indicator"
size={balance.currency.length}
maxLength={balance.currency.length}
tabIndex={-1}
value={balance.currency}
/>
&nbsp;
<input
type="number"
id="withdraw-amount"
disabled
name="withdraw-amount"
value={Amounts.stringifyValue(balance)} value={Amounts.stringifyValue(balance)}
/> />
</div>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label <label
style={{ fontWeight: "bold", color: "red" }} style={{ fontWeight: "bold", color: "red" }}
>{i18n.str`Total cost`}</label> >{i18n.str`Total cost`}</label>
<div style={{ width: "max-content" }}> <Amount
<input currency={balance.currency}
type="text"
readonly
class="currency-indicator"
size={balance.currency.length}
maxLength={balance.currency.length}
tabIndex={-1}
value={balance.currency}
/>
&nbsp;
<input
type="number"
// ref={ref}
id="withdraw-amount"
disabled
name="withdraw-amount"
value={Amounts.stringifyValue(calc.debit)} value={Amounts.stringifyValue(calc.debit)}
/> />
</div>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label>{i18n.str`Balance after`}</label> <label>{i18n.str`Balance after`}</label>
<div style={{ width: "max-content" }}> <Amount
<input currency={balance.currency}
type="text"
readonly
class="currency-indicator"
size={balance.currency.length}
maxLength={balance.currency.length}
tabIndex={-1}
value={balance.currency}
/>
&nbsp;
<input
type="number"
// ref={ref}
id="withdraw-amount"
disabled
name="withdraw-amount"
value={balanceAfter ? Amounts.stringifyValue(balanceAfter) : ""} value={balanceAfter ? Amounts.stringifyValue(balanceAfter) : ""}
/> />
</div>
</fieldset>{" "} </fieldset>{" "}
{Amounts.isZero(sellFee) ? undefined : ( {Amounts.isZero(sellFee) ? undefined : (
<Fragment> <Fragment>
<fieldset> <fieldset>
<label>{i18n.str`Amount after conversion`}</label> <label>{i18n.str`Amount after conversion`}</label>
<div style={{ width: "max-content" }}> <Amount
<input currency={fiatCurrency}
type="text"
readonly
class="currency-indicator"
size={fiatCurrency.length}
maxLength={fiatCurrency.length}
tabIndex={-1}
value={fiatCurrency}
/>
&nbsp;
<input
// type="number"
style={{ color: "black" }}
disabled
value={Amounts.stringifyValue(calc.beforeFee)} value={Amounts.stringifyValue(calc.beforeFee)}
/> />
</div>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label>{i18n.str`Cashout fee`}</label> <label>{i18n.str`Cashout fee`}</label>
<div style={{ width: "max-content" }}> <Amount
<input currency={fiatCurrency}
type="text"
readonly
class="currency-indicator"
size={fiatCurrency.length}
maxLength={fiatCurrency.length}
tabIndex={-1}
value={fiatCurrency}
/>
&nbsp;
<input
// type="number"
style={{ color: "black" }}
disabled
value={Amounts.stringifyValue(sellFee)} value={Amounts.stringifyValue(sellFee)}
/> />
</div>
</fieldset> </fieldset>
</Fragment> </Fragment>
)} )}
@ -510,26 +421,10 @@ function CreateCashout({
<label <label
style={{ fontWeight: "bold", color: "green" }} style={{ fontWeight: "bold", color: "green" }}
>{i18n.str`Total cashout transfer`}</label> >{i18n.str`Total cashout transfer`}</label>
<div style={{ width: "max-content" }}> <Amount
<input currency={fiatCurrency}
type="text"
readonly
class="currency-indicator"
size={fiatCurrency.length}
maxLength={fiatCurrency.length}
tabIndex={-1}
value={fiatCurrency}
/>
&nbsp;
<input
type="number"
// ref={ref}
id="withdraw-amount"
disabled
name="withdraw-amount"
value={Amounts.stringifyValue(calc.credit)} value={Amounts.stringifyValue(calc.credit)}
/> />
</div>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label>{i18n.str`Confirmation channel`}</label> <label>{i18n.str`Confirmation channel`}</label>

View File

@ -45,7 +45,7 @@ export function PaymentOptions({ limit }: { limit: AmountJson }): VNode {
setTab("charge-wallet"); setTab("charge-wallet");
}} }}
> >
{i18n.str`Obtain digital cash`} {i18n.str`Withdraw `}
</button> </button>
<button <button
class={tab === "wire-transfer" ? "tablinks active" : "tablinks"} class={tab === "wire-transfer" ? "tablinks active" : "tablinks"}
@ -53,7 +53,7 @@ export function PaymentOptions({ limit }: { limit: AmountJson }): VNode {
setTab("wire-transfer"); setTab("wire-transfer");
}} }}
> >
{i18n.str`Transfer to bank account`} {i18n.str`Wire transfer`}
</button> </button>
</div> </div>
{tab === "charge-wallet" && ( {tab === "charge-wallet" && (

View File

@ -100,7 +100,6 @@ export function PaytoWireTransferForm({
autoCapitalize="none" autoCapitalize="none"
autoCorrect="off" autoCorrect="off"
> >
<p>
<label for="iban">{i18n.str`Receiver IBAN:`}</label>&nbsp; <label for="iban">{i18n.str`Receiver IBAN:`}</label>&nbsp;
<input <input
ref={ref} ref={ref}
@ -115,12 +114,10 @@ export function PaytoWireTransferForm({
setIban(e.currentTarget.value); setIban(e.currentTarget.value);
}} }}
/> />
<br />
<ShowInputErrorLabel <ShowInputErrorLabel
message={errorsWire?.iban} message={errorsWire?.iban}
isDirty={iban !== undefined} isDirty={iban !== undefined}
/> />
<br />
<label for="subject">{i18n.str`Transfer subject:`}</label>&nbsp; <label for="subject">{i18n.str`Transfer subject:`}</label>&nbsp;
<input <input
type="text" type="text"
@ -133,14 +130,12 @@ export function PaytoWireTransferForm({
setSubject(e.currentTarget.value); setSubject(e.currentTarget.value);
}} }}
/> />
<br />
<ShowInputErrorLabel <ShowInputErrorLabel
message={errorsWire?.subject} message={errorsWire?.subject}
isDirty={subject !== undefined} isDirty={subject !== undefined}
/> />
<br />
<label for="amount">{i18n.str`Amount:`}</label>&nbsp; <label for="amount">{i18n.str`Amount:`}</label>&nbsp;
<div style={{ width: "max-content" }}> <div style={{ width: "max-content", display: "flex" }}>
<input <input
type="text" type="text"
readonly readonly
@ -148,15 +143,25 @@ export function PaytoWireTransferForm({
size={limit.currency.length} size={limit.currency.length}
maxLength={limit.currency.length} maxLength={limit.currency.length}
tabIndex={-1} tabIndex={-1}
style={{
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
borderRight: 0,
}}
value={limit.currency} value={limit.currency}
/> />
&nbsp;
<input <input
type="number" type="number"
name="amount" name="amount"
id="amount" id="amount"
placeholder="amount" placeholder="amount"
required required
style={{
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
borderLeft: 0,
width: 150,
}}
value={amount ?? ""} value={amount ?? ""}
onInput={(e): void => { onInput={(e): void => {
setAmount(e.currentTarget.value); setAmount(e.currentTarget.value);
@ -167,8 +172,6 @@ export function PaytoWireTransferForm({
message={errorsWire?.amount} message={errorsWire?.amount}
isDirty={amount !== undefined} isDirty={amount !== undefined}
/> />
</p>
<p style={{ display: "flex", justifyContent: "space-between" }}> <p style={{ display: "flex", justifyContent: "space-between" }}>
<input <input
type="submit" type="submit"

View File

@ -51,19 +51,14 @@ export function QrCodeSection({
const { abortWithdrawal } = useAccessAnonAPI(); const { abortWithdrawal } = useAccessAnonAPI();
return ( return (
<section id="main" class="content"> <section id="main" class="content">
<h1 class="nav">{i18n.str`Transfer to Taler Wallet`}</h1> <h1 class="nav">{i18n.str`Charge your GNU Taler wallet`}</h1>
<article> <article>
<div class="qr-div"> <div class="qr-div ">
<p>{i18n.str`Use this QR code to withdraw to your mobile wallet:`}</p> <a href={talerWithdrawUri} class="pure-button pure-button-primary">
<i18n.Translate>Continue with GNU Taler</i18n.Translate>
</a>
<p>{i18n.str`Or scan this QR code with your mobile to receive the coin in another device:`}</p>
<QR text={talerWithdrawUri} /> <QR text={talerWithdrawUri} />
<p>
<i18n.Translate>
Click{" "}
<a href={talerWithdrawUri}>{i18n.str`this taler:// link`}</a> to
open your Taler wallet
</i18n.Translate>{" "}
</p>
<br />
<a <a
class="pure-button btn-cancel" class="pure-button btn-cancel"
onClick={async (e) => { onClick={async (e) => {
@ -92,7 +87,7 @@ export function QrCodeSection({
} }
} }
}} }}
>{i18n.str`Abort`}</a> >{i18n.str`Cancel`}</a>
</div> </div>
</article> </article>
</section> </section>

View File

@ -25,14 +25,16 @@ import {
RequestError, RequestError,
useTranslationContext, useTranslationContext,
} from "@gnu-taler/web-util/browser"; } from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact"; import { Ref, VNode, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks"; import { useEffect, useRef, useState } from "preact/hooks";
import { useAccessAPI } from "../hooks/access.js"; import { useAccessAPI } from "../hooks/access.js";
import { notifyError } from "../hooks/notification.js"; import { notifyError } from "../hooks/notification.js";
import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js"; import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js"; import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js";
import { forwardRef } from "preact/compat";
const logger = new Logger("WalletWithdrawForm"); const logger = new Logger("WalletWithdrawForm");
const RefAmount = forwardRef(Amount);
export function WalletWithdrawForm({ export function WalletWithdrawForm({
focus, focus,
@ -68,6 +70,7 @@ export function WalletWithdrawForm({
? i18n.str`balance is not enough` ? i18n.str`balance is not enough`
: undefined, : undefined,
}); });
return ( return (
<form <form
id="reserve-form" id="reserve-form"
@ -82,32 +85,15 @@ export function WalletWithdrawForm({
<p> <p>
<label for="withdraw-amount">{i18n.str`Amount to withdraw:`}</label> <label for="withdraw-amount">{i18n.str`Amount to withdraw:`}</label>
&nbsp; &nbsp;
<div style={{ width: "max-content" }}> <RefAmount
<input currency={limit.currency}
type="text" value={amountStr}
readonly onChange={(v) => {
class="currency-indicator" setAmountStr(v);
size={limit.currency.length}
maxLength={limit.currency.length}
tabIndex={-1}
value={limit.currency}
/>
&nbsp;
<input
type="number"
ref={ref}
id="withdraw-amount"
name="withdraw-amount"
value={amountStr ?? ""}
onChange={(e): void => {
setAmountStr(e.currentTarget.value);
}} }}
error={errors?.amount}
ref={ref}
/> />
<ShowInputErrorLabel
message={errors?.amount}
isDirty={amountStr !== undefined}
/>
</div>
</p> </p>
<p> <p>
<div> <div>
@ -160,3 +146,61 @@ export function WalletWithdrawForm({
</form> </form>
); );
} }
export function Amount(
{
currency,
value,
error,
onChange,
}: {
error?: string;
currency: string;
value: string | undefined;
onChange?: (s: string) => void;
},
ref: Ref<HTMLInputElement>,
): VNode {
return (
<div style={{ width: "max-content" }}>
<div>
<input
type="text"
readonly
class="currency-indicator"
size={currency.length}
maxLength={currency.length}
tabIndex={-1}
style={{
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
borderRight: 0,
}}
value={currency}
/>
<input
type="number"
ref={ref}
name="amount"
id="amount"
placeholder="0"
style={{
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
borderLeft: 0,
width: 150,
color: "black",
}}
value={value ?? ""}
disabled={!onChange}
onInput={(e): void => {
if (onChange) {
onChange(e.currentTarget.value);
}
}}
/>
</div>
<ShowInputErrorLabel message={error} isDirty={value !== undefined} />
</div>
);
}

View File

@ -310,3 +310,8 @@ h1.nav {
background: rgb(66, 184, 221); background: rgb(66, 184, 221);
/* this is a light blue */ /* this is a light blue */
} }
[name=wire-transfer-form] > input {
margin-bottom: 1em;
}

View File

@ -39,8 +39,8 @@ Colors:
} }
.content { .content {
margin-left: 2em; margin-left: 1em;
margin-right: 2em; margin-right: 1em;
overflow-x: auto; overflow-x: auto;
} }
@ -60,8 +60,8 @@ body {
margin-bottom: 50px; margin-bottom: 50px;
width: 100%; width: 100%;
color: white; color: white;
position: -webkit-sticky; // position: -webkit-sticky;
position: sticky; // position: sticky;
top: 0px; top: 0px;
width: 100vw; width: 100vw;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
@ -70,7 +70,7 @@ body {
} }
nav { nav {
left: 1vw; // left: 1vw;
position: relative; position: relative;
background: #0042b2; background: #0042b2;
z-index: 100; z-index: 100;
@ -83,7 +83,7 @@ nav span,
border: none; border: none;
color: white; color: white;
text-align: center; text-align: center;
text-decoration: none; // text-decoration: none;
display: inline-block; display: inline-block;
font-size: 16px; font-size: 16px;
background: #0042b2; background: #0042b2;
@ -94,9 +94,10 @@ nav a,
nav button, nav button,
nav span, nav span,
.navbtn { .navbtn {
padding: 15px 32px; padding: 8px;
} }
nav a:hover, nav a:hover,
nav span:hover, nav span:hover,
.navbtn:hover { .navbtn:hover {
@ -138,7 +139,7 @@ nav .hide div.nav {
// } // }
.langbtn { .langbtn {
width: 100%; width: 100px;
text-align: left; text-align: left;
} }
@ -156,3 +157,11 @@ nav .hide div.nav {
width: auto; width: auto;
height: auto; height: auto;
} }
.demolist > a {
margin: 8px;
}
.buttons-account input.pure-button {
margin: 8px;
}

View File

@ -1091,29 +1091,29 @@ since IE8 won't execute CSS that contains a CSS3 selector.
} }
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
.pure-form button[type="submit"] { // .pure-form button[type="submit"] {
margin: 0.7em 0 0; // margin: 0.7em 0 0;
} // }
.pure-form input:not([type]), // .pure-form input:not([type]),
.pure-form input[type="text"], // .pure-form input[type="text"],
.pure-form input[type="password"], // .pure-form input[type="password"],
.pure-form input[type="email"], // .pure-form input[type="email"],
.pure-form input[type="url"], // .pure-form input[type="url"],
.pure-form input[type="date"], // .pure-form input[type="date"],
.pure-form input[type="month"], // .pure-form input[type="month"],
.pure-form input[type="time"], // .pure-form input[type="time"],
.pure-form input[type="datetime"], // .pure-form input[type="datetime"],
.pure-form input[type="datetime-local"], // .pure-form input[type="datetime-local"],
.pure-form input[type="week"], // .pure-form input[type="week"],
.pure-form input[type="number"], // .pure-form input[type="number"],
.pure-form input[type="search"], // .pure-form input[type="search"],
.pure-form input[type="tel"], // .pure-form input[type="tel"],
.pure-form input[type="color"], // .pure-form input[type="color"],
.pure-form label { // .pure-form label {
margin-bottom: 0.3em; // margin-bottom: 0.3em;
display: block; // display: block;
} // }
.pure-group input:not([type]), .pure-group input:not([type]),
.pure-group input[type="text"], .pure-group input[type="text"],