/*
 * sikkerfil — carried over from the 2020 site.
 *
 * The brand is already decided: the colours out of the logo. Those values are reused exactly rather than re-picked — when the
 * wordmarks were redrawn in 2026 the palette moved with them, from the old
 * #255084/#4d8bd3 blues to the mark's navy, slate and teal, because a site
 * whose chrome disagrees with its own logo reads as unfinished to exactly the
 * compliance buyer plan.md §2 is written for.
 *
 * The teal (#248793) is the one genuinely new role. It is the only colour in
 * the mark that is not a blue, which makes it the only one that can carry a
 * primary action without the page turning monochrome.
 *
 * ONE DEPARTURE FROM THE ORIGINAL, and it is deliberate. The 2020 stylesheet
 * set League Gothic on `*`, so every word on the page was in a condensed
 * display face. That is right for the wordmark and headings and wrong for the
 * things this service now has to say — an expiry warning, a "your key is in the
 * link and we cannot recover it" notice, a file size. Condensed faces at small
 * sizes are measurably harder to read, and the copy that matters most here is
 * the copy a user must not skim. So League Gothic became the display face only,
 * and in 2026 it gave way to Inter entirely — see the @font-face below.
 */

/* INTER, in place of League Gothic. The condensed face was the 2020 site's
   voice and it shouted: at hero size it read as a poster, not as a service a
   DPO is asked to trust. Inter is the open face closest to the platform's own
   (SF Pro), and the variable file carries an optical-size axis, so the large
   tagline gets the Display cut — tighter spacing, finer joins — and body copy
   the Text cut, from one 73kb request instead of two families.

   ONE FILE, REAL WEIGHTS. The weight axis runs 100-900, so a bold heading is a
   drawn face, never a synthesised one. The range is declared here so the
   browser knows that and so seo.test.ts can check the tagline stays inside it.

   SELF-HOSTED, never from a font CDN: a third-party font request sends every
   visitor's address outside the boundary the trust page describes. The Latin
   subset covers æ, ø, å, ä and ö. Licensed OFL-1.1; see
   src/web/fonts/inter-LICENSE.txt. */
@font-face {
  font-family: "Inter";
  src: url("/a/inter.2c295d99.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  /* swap, so the page is readable before the font arrives. */
  font-display: swap;
}

:root {
  --ink: #122f4b;
  --ink-bright: #4a789f;
  /* TWO TEALS, because one cannot do both jobs. #248793 is the logo's own and
     is right as a shape beside the mark, but on white it is 4.2:1 — under AA
     for text and for a button label. --accent-ink is the same hue darkened
     until it passes (6.2:1), and is what anything carrying WORDS uses. A
     service that sells an auditable trail should not ship a trust page a DPO
     cannot read. */
  --accent: #248793;
  --accent-ink: #0b6e7a;
  --chrome: #42576f;
  --paper: #f5f5f7;
  /* NEUTRAL, NOT A TINT OF THE BRAND. These were #f4f7fb and #d6e2f2 — pale
     blues, so every surface on the page carried a wash of the logo. Nine
     identical blue-tinted cards down /bedrift is what that produced, and it is
     the look this redesign exists to remove: colour belongs to the mark and to
     the one action on the page, not to the furniture. A grey rule is a rule. */
  --paper-sunk: #ececf0;
  --line: rgba(60, 60, 67, 0.14);
  --muted: #6e6e73;
  /* SYNTAX COLOURS, chosen from the palette already here rather than from a
     highlighter's defaults, so a code block looks like part of this site and not
     like a screenshot of somebody's editor. Four hues is the whole set: comments
     recede, strings and numbers are the literals, keywords carry the structure.
     EVERY ONE CLEARS 4.5:1 AGAINST --paper-sunk, which is what they sit on, and
     that is measured rather than eyeballed. The comment grey started at #6b7a8f,
     which is 4.07:1 — recessive is the intent, failing AA at 0.85rem is not, so
     it is #616f85 at 4.74:1. The lowest in the set is now the comment, which is
     the right thing for the lowest to be. */
  --t-comment: #616f85;
  --t-string: #1a6a74;
  --t-number: #8a5a00;
  --t-keyword: #8a3ca8;
  --t-builtin: #2563a8;
  --warn: #8a5a00;
  --warn-bg: #fff8e6;
  --bad: #a3282d;
  --text: #1d1d1f;
  /* Revoking is destructive and reads in a different red from an error
     message. It is a token rather than a literal so that its dark value lives
     with the rest of the dark palette instead of in a third media query that
     the theme override would not reach. */
  --revoke: #b3261e;
  --sunk-tint: rgba(37, 80, 132, 0.06);

  /* So the scrollbar, the form controls and the canvas the browser paints
     before our CSS arrives all follow the theme rather than only our own
     backgrounds doing so. */
  color-scheme: light;

  /* A surface that sits ON the page rather than floating in it, and a rim
     light to separate the two. Stated once so a card, a dropzone and a footer
     cannot each invent their own. */
  --radius: 10px;
  --radius-lg: 18px;
  /* NO DROP SHADOW, anywhere. The old value floated every surface a centimetre
     off the page, which is the house style of software that wants to look
     friendly and the opposite of what this one is selling. Separation here is a
     hairline and space — a drawn edge you can point at, like the boundary the
     product is about. The tokens stay so nothing has to invent its own. */
  --shadow: 0 1px 1px rgba(0, 0, 0, 0.03), 0 6px 24px rgba(0, 0, 0, 0.05);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.04), 0 16px 40px rgba(0, 0, 0, 0.08);
  /* One measure for running text, stated once. Body copy set across a 44rem
     column runs to 90-odd characters, which is past the point a reader starts
     losing their place on the return sweep. */
  --measure: 66ch;

  --display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --surface: #ffffff;
  --fill: rgba(118, 118, 128, 0.10);
  --bar: rgba(245, 245, 247, 0.72);
  --on-accent: #ffffff;
  /* The Google and Microsoft buttons, and the passkey one beside them (see
     "Sign-in buttons" at the end). Google's light style, which Microsoft's
     own light button is within a shade of. Not the palette: these are the
     colours the two companies ask for, so they do not follow the brand. */
  --idp-fill: #ffffff;
  --idp-line: #747775;
  --idp-text: #1f1f1f;
  --idp-hover: #f1f1f1;

  /* DESIGN.md §5. Colour: a control's resting edge (3:1), the focus ring,
     the primary action's hover and press, and success. */
  --control-line: #86868b;
  --focus-ring: #0b6e7a;
  --accent-press: #085a64;
  --ok: #1e6b3a;

  /* Type: eight steps, the sizes this sheet actually renders (§5.2). */
  --type-display: clamp(2.5rem, 7vw, 4.25rem);
  --type-title: clamp(1.75rem, 4vw, 2.25rem);
  --type-heading: 1.375rem;
  --type-lede: 1.1875rem;
  --type-body: 1.0625rem;
  --type-small: 0.9375rem;
  --type-label: 0.875rem;
  --type-micro: 0.8125rem;

  /* Space, on a 4px base (§5.3). */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4rem;

  /* Shape (§5.4): --radius and --radius-lg above, and these two. */
  --radius-sm: 6px;
  --radius-pill: 999px;

  /* Motion (§5.5). */
  --dur-press: 100ms;
  --dur-quick: 150ms;
  --dur-move: 250ms;
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}

/* The original was light-only. A dark scheme is not invented here — these are
   the same hues at a lightness that works on a dark ground, so the brand is
   recognisably itself either way.

   TWO BLOCKS, IDENTICAL BY OBLIGATION. The first is the default: the reader's
   system asked for dark and they have not overridden it. The second is the
   override itself. CSS cannot apply one declaration block to both a media
   query and a selector, so the values are written twice — and app.css.test.ts
   parses this file and fails if the two ever stop agreeing, because a palette
   that drifts between "dark because your phone is" and "dark because you asked"
   is a bug nobody would think to look for. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ink: #9dc2ee;
    --ink-bright: #7fb0e8;
    /* Lifted off the logo's #248793, which on this ground is legible as a
       shape but not as a word. At 7.2:1 against --paper the lifted one carries
       text too, so dark mode needs only the one. */
    --accent: #45b3c0;
    --accent-ink: #45b3c0;
    --chrome: #16304f;
    --paper: #000000;
    --paper-sunk: #2c2c2e;
    --line: rgba(84, 84, 88, 0.55);
    --muted: #98989d;
    /* Lifted for the dark ground, same reasoning as --accent above: the light
       set is legible as shapes here but muddy as text. */
    --t-comment: #7d8ea6;
    --t-string: #45b3c0;
    --t-number: #e8b552;
    --t-keyword: #c792ea;
    --t-builtin: #82aaff;
    --warn: #e8b552;
    --warn-bg: #2b2313;
    --bad: #f08c90;
    --text: #f5f5f7;
    --revoke: #ff8a80;
    --sunk-tint: rgba(255, 255, 255, 0.06);
    /* Shadows do almost nothing on a dark ground — depth there comes from the
       surface being LIGHTER than the page, which --paper-sunk already is. What
       is left is a rim, so a card still has an edge. */
    --shadow: 0 0 0 1px rgba(255, 255, 255, 0.06);
    --shadow-lift: 0 0 0 1px rgba(255, 255, 255, 0.12);
    --surface: #1c1c1e;
    --fill: rgba(118, 118, 128, 0.24);
    --bar: rgba(22, 22, 24, 0.72);
    --on-accent: #03272b;
    /* Google's dark style. The marks on it stay as they are. */
    --idp-fill: #131314;
    --idp-line: #8e918f;
    --idp-text: #e3e3e3;
    --idp-hover: #242425;
    --control-line: #7c7c80;
    --focus-ring: #45b3c0;
    --accent-press: #62c3ce;
    --ok: #7fd39b;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
    --ink: #9dc2ee;
    --ink-bright: #7fb0e8;
    /* Lifted off the logo's #248793, which on this ground is legible as a
       shape but not as a word. At 7.2:1 against --paper the lifted one carries
       text too, so dark mode needs only the one. */
    --accent: #45b3c0;
    --accent-ink: #45b3c0;
    --chrome: #16304f;
    --paper: #000000;
    --paper-sunk: #2c2c2e;
    --line: rgba(84, 84, 88, 0.55);
    --muted: #98989d;
    /* Lifted for the dark ground, same reasoning as --accent above: the light
       set is legible as shapes here but muddy as text. */
    --t-comment: #7d8ea6;
    --t-string: #45b3c0;
    --t-number: #e8b552;
    --t-keyword: #c792ea;
    --t-builtin: #82aaff;
    --warn: #e8b552;
    --warn-bg: #2b2313;
    --bad: #f08c90;
    --text: #f5f5f7;
    --revoke: #ff8a80;
    --sunk-tint: rgba(255, 255, 255, 0.06);
    /* Shadows do almost nothing on a dark ground — depth there comes from the
       surface being LIGHTER than the page, which --paper-sunk already is. What
       is left is a rim, so a card still has an edge. */
    --shadow: 0 0 0 1px rgba(255, 255, 255, 0.06);
    --shadow-lift: 0 0 0 1px rgba(255, 255, 255, 0.12);
    --surface: #1c1c1e;
    --fill: rgba(118, 118, 128, 0.24);
    --bar: rgba(22, 22, 24, 0.72);
    --on-accent: #03272b;
    /* Google's dark style. The marks on it stay as they are. */
    --idp-fill: #131314;
    --idp-line: #8e918f;
    --idp-text: #e3e3e3;
    --idp-hover: #242425;
    --control-line: #7c7c80;
    --focus-ring: #45b3c0;
    --accent-press: #62c3ce;
    --ok: #7fd39b;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

/* THE SITE HAD NO LINK COLOUR. Anything outside the footer or a styled
   component rendered in the browser's default blue — and after a visit, purple.
   On /bedrift that was the one call to action at the foot of the page. Stated
   once, in the ink that carries every other action here. */
a {
  color: var(--accent-ink);
  text-underline-offset: 0.15em;
}

body {
  font-family: var(--body);
  color: var(--text);
  background: var(--paper);
  line-height: 1.5;
  /* So a short page still puts the footer at the bottom of the viewport
     instead of leaving it floating halfway up with blank space beneath. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* The 2020 rule was `width: 50%`, which on a phone is a 190px column. Same
   intent — a comfortable measure — expressed so it survives a narrow viewport.
   Wider than it was, because the column no longer has to be the measure as
   well: running text gets --measure below, and the extra room goes to the
   things that want it — a code block, a table of endpoints, a share row. */
.container {
  width: 100%;
  max-width: 52rem;
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* RUNNING TEXT IS NARROWER THAN THE COLUMN IT SITS IN. Prose set across the
   full 52rem runs past 100 characters, which is where a reader starts losing
   the line on the return sweep. Everything structural keeps the column; only
   the sentences are held in. */
main p,
main li,
.lede {
  max-width: var(--measure);
}

/* Takes up the slack in the body's column, which is what pushes the footer to
   the bottom of a short page rather than leaving it mid-screen. */
/* Takes up the slack in the body's column, which is what pushes the footer to
   the bottom of a short page rather than leaving it mid-screen.
   The top padding is what turns the homepage's empty lower half from a gap into
   a field: the claim sits a clear distance below the masthead, and on a short
   page the residency line lands at the bottom of the first screen. */
/* SMALL, BECAUSE THE HOMEPAGE'S HEADLINE IS IN THE HEADER. The h1 there is the
   strapline in the masthead, so anything generous here opens a gap between that
   line and the sentence answering it — the hero comes apart. The air a page
   needs under its masthead is given by the header's own row-gap above, and by
   the margin on an inner page's h1 below. */
/* main.container, NOT main, AND THE SELECTOR IS THE WHOLE FIX. This rule set
   padding-top on `main`, which is a type selector; .container above sets
   `padding: 0 1.5rem`, which is a SHORTHAND on a class. The class wins, the
   shorthand resets the top to zero, and the padding had never once applied —
   measured at 0px between the headline and the dropzone at every width from 390
   to 1280, with the descenders of "Trygg fildeling" running into the drop
   target's dashed edge. The comment that used to sit here explained at length
   what the spacing was for, which made it fiction rather than documentation. */
main.container {
  flex: 1;
  padding-top: 1.5rem;
}

/* An inner page's own heading, which is the first thing in main rather than in
   the masthead, and needs the distance the homepage gets from the grid. */
main > h1:first-child,
.doc-main > h1:first-child {
  margin-top: clamp(0.5rem, 4vh, 2rem);
}

/* A heading set large holds fewer letters to the line than the text under it,
   and "personopplysningssikkerheten" alone is wider than a 320px phone. */
main :is(h1, h2, h3) {
  overflow-wrap: break-word;
  hyphens: auto;
}


/* The mark is the way home. inline-block so the link box is the image itself
   and shrink-wraps it — giving the link its own width would leave the narrower
   phone variant sitting off-centre inside a 300px box. */
.home {
  display: inline-block;
}

/* aspect-ratio rather than width/height attributes, because <picture> serves
   two different shapes from one <img> and the attributes can only describe one
   of them. Without this the header reflows when the logo lands, which is the
   worst place on the page for it — it is the first thing above the fold.
   The breakpoint matches the one in pages.ts; they have to agree, and the
   markup is the one that decides which file is actually fetched. */
/* THE WIDE LOCKUP AT EVERY WIDTH. The stacked mark was served to anything
   above 600px and it is 300px tall — the single biggest thing on every page,
   above everything the page had to say. The horizontal one says the same name
   in a fifth of the height, which is what lets the header be a bar at all.
   aspect-ratio rather than width/height attributes, because <picture> serves
   one <img> from several files; the ratio is the wide artwork's. */
header img {
  display: block;
  width: 100%;
  max-width: 190px;
  height: auto;
  aspect-ratio: 1530 / 535;
}

.tagline {
  font-family: var(--display);
  font-size: var(--type-title);
  letter-spacing: 0;
  color: var(--ink);
  margin: 0;
  line-height: 1.05;
  /* EXPLICIT, BECAUSE THE HOMEPAGE'S TAGLINE IS AN h1, and an h1 otherwise
     takes the browser's bold. Under League Gothic, which
     shipped one weight, that bold was synthesised; Inter draws every weight, so
     the hero now asks for 700 on purpose (h1.tagline in the refinement below)
     and seo.test.ts checks it stays inside the range @font-face declares. */
  font-weight: normal;
}

/* THE HERO, AND IT IS THE SENTENCE THE SITE IS ABOUT. On the homepage the
   tagline is the h1 — "Trygg fildeling i Norden" — and it was set at 1.75rem
   under a logo four times its size. It is the claim the whole product rests on,
   so it is the largest thing on the page and the mark is the small thing in the
   corner. No other page carries it (DESIGN.md §2.3).
   clamp() rather than a breakpoint: the line is three or four words and should
   fill the column at any width without a media query deciding for it. */
h1.tagline {
  font-size: var(--type-display);
  letter-spacing: -0.01em;
  margin: 0.5rem 0 0;
}

h1,
h2,
h3 {
  font-family: var(--display);
  color: var(--ink);
  letter-spacing: 0;
  line-height: 1.1;
  margin: 0 0 0.75rem;
}

h1 {
  font-size: var(--type-title);
}

h2 {
  font-size: var(--type-title);
}

/* ADDED WITH THE LIBRARY REFERENCE, which is the first page here deep enough to
   need a third level. There was no h3 rule at all, so the six new subheadings
   rendered in the browser's default serif at its default size — a section that
   looked like it had escaped the stylesheet. Given a size between h2 and body,
   and extra space above, because an h3 that follows a code block needs to read
   as a new section rather than as a caption for the block above it. */
h3 {
  font-size: var(--type-lede);
  margin: 1.6rem 0 0.4rem;
}

/* The drop target. Dropzone.js is gone — the client encrypts before uploading
   (plan.md §6.2), so the upload cannot be handed to a library that posts the
   file as it is — but the shape it presented is kept. */
.dropzone {
  /* BOTH OF THESE ARE LOAD-BEARING and their absence broke the page.
     A <label> is inline by default, and an inline box's padding does not
     affect line height — so `padding: 3rem 1.5rem` below rendered as a dashed
     border bleeding OUTSIDE the flow without reserving any space for itself.
     The result: the border fragmented across line boxes, the zone started
     above its own form, and the first field sat on top of it.
     `.field label` has always had display: block; this one was simply missed.

     position: relative is the companion to the visually-hidden file input
     below, which is position: absolute. Without a positioned ancestor it
     resolves against the initial containing block — harmless while it is 1px
     and clipped, wrong the moment either changes. */
  display: block;
  position: relative;
  border: 2px dashed var(--line);
  border-radius: var(--radius-lg);
  background: var(--paper-sunk);
  padding: 3.25rem 1.5rem;
  text-align: center;
  cursor: pointer;
  transition: border-color var(--dur-quick) ease, background var(--dur-quick) ease;
}

.dropzone:hover,
.dropzone:focus-visible,
.dropzone.is-over {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--paper-sunk));
}

/* Dragging a file over it should feel like it has been caught. */
.dropzone.is-over {
  border-style: solid;
  box-shadow: var(--shadow-lift);
}

.dropzone .prompt {
  font-family: var(--display);
  font-size: var(--type-title);
  color: var(--ink);
  display: block;
}

.dropzone .hint {
  color: var(--muted);
  font-size: var(--type-label);
}

/* The file input is .sr-only in the markup: hidden but still focusable and
   still announced, so the keyboard and screen-reader path is this same control
   rather than a second one. */

.field {
  margin: 1rem 0;
}

.field label {
  display: block;
  font-weight: 600;
  font-size: var(--type-label);
  margin-bottom: 0.25rem;
}

/* A FIELD YOU CAN SEE AND HIT. The 2020 rule produced a 30-pixel box with a
   hairline round it, which on the sign-in page — where the field IS the page —
   read as an afterthought. 44px is the smallest target a thumb reliably hits,
   and the measure is capped because a single email field stretched across a
   desktop looks broken, not generous. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
textarea,
select {
  width: 100%;
  max-width: 26rem;
  min-height: 2.75rem;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font: inherit;
  font-size: var(--type-body);
  background: var(--paper);
  color: inherit;
  transition: border-color var(--dur-quick) ease, box-shadow var(--dur-quick) ease;
}

input[type="text"]:hover,
input[type="email"]:hover,
input[type="password"]:hover,
input[type="number"]:hover,
textarea:hover,
select:hover {
  border-color: var(--ink-bright);
}

/* THE FOCUS RING IS THE BRAND'S, not the browser's default blue, and it is a
   ring rather than an outline so it follows the radius. :focus-visible so a
   mouse click does not light it up — a keyboard user needs this and a pointer
   user has already been told where they are by the caret. */
input[type="text"]:focus-visible,
input[type="email"]:focus-visible,
input[type="password"]:focus-visible,
input[type="number"]:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
}

/* Everything else focusable gets a visible ring too. The site had none and
   relied on whatever the browser drew, which on a dark page is often nothing. */
a:focus-visible,
button:focus-visible,
.dropzone:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* The teal, not the navy. It is the only colour in the mark that is not a
   blue, so it is the only one that can mark the primary action without the
   page going monochrome — and the navy is now dark enough that a button in it
   reads as disabled chrome rather than as the thing to press. */
button {
  font-family: var(--display);
  font-size: var(--type-heading);
  letter-spacing: 0.02em;
  background: var(--accent-ink);
  color: var(--on-accent);
  border: 0;
  border-radius: var(--radius);
  padding: 0.6rem 1.9rem;
  min-height: 2.75rem;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: background var(--dur-quick) ease, box-shadow var(--dur-quick) ease, transform var(--dur-press) ease;
}

button:hover:not(:disabled) {
  background: var(--accent-press);
  box-shadow: var(--shadow-lift);
}

/* One pixel, on press. Enough to feel like a button and not enough to shift
   anything around it. */
button:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: var(--shadow);
}

button:disabled {
  opacity: 0.55;
  cursor: default;
  box-shadow: none;
}

.progress {
  height: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--paper-sunk);
}

.progress > span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink-bright);
  transition: width var(--dur-move) ease;
}

/* The link and the button that copies it, on one line — and wrapping to two on
   a narrow phone rather than squeezing a monospace URL into half a screen. */
.link-row {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.5rem 0 1rem;
}

.link-out {
  flex: 1 1 18rem;
  /* The measure cap on other inputs is wrong here: this is a URL to be read
     back or copied, not a field to type into, so it takes the width it has. */
  max-width: none;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: var(--type-small);
}

#copy {
  flex: 0 0 auto;
  font-size: var(--type-body);
  padding: 0.5rem 1.25rem;
}

/* The notice that carries plan.md §6.2's cost. It is styled to be read rather
   than to be pretty: if a user skims past this, they lose a file and we cannot
   help them. */
.notice {
  background: var(--warn-bg);
  border-left: 4px solid var(--warn);
  color: var(--warn);
  padding: 1rem 1.25rem;
  border-radius: 0 var(--radius) var(--radius) 0;
  margin: 1rem 0;
  font-size: var(--type-small);
}

.notice h2 {
  color: inherit;
  margin-top: 0;
}

.error {
  color: var(--bad);
  font-weight: 600;
}

.meta {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
  border-top: 1px solid var(--line);
}

.meta li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--type-small);
}

.meta li span:first-child {
  color: var(--muted);
}

/* A READER WHO HAS ASKED FOR LESS MOTION GETS NONE. Every transition here is
   small — a border warming on hover, a segment filling — but "small" is not the
   test; the setting is an accessibility preference, and vestibular disorders do
   not grade movement by how tasteful it is. Nothing on this site depends on
   animation to be understood, so the honest implementation is to switch it off
   rather than to shorten it. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

[hidden] {
  display: none !important;
}

/* An ordinary footer at the end of the document.
   The 2020 design had it FIXED, and it was carried over that way without the
   question being asked. A bar pinned across the bottom of every page costs a
   phone a permanent strip of its screen, covers the last line of whatever you
   are reading, and follows you down a long page like a cookie banner. The
   residency line does not need to be in front of you at all times; it needs to
   be somewhere obvious, which the end of the page is.
   The residency line is in it deliberately: plan.md §3 says residency should be
   demonstrable, and the cheapest version of that is saying it on every page. */
/* NO LONGER A NAVY BAR. A filled band across the bottom made the footer the
   heaviest object on a page whose content is a sentence and a button — the eye
   went to the furniture. It is the same information, set as the page's last
   quiet line above a rule.
   THE RESIDENCY SENTENCE KEEPS ITS WEIGHT, and gains some: it is the claim the
   product is sold on, so it is the first thing in the footer, in the page's own
   ink rather than in white on navy, with the rest set smaller beside it. */
.footer {
  width: 100%;
  max-width: 52rem;
  margin: 5rem auto 0;
  padding: 1.25rem 1.5rem 2.5rem;
  border-top: 1px solid var(--line);
  background: none;
  color: var(--muted);
  text-align: left;
  font-size: var(--type-label);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem 2rem;
  flex-wrap: wrap;
}

.footer > span:first-child {
  color: var(--text);
  font-size: var(--type-small);
  max-width: var(--measure);
}

.footer a {
  color: var(--accent-ink);
}

/* The theme control. Styled as the footer's own text rather than as a button,
   for the same reason the sign-out control is: a 40-pixel blue button down here
   would shout over the residency line, which is the sentence this footer exists
   to carry. */
/* A visually-hidden utility. The file input inside the dropzone has carried its
   own copy of this since the first commit; the radios below need the same, and
   two copies of a clip rectangle is one too many. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* THE COLOUR THEME, as three segments on the footer's chrome.
   It was an underlined word, which reads as a link — and a link that does not
   navigate is the most confusing thing a footer can hold. Segments show all
   three states at once, so the one that is on is visible without pressing
   anything, and "follow the system" stays somewhere a reader can get back to. */
/* TOKENS, NOT WHITE. Every colour in this control was a literal white or an
   rgba(255,255,255,…), which was correct exactly as long as the footer was a
   navy bar. The moment the footer became paper the whole control went white on
   white — present, focusable, and invisible. That is the cost of a component
   knowing what it is sitting on; it now asks the palette instead. */
.theme {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.theme-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 28px rather than the 44px a standalone target would get: three of those in
     a footer is a toolbar, and these sit inside one control that is itself
     comfortably large. */
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  transition: background var(--dur-quick) ease, color var(--dur-quick) ease;
}

.theme-option:hover {
  color: var(--text);
  background: var(--sunk-tint);
}

/* The chosen segment. Filled rather than merely brighter, because "which one is
   on" has to survive being glanced at. */
.sr-only:checked + .theme-option {
  color: var(--paper);
  background: var(--ink);
}

/* The input is off-screen, so the ring has to be drawn on the label it drives —
   otherwise keyboard focus lands somewhere nobody can see. */
.sr-only:focus-visible + .theme-option {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

.theme-option svg {
  display: block;
}

/* The receipt (plan.md §2 "Prove"). Deliberately plain: this is evidence
   somebody forwards to a data protection officer, not a dashboard. It reuses
   .meta for the trail itself so a receipt and a share page look like the same
   product. */
.download-csv {
  color: var(--ink);
  font-weight: 600;
  cursor: pointer;
}

.download-csv:hover {
  color: var(--ink-bright);
}

.receipt-note {
  color: var(--muted);
  font-size: var(--type-label);
  border-top: 1px solid var(--line);
  padding-top: 0.75rem;
}




/* NOT A CARD ANY MORE, AND THAT IS THE POINT OF THE REDESIGN. Nine of these
   ran down /bedrift — identical pale-blue rounded rectangles with identical
   shadows, one per section, so the page read as a stack of tiles rather than as
   a document with parts. Each tile also said the same thing about its contents:
   nothing.
   What separates a section from the next one is now space and a single rule at
   its head. The rule is drawn, thin and full-width; it is the same device the
   footer uses for the residency line, because it means the same thing in both
   places — this is where one claim ends and another begins.
   A FORM STILL GETS AN EDGE. Where .card holds a control rather than prose,
   .card.enclosed below keeps a real border: "this is the thing to fill in" is
   information, and it is the one place the old surface was doing a job. */
.card {
  border-top: 1px solid var(--line);
  padding: 1.75rem 0 0;
  margin: 3rem 0 0;
}

/* HEADINGS IN THE MARGIN, CONTENT IN THE COLUMN — the shape of a register or a
   statute rather than of a landing page, which is the document /bedrift and
   /personvern actually are. It earns its place on the long pages: a reader
   scanning for "what does it cost" runs their eye down one narrow column of
   names instead of through the prose, and the answer is level with its own
   heading rather than under it.
   It collapses below 48rem, where a 13rem margin column would leave the text
   too narrow to read. */
@media (min-width: 48rem) {
  .card:not(.enclosed) {
    display: grid;
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
    column-gap: 3rem;
  }

  /* Everything sits in the content column; the heading is lifted out of it into
     the margin, level with the first line it belongs to. */
  .card:not(.enclosed) > * {
    grid-column: 2;
  }

  .card:not(.enclosed) > h2 {
    grid-column: 1;
    grid-row: 1;
    margin-top: 0;
    /* Optically level with the body text beside it: the display face sits high
       in its box, so matching the baselines takes a nudge rather than nothing. */
    padding-top: 0.15rem;
  }
}

/* AS WIDE AS WHAT IT BELONGS TO. This carried a 30rem cap, which was right for
   a form standing on its own and wrong for this one: on the upload page the
   options sit directly under a full-width dropzone, and a narrower panel beneath
   a wider one reads as two unrelated things rather than as one form. The sign-in
   page keeps its own 26rem below, where a single field IS the page. */
.card.enclosed {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem;
  margin: 1.5rem 0;
}

/* THE SETTINGS ARE A REGISTER, not a form laid out in columns.

   What was here put three controls on one line and the fourth on its own, which
   gave the panel two different grid systems and no answer for where a hint
   goes: the one under "max downloads" hung below the middle column with empty
   space either side of it, and the named link's row stopped two thirds of the
   way across while the row above ran the full width. Nothing lined up with
   anything, and the widths — a 640px box for an optional password beside a 96px
   box for a digit — read as arbitrary rather than as information.

   THE SHAPE IS ALREADY IN THIS STYLESHEET. The download page states its facts
   as a .meta list — term, value, a hairline between rows — and two of the four
   settings chosen here (when it expires, how many downloads are left) are
   literally rows in that list on the other side. Not the same list: the receipt
   has three rows to this one's four, and it pushes its values to the right edge
   where a form has to align its controls to a left one. But the construction is
   deliberately the same, because a setting and the fact it becomes should not
   be two unrelated shapes.

   It also answers the widths. Every control starts at one left edge, so a
   narrow one is no longer a short box floating in a wide column; it is a short
   answer in a column of answers, which is what a field's width should say.

   SUBGRID, AND IT IS LOAD-BEARING. The label column is sized to the longest
   label across ALL FOUR rows, and that label differs by market: one stylesheet
   is served to Norwegian, Swedish and Danish readers, whose strings are not the
   same length. A fixed column would be right in one language and wrong in the
   other two. max-content over a shared track is the only value that is right in
   all three without measuring any of them. */
@media (min-width: 40rem) {
  .options {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
  }

  .options > .field {
    display: grid;
    grid-template-columns: subgrid;
    grid-column: 1 / -1;
    column-gap: 2rem;
    margin: 0;
    padding: 0.9rem 0;
    border-top: 1px solid var(--line);
  }

  /* The panel's own rim is the first row's rule. */
  .options > .field:first-child {
    border-top: 0;
    padding-top: 0;
  }

  .options > .field:last-child {
    padding-bottom: 0;
  }

  /* A TERM, NOT A HEADING. Four labels at 600 weight in the page's brightest
     ink made the panel four shouted words and their quiet answers. This is the
     weight and colour .meta gives the term beside a value, which is the same
     relationship. */
  .options > .field > label {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    font-weight: 500;
    color: var(--muted);
    /* Optically on the control's text rather than on the top of its box. */
    padding-top: 0.65rem;
  }

  /* The control and its hint share the second column, stacked. Stated as
     "everything that is not the label" so a field that gains a second element
     lands in the column rather than under the term. */
  .options > .field > :not(label) {
    grid-column: 2;
  }

  /* Sized to their contents. The select shows "24t" at its widest and the count
     cannot exceed the free cap, so neither has any use for more room — and now
     that both start at the column's edge, having less of it reads as the answer
     being short rather than as the box being wrong.

     justify-self, AND WITHOUT IT THE WIDTHS DO NOTHING. A grid item stretches
     to its track by default, so `width: auto` on the select filled the whole
     column — the rule was present, more specific than the `select` it was
     overriding, and still produced a full-width box, because stretch had
     already decided the size. The declaration that matters here is the
     alignment one, not the width one. */
  .options > .field > :not(label) {
    justify-self: start;
  }

  .options #expiry {
    width: auto;
    min-width: 7rem;
  }

  .options #downloads {
    width: 5.5rem;
  }

  .options #password {
    width: 100%;
    max-width: 22rem;
  }

  /* The one control that genuinely wants the column: it is a URL, and the point
     of a named link is being able to read it. */
  /* MORE SPECIFIC THAN THE start ABOVE, deliberately. `:not(label)` carries the
     specificity of its argument, so `.options > .field > :not(label)` is
     (0,2,1) and a plain `.options .named-link` (0,2,0) loses to it — the
     stretch was written, was correct, and did nothing. Matching the shape of
     the rule it overrides is what makes it win.

     THE RECIPIENTS FIELD JOINS IT, for the same reason the named link is here:
     both hold a long string the sender has to proof-read before pressing send.
     A text input's intrinsic width is about twenty characters — measured at
     416px — which shows roughly ONE of the five addresses it may hold, and a
     field you cannot read back is a field that mails the wrong person. */
  .options > .field > .named-link,
  .options > .field > #recipients {
    max-width: none;
    justify-self: stretch;
  }
}

/* Below the breakpoint the register collapses to a stack — label above control,
   controls full width, because on a phone a full-width target is the easiest to
   hit — but the rules stay, so it is still recognisably the same list. */
@media (max-width: 39.999rem) {
  .options > .field {
    margin: 0;
    padding: 0.9rem 0;
    border-top: 1px solid var(--line);
  }

  .options > .field:first-child {
    border-top: 0;
    padding-top: 0;
  }

  .options > .field:last-child {
    padding-bottom: 0;
  }
}

/* The hint under a field, which the .dropzone rule already styles for its own
   use — outside it, it needs to be a block or it sits on the same line as the
   control above it. */
.field .hint {
  display: block;
  margin-top: 0.35rem;
  color: var(--muted);
  font-size: var(--type-label);
}

/* The last field in a card should not push the rim away from itself. */
.card > .field:last-child,
.card > p:last-child {
  margin-bottom: 0;
}

/* The sign-in page. One narrow column: there is one field on it and nothing
   else to look at. The other ways in sit outside the form, so they are held
   to the same width; otherwise their full-width buttons ran to the page's
   38rem on a desktop and the stack stopped being one stack. The same width
   is not enough on its own: the form's button sits inside the card's side
   padding (.card.enclosed, "Surfaces", 1.25rem), so the alternatives take
   the same inset or they come out 2.5rem wider than it. */
#signin,
#signin-alternatives {
  max-width: 26rem;
}
#signin-alternatives {
  padding: 0 1.25rem;
}

/* The dashboard (plan.md §10 Phase 3c).

   Cards rather than a table, because the interesting thing about a share is
   four short facts and two actions, and a table of four columns on a phone is
   four columns too many. It reuses .meta so a dashboard row, a share page and
   a receipt all look like the same product. */
.shares {
  list-style: none;
  padding: 0;
  margin: 0;
}

.share {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 1rem 1.25rem;
  margin-bottom: 1rem;
}

/* The id is the only handle on a share the dashboard can show — the filename
   is encrypted under a key we never had. Monospace because it is an
   identifier somebody may read aloud or type. */
.share-id {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--type-body);
  letter-spacing: 0.06em;
  margin: 0 0 0.5rem;
}

.share .meta {
  margin: 0 0 0.75rem;
}

.share-actions {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin: 0;
}

/* Destructive, so it reads as destructive — but not a red slab, because it
   sits next to an ordinary link and the page is not trying to frighten
   anybody. The dialog before it is what actually prevents the accident. */
.revoke {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  min-height: 0;
  font-family: inherit;
  font-size: inherit;
  color: var(--revoke);
  text-decoration: underline;
  cursor: pointer;
}

.revoke:hover:not(:disabled) {
  background: none;
  opacity: 0.75;
}

/* The sign-in prompt where the dropzone would be. A button rather than a bare
   link: on the upload page it is the only thing to do. */
/* The same decision as `button`, for the anchor that looks like one. */
.cta {
  display: inline-block;
  background: var(--accent-ink);
  color: var(--on-accent);
  padding: 0.6rem 1.4rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-weight: 600;
}

.cta:hover {
  background: var(--accent-press);
  color: var(--on-accent);
}

/* The DPO page (plan.md §2). Long-form prose, so it gets a measure a person
   can actually read — around 70 characters — rather than the full container
   width the forms use. */
.lede {
  font-size: var(--type-body);
  color: var(--muted);
}

main h2 {
  margin-top: 2.25rem;
}

main p {
  max-width: 38rem;
  line-height: 1.6;
}

ul.plain {
  max-width: 38rem;
  line-height: 1.6;
  padding-left: 1.2rem;
}

ul.plain li {
  margin-bottom: 0.4rem;
}

/* ── Content pages (DESIGN.md §3.7) ──────────────────────────────────────────
   A list of facts is short items, each with one bold lead, a hairline between
   them, so the eye runs down the leads. A paragraph in a bullet is a paragraph. */
ul.facts {
  list-style: none;
  max-width: var(--measure);
  margin: 0 0 var(--s-5);
  padding: 0;
  line-height: 1.55;
}
ul.facts li {
  padding: var(--s-2) 0;
  border-top: 1px solid var(--line);
}
ul.facts li:first-child {
  border-top: 0;
}
ul.facts strong {
  color: var(--text);
  font-weight: 600;
}

/* The on-page table of contents: only from 64rem, where there is a column for
   it beside the page's own two columns. Below that it is not rendered at all,
   because a list of links above a page that is one scroll is a detour. */
.toc {
  display: none;
}
@media (min-width: 64rem) {
  .container:has(> .doc) {
    max-width: 70rem;
  }
  .container.wide:has(> .doc) {
    max-width: 76rem;
  }
  .doc {
    display: grid;
    grid-template-columns: 12rem minmax(0, 1fr);
    column-gap: var(--s-7);
    align-items: start;
  }
  .doc-main {
    min-width: 0;
  }
  .toc {
    display: block;
    position: sticky;
    top: 5rem;
    max-height: calc(100vh - 6rem);
    overflow-y: auto;
    margin-top: clamp(0.5rem, 4vh, 2rem);
    font-size: var(--type-small);
  }
  .toc p {
    margin: 0 0 var(--s-2);
    padding: 0 var(--s-2);
    color: var(--muted);
    font-size: var(--type-label);
    font-weight: 600;
  }
  /* 8px between targets, the spacing §8 asks of adjacent controls. */
  .toc ol {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    list-style: none;
    margin: 0;
    padding: 0;
  }
  /* 44px tall, the target every control gets (DESIGN.md §8). */
  .toc a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.375rem var(--s-2);
    border-radius: var(--radius-sm);
    color: var(--text);
    text-decoration: none;
    line-height: 1.35;
  }
  .toc a:hover {
    background: var(--fill);
  }
}

/* The retention table. A real <table> because it is tabular data that somebody
   will print or paste into a procurement document, and because a screen reader
   should announce it as one. */
.retention {
  border-collapse: collapse;
  max-width: 38rem;
  width: 100%;
  margin: 1rem 0 0;
}

.retention th,
.retention td {
  text-align: left;
  padding: 0.5rem 0.75rem 0.5rem 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
  /* Norwegian compounds are long, and a table sizes its columns to the longest
     word: at 320px one of them pushed the page 89px sideways. "anywhere" is
     the value that lowers that minimum; hyphens make the break read as one. */
  overflow-wrap: anywhere;
  hyphens: auto;
}

.retention th {
  font-family: var(--display);
  font-size: var(--type-lede);
  letter-spacing: 0.02em;
}

/* Printed and attached to a ticket is a first-class use of this page, so the
   chrome that helps on screen only gets in the way on paper. */
@media print {
  .footer,
  .site-nav,
  .app-nav,
  .account-menu,
  .tab-bar,
  .skip-link,
  .toc,
  header picture {
    display: none;
  }

  /* The contents column is hidden, so the page is one column again even on
     paper wide enough to match the 64rem query. */
  .doc {
    display: block;
  }

  main p,
  ul.plain,
  ul.facts,
  .retention {
    max-width: none;
  }
}

/* The named link field. The prefix sits outside the input so what the sender
   types is exactly what gets claimed — a field pre-filled with "sikkerfil.no/"
   is a field people paste a whole URL into. */
/* The one control here that genuinely wants room: it is a URL, and the point of
   a named link is being able to read it. */
.named-link {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  max-width: 32rem;
  min-height: 2.75rem;
  background: var(--paper);
  transition: border-color var(--dur-quick) ease, box-shadow var(--dur-quick) ease;
}

.named-link:hover {
  border-color: var(--ink-bright);
}

/* The ring goes on the WHOLE control, not on the input inside it — the prefix
   is part of the same field and a ring round half of it looks broken. */
.named-link:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
}

.named-prefix {
  display: flex;
  align-items: center;
  padding: 0 0.1rem 0 0.75rem;
  background: var(--sunk-tint);
  color: var(--muted);
  white-space: nowrap;
  font-size: var(--type-small);
}

.named-link input {
  border: none;
  border-radius: 0;
  flex: 1;
  min-width: 0;
  max-width: none;
  min-height: 0;
  background: none;
}

.named-link input:focus-visible {
  outline: none;
  box-shadow: none;
}


/* The footer's own pages ---------------------------------------------------
   A row, not a column: two links wrapping to one per line on a narrow screen
   rather than overflowing. The separator is DRAWN between items rather than
   typed into the markup, so adding or removing a link cannot leave a stray dot
   behind — which is the failure mode of every hand-punctuated nav. */
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1.75rem;
}

/* NO DOT BETWEEN THEM. 'A · B · C' is the house punctuation of generated
   pages, and it was doing nothing here that the gap does not: two links a
   comfortable distance apart already read as two links. The gap widened to
   carry the separation on its own. */

/* The business and developer pages -----------------------------------------
   Both are documents rather than forms, and the column the app's controls live
   in is too narrow for a reference with a three-column table in it. Widening
   main for everybody would loosen the pages that are already right, so this is
   scoped to the two that need it. */
.price {
  font-family: var(--display);
  font-size: var(--type-title);
  letter-spacing: 0.02em;
  margin: 0.3rem 0 0.6rem;
}

/* The endpoint table. Tabular for the same reason the retention table is: it is
   a reference somebody scans down a column of, not prose. */
.endpoints {
  border-collapse: collapse;
  width: 100%;
  margin: 0.5rem 0 0;
  font-size: var(--type-small);
}

.endpoints th,
.endpoints td {
  text-align: left;
  padding: 0.5rem 0.9rem 0.5rem 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.endpoints th {
  font-family: var(--display);
  font-size: var(--type-lede);
  letter-spacing: 0.02em;
}

.endpoints .need {
  color: var(--muted);
  white-space: nowrap;
}

.method {
  font-weight: 600;
  color: var(--accent-ink);
}

.path {
  white-space: nowrap;
}

/* A table of paths is the one thing on this site that genuinely cannot be made
   narrower — a path is as wide as it is. Scrolling the table alone beats
   scrolling the page sideways, which moves the text out from under the reader. */
.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

pre {
  background: var(--paper-sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.75rem 0.9rem;
  overflow-x: auto;
  font-size: var(--type-label);
  line-height: 1.5;
  margin: 0.6rem 0;
}

pre code {
  background: none;
  padding: 0;
  white-space: pre;
}

/* Rendered server-side by highlight.ts — there is no highlighter in the bundle,
   because the CSP forbids inline script and one page's colouring is not worth an
   asset every visitor fetches. A viewer with no CSS sees the code unchanged. */
.t-c {
  color: var(--t-comment);
  font-style: italic;
}

.t-s {
  color: var(--t-string);
}

.t-n {
  color: var(--t-number);
}

.t-k {
  color: var(--t-keyword);
}

.t-b {
  color: var(--t-keyword);
  font-weight: 600;
}

.t-f {
  color: var(--t-builtin);
}

/* The reference is the one page this column is too narrow for. 44rem suits a
   form and a paragraph, which is what everything else here is; a three-column
   table of HTTP paths in it wraps "POST /api/shares/{id}/complete" onto two
   lines and reads like a mistake. Widening main for everybody would loosen the
   pages that are already right, so it is scoped to the one that needs it —
   and the prose inside keeps its own 38rem measure, because a line of text
   that wide is harder to read, not easier. */
.container.wide {
  max-width: 58rem;
}

/* The second action next to a primary one: the passkey button under "send me
   a link", and "add a passkey" on the dashboard. Outlined in the same teal, so
   it reads as the same product's button without competing with the one the
   page is for. */
button.secondary {
  background: none;
  color: var(--accent-ink);
  box-shadow: inset 0 0 0 2px var(--accent-ink);
}

button.secondary:hover:not(:disabled) {
  background: var(--sunk-tint);
  box-shadow: inset 0 0 0 2px var(--accent);
}

.signin-or {
  color: var(--muted);
  margin: 1rem 0 0.25rem;
}

/* Passkeys: the same row shape as API keys and shares, see below. */
#passkeys .hint {
  color: var(--muted);
}

/* API keys ------------------------------------------------------------------
   The list reuses .share, because a key row and a share row are the same
   shape — a title, some facts, one destructive action — and a second set of
   rules that drifts from the first is how two lists on one page stop looking
   like one product. */
#api-keys .hint,
#team .hint {
  color: var(--muted);
  font-size: var(--type-label);
  margin: 0.2rem 0 0.8rem;
}

/* The team's controls (phase 5). The add form sits under the roster like the
   key form sits above its list, and a member's remove button is the same
   small destructive action as a share's, against the row's right edge. */
#team-add-form {
  margin-top: 1.5rem;
}

#team-list .revoke {
  margin-left: 0.75rem;
}

#team-leave {
  margin-top: 1rem;
}

/* Monospace and allowed to shrink: on a narrow phone the prefix plus eight
   characters plus a date is more than one line, and the date is the half a
   reader can afford to wrap. The colour is inherited from .meta's first-child
   rule rather than set here, so a key row and a share row grey the same way. */
.key-hint {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--type-label);
  overflow-wrap: anywhere;
}

/* A revoked key KEEPS ITS ROW, unlike a revoked share. The two lists answer
   different questions: which shares can still be downloaded, versus what has
   ever had access to this account — and the second one is the question
   somebody asks after a leak, which a disappearing row cannot answer. Dimmed
   rather than removed, with the revocation date where the actions were. */
.share.revoked {
  opacity: 0.6;
}

.share.revoked .share-title,
.share.revoked .row-title {
  text-decoration: line-through;
}

/*
 * THE 2026 REFINEMENT — grouped surfaces, system type, tactile controls.
 *
 * The hairline-and-space look above was right about restraint and wrong about
 * hierarchy: every surface sat at the same depth as the page, so a form, a
 * warning and a footer all read as the same grey box. This pass keeps the
 * restraint and borrows the platform's answer to the hierarchy problem — the
 * inset grouped list. The page is a quiet tinted ground; the things you act on
 * are white surfaces lifted off it; separators are inset hairlines inside a
 * surface, never boxes around it.
 *
 * Type: one family, Inter (see the @font-face at the top), with size-specific
 * tracking — negative as it grows, near zero at body size.
 *
 * Feedback lives on the press: controls scale down on :active in 100ms, and
 * nothing waits for release to acknowledge a touch.
 */

body {
  font-size: var(--type-body);
  line-height: 1.47;
  letter-spacing: -0.003em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3 {
  font-family: var(--display);
  color: var(--text);
  font-weight: 700;
  font-optical-sizing: auto;
}
h1 {
  font-size: var(--type-title);
  line-height: 1.1;
  letter-spacing: -0.024em;
}
h2 {
  font-size: var(--type-heading);
  line-height: 1.2;
  letter-spacing: -0.016em;
}
h3 {
  font-size: var(--type-body);
  font-weight: 600;
  letter-spacing: -0.008em;
}

/* ── Header ─────────────────────────────────────────────────────────────── */

h1.tagline {
  color: var(--text);
  text-align: center;
  font-size: var(--type-display);
  font-weight: 700;
  font-optical-sizing: auto;
  line-height: 1.02;
  letter-spacing: -0.032em;
  text-wrap: balance;
  margin: 0;
}

/* ── Navigation (DESIGN.md §2.2) ────────────────────────────────────────────
   One bar for everybody, holding the mark and the navigation only. A visitor
   sees "For bedrifter" and "Logg inn"; an account sees its destinations and
   the account menu, at 48rem and up in this bar and below it as a tab bar at
   the foot of the screen. Both ship hidden and the session reveals one
   (paintAccountCorner in app.ts), because the page is cached for everyone.
   A page a recipient lands on has none of it. */

html {
  scroll-padding-top: 4.5rem;
}

.skip-link {
  position: absolute;
  top: var(--s-2);
  left: var(--s-4);
  z-index: 30;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lift);
  transform: translateY(-200%);
}
.skip-link:focus {
  transform: none;
}
main:focus {
  outline: none;
}

/* A material, not a slab: translucent over what scrolls beneath it, with a
   fade at its edge instead of a rule. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bar);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
}
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-1 * var(--s-3));
  height: var(--s-3);
  background: linear-gradient(var(--bar), transparent);
  pointer-events: none;
}
.site-bar {
  max-width: 72rem;
  margin: 0 auto;
  min-height: 3.5rem;
  padding: var(--s-2) var(--s-4);
  display: flex;
  align-items: center;
  gap: var(--s-4);
  box-sizing: border-box;
}
header img {
  max-width: 132px;
}

.site-nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--s-1);
}
.site-nav a,
.app-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--s-3);
  color: var(--text);
  font-size: var(--type-label);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.site-nav a {
  border-radius: var(--radius-pill);
}
.site-nav a:hover {
  background: var(--fill);
}
/* The one filled button in the bar. */
.site-nav .nav-signin {
  margin-left: var(--s-1);
  background: var(--accent-ink);
  color: var(--on-accent);
}
.site-nav .nav-signin:hover {
  background: var(--accent-press);
}

.app-nav {
  display: none;
}
.app-nav svg {
  display: none;
}
.app-nav a {
  color: var(--muted);
  border-bottom: 2px solid transparent;
  border-radius: 0;
}
.app-nav a:hover,
.app-nav a[aria-current="page"] {
  color: var(--text);
}
.app-nav a[aria-current="page"] {
  border-bottom-color: var(--accent-ink);
}

.account-menu {
  position: relative;
  margin-left: auto;
  min-width: 0;
}
.account-menu #account-button {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  max-width: 18rem;
  min-height: 44px;
  padding: 0 var(--s-3);
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--text);
  font-family: var(--body);
  font-size: var(--type-label);
  font-weight: 500;
  letter-spacing: 0;
}
.account-menu #account-button:hover:not(:disabled) {
  background: color-mix(in srgb, var(--fill) 100%, var(--text) 8%);
}
/* The chevron, drawn rather than typed, so it is not read out. */
.account-menu #account-button::after {
  content: "";
  flex: none;
  width: 0.4em;
  height: 0.4em;
  margin: 0 0.1em 0.2em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}
/* AN ADDRESS SETS NO WIDTH: it is user data of any length, so it is cut
   rather than allowed to push the mark off the bar. */
#account-email {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.account-initial {
  display: none;
}

.menu {
  position: absolute;
  top: calc(100% + var(--s-2));
  right: 0;
  z-index: 25;
  display: flex;
  flex-direction: column;
  min-width: 15rem;
  max-width: min(22rem, calc(100vw - 2rem));
  padding: var(--s-2);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-lift);
}
.menu-who {
  margin: 0;
  padding: var(--s-2) var(--s-3);
  color: var(--muted);
  font-size: var(--type-small);
  overflow-wrap: anywhere;
}
.menu a,
.menu .menu-item {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  padding: 0 var(--s-3);
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font-family: var(--body);
  font-size: var(--type-body);
  font-weight: 400;
  letter-spacing: 0;
  text-align: left;
  text-decoration: none;
  box-shadow: none;
}
.menu a:hover,
.menu .menu-item:hover:not(:disabled) {
  background: var(--fill);
}
.menu a[aria-current="page"] {
  font-weight: 600;
}
.menu hr {
  width: 100%;
  margin: var(--s-1) 0;
  border: 0;
  border-top: 1px solid var(--line);
}

.tab-bar {
  display: none;
}

/* The smallest phones: the mark and both visitor links have to fit in
   320px, so the mark and the spacing give way, never the links. */
@media (max-width: 24rem) {
  .site-bar {
    gap: var(--s-2);
    padding: var(--s-2) var(--s-3);
  }
  header img {
    max-width: 104px;
  }
  .site-nav {
    gap: 0;
  }
  .site-nav a {
    padding: 0 var(--s-2);
  }
}

@media (min-width: 48rem) {
  .app-nav:not([hidden]) {
    display: flex;
    gap: var(--s-1);
  }
}

@media (max-width: 47.999rem) {
  /* The menu's button is a round initial here; the address stays its name. */
  .account-menu #account-button {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
    border-radius: 50%;
  }
  .account-menu #account-button::after {
    display: none;
  }
  .account-initial {
    display: inline;
  }
  #account-email {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  .tab-bar:not([hidden]) {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    display: flex;
    padding: 0 var(--s-2) env(safe-area-inset-bottom);
    background: var(--bar);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    box-shadow: 0 -1px 0 var(--line);
  }
  .tab-bar a {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 3.25rem;
    color: var(--muted);
    font-size: var(--type-micro);
    font-weight: 500;
    text-decoration: none;
  }
  .tab-bar a[aria-current="page"] {
    color: var(--accent-ink);
  }
  .tab-bar svg {
    width: 22px;
    height: 22px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  /* Nothing hides behind the tab bar, and nothing focused scrolls under it. */
  body.signed-in {
    padding-bottom: calc(3.25rem + env(safe-area-inset-bottom));
  }
  html:has(body.signed-in) {
    scroll-padding-bottom: calc(3.25rem + env(safe-area-inset-bottom));
  }
}

@media (prefers-reduced-transparency: reduce) {
  .site-header,
  .tab-bar:not([hidden]) {
    background: var(--paper);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .site-header::after {
    background: none;
  }
}

/* ── Surfaces ───────────────────────────────────────────────────────────── */

.card.enclosed,
.share,
.dropzone {
  background: var(--surface);
  border: 0;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.card.enclosed {
  padding: 0.25rem 1.25rem;
  margin: 1rem 0;
}

/* Section cards on the account and business pages: a heading above a group,
   the way a settings screen titles its sections. */
.card {
  border-top: 0;
  margin-top: 2.5rem;
  padding-top: 0;
}

/* ── Drop zone ──────────────────────────────────────────────────────────── */

main:has(#upload) {
  max-width: 40rem;
}
/* The request's form at the home page's width, but LEFT where the masthead's
   small tagline is: an inner page's column starts under its header. */
#request-upload {
  max-width: 37rem;
}
/* The request's facts and its send button take the column the drop zone does,
   not the prose measure: they are one form, and three widths read as three. */
#request-upload .meta li,
#request-upload p:has(> button) {
  max-width: none;
}
#request-upload p:has(> button) button {
  width: 100%;
}
.dropzone {
  margin-top: 0.5rem;
  padding: 2.75rem 1.5rem 2.5rem;
  outline: 1.5px dashed transparent;
  outline-offset: -10px;
  transition: transform var(--dur-press) ease-out, box-shadow var(--dur-move) ease, outline-color var(--dur-move) ease,
    background var(--dur-move) ease;
}
.dropzone::before {
  content: "";
  display: block;
  width: 3rem;
  height: 3rem;
  margin: 0 auto 1rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 14%, transparent)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23248793' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 17V6M7 10.5 12 5.5l5 5'/%3E%3C/svg%3E")
    center / 1.5rem no-repeat;
}
.dropzone:hover,
.dropzone:focus-visible {
  border-color: transparent;
  background: var(--surface);
  box-shadow: var(--shadow-lift);
}
.dropzone.is-over {
  outline-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, var(--surface));
  box-shadow: var(--shadow-lift);
  transform: scale(1.01);
}
.dropzone:active {
  transform: scale(0.99);
}
.dropzone .prompt {
  font-family: var(--body);
  font-size: var(--type-lede);
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--text);
  margin-bottom: 0.25rem;
}
.dropzone .hint {
  display: block;
  max-width: 26rem;
  margin: 0 auto;
  font-size: var(--type-small);
  line-height: 1.4;
}

/* ── Grouped form rows ──────────────────────────────────────────────────── */

.options > .field,
.options > .field:first-child,
.options > .field:last-child {
  padding: 0.75rem 0;
  border-top: 0.5px solid var(--line);
}
.options > .field:first-child {
  border-top: 0;
}
@media (min-width: 40rem) {
  .options > .field > label {
    color: var(--text);
    font-weight: 400;
    padding-top: 0.55rem;
  }
}
@media (max-width: 39.999rem) {
  .options > .field > label {
    font-weight: 500;
    font-size: var(--type-label);
    color: var(--muted);
  }
}
.field .hint {
  font-size: var(--type-micro);
  line-height: 1.35;
}
/* A refused link name, under its field rather than under the send button. */
.field .name-error {
  margin: var(--s-2) 0 0;
  font-size: var(--type-small);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
textarea,
select,
.named-link {
  min-height: 2.5rem;
  border: 0;
  border-radius: var(--radius);
  background: var(--fill);
  box-shadow: 0 0 0 0 transparent;
  transition: box-shadow var(--dur-quick) ease, background var(--dur-quick) ease;
}
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
textarea,
select {
  padding: 0.5rem 0.8rem;
}
select {
  appearance: none;
  padding-right: 2.25rem;
  background: var(--fill)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%238e8e93' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 4.75 6 2.25l2.5 2.5M3.5 7.25 6 9.75l2.5-2.5'/%3E%3C/svg%3E")
    right 0.75rem center / 0.75rem no-repeat;
}
input[type="text"]:hover,
input[type="email"]:hover,
input[type="password"]:hover,
input[type="number"]:hover,
textarea:hover,
select:hover,
.named-link:hover {
  border-color: transparent;
}
input[type="text"]:focus-visible,
input[type="email"]:focus-visible,
input[type="password"]:focus-visible,
input[type="number"]:focus-visible,
textarea:focus-visible,
select:focus-visible,
.named-link:focus-within {
  background-color: var(--surface);
  box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent);
}
.named-link input,
.named-link input:focus-visible {
  background: none;
  box-shadow: none;
  padding-left: 0;
}
.named-prefix {
  background: none;
  padding: 0 0 0 0.8rem;
}

/* ── Buttons ────────────────────────────────────────────────────────────── */

button,
.cta {
  font-family: var(--body);
  font-size: var(--type-body);
  font-weight: 600;
  letter-spacing: -0.01em;
  border-radius: var(--radius);
  padding: 0.65rem 1.35rem;
  min-height: 2.75rem;
  box-shadow: none;
  transition: transform var(--dur-press) ease-out, background var(--dur-quick) ease;
}
/* DARKER ON HOVER IN LIGHT, lighter in dark (--accent-press), so the label
   gains contrast instead of losing it. brightness(1.08) lifted the teal to
   about 4.2:1 against white, under AA for the label. DESIGN.md V4. */
button:hover:not(:disabled),
.cta:hover {
  background: var(--accent-press);
  box-shadow: none;
}
button:active:not(:disabled),
.cta:active {
  transform: scale(0.97);
  box-shadow: none;
}
.cta {
  display: inline-flex;
  align-items: center;
}
#send {
  width: 100%;
  min-height: 3.25rem;
  font-size: var(--type-body);
  border-radius: var(--radius);
  margin-top: 0.25rem;
}
#copy {
  font-size: var(--type-small);
  border-radius: var(--radius);
}

/* ── Status ─────────────────────────────────────────────────────────────── */

.progress {
  height: 6px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--fill);
}
.progress > span {
  background: var(--accent);
  border-radius: var(--radius-sm);
}
.link-out {
  font-size: var(--type-label);
}
.notice {
  border: 0;
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
  font-size: var(--type-small);
  line-height: 1.45;
}
#result {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 1.5rem 1.25rem;
}

/* ── Account: shares as grouped lists ───────────────────────────────────── */

.share {
  padding: 1rem 1.25rem 1.1rem;
  margin-bottom: 0.875rem;
}
.share-id {
  font-size: var(--type-body);
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-bottom: 0.25rem;
}
.meta {
  border-top: 0;
  margin: 0.5rem 0;
}
.meta li {
  padding: 0.55rem 0;
  border-bottom: 0.5px solid var(--line);
  font-size: var(--type-small);
}
.meta li:last-child {
  border-bottom: 0;
}
.meta li span:last-child {
  font-variant-numeric: tabular-nums;
}
.share-actions {
  gap: 0.5rem;
  margin-top: 0.5rem;
}
.share-actions a,
.share-actions .revoke {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  padding: 0 0.9rem;
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--accent-ink);
  font-size: var(--type-label);
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--dur-press) ease-out, background var(--dur-quick) ease;
}
/* A BUTTON THAT IS THE ROW'S MAIN ACTION — download, on a file sent to a
   request — in the same pill as the links beside it, filled with the accent
   so it still reads as the thing to press. The form-sized default button sat
   twice the height of its neighbours. */
.share-actions .action {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  padding: 0 0.9rem;
  border-radius: var(--radius-pill);
  font-size: var(--type-label);
  font-weight: 600;
}
.share-actions .revoke {
  color: var(--revoke);
  background: color-mix(in srgb, var(--revoke) 10%, transparent);
}
.share-actions .revoke:hover:not(:disabled) {
  opacity: 1;
  filter: none;
  background: color-mix(in srgb, var(--revoke) 16%, transparent);
}
.share-actions a:active,
.share-actions .revoke:active:not(:disabled) {
  transform: scale(0.96);
}
.revoke {
  text-decoration: none;
  font-weight: 600;
}

/* ── Long-form pages ────────────────────────────────────────────────────── */

.lede {
  font-size: var(--type-lede);
  line-height: 1.42;
  letter-spacing: -0.008em;
}
main h2 {
  margin-top: 2.75rem;
}
.retention th,
.endpoints th {
  font-family: var(--body);
  font-size: var(--type-micro);
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}
.retention th,
.retention td,
.endpoints th,
.endpoints td {
  border-bottom-width: 0.5px;
}
.price {
  font-family: var(--body);
  font-size: var(--type-title);
  font-weight: 700;
  letter-spacing: -0.022em;
}
pre {
  background: var(--surface);
  border: 0.5px solid var(--line);
  border-radius: var(--radius);
  padding: 0.9rem 1rem;
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.footer {
  border-top: 0.5px solid var(--line);
  margin-top: 4rem;
  font-size: var(--type-micro);
  align-items: center;
}
.footer > span:first-child {
  color: var(--muted);
  font-size: var(--type-micro);
}
.footer a {
  color: var(--text);
  text-decoration: none;
}
.footer a:hover {
  text-decoration: underline;
}
.footer-links {
  gap: 0.2rem 1.25rem;
}

/* The theme picker as a segmented control: a recessed track, and the chosen
   segment a raised surface that sits in it. */
.theme {
  border: 0;
  border-radius: var(--radius);
  background: var(--fill);
  padding: 2px;
}
.theme-option {
  width: 32px;
  height: 26px;
  border-radius: var(--radius);
}
.theme-option:hover {
  background: none;
}
.sr-only:checked + .theme-option {
  color: var(--text);
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 0 0 0.5px rgba(0, 0, 0, 0.04);
}

/* ── Accessibility preferences ──────────────────────────────────────────── */

@media (prefers-contrast: more) {
  .card.enclosed,
  .share,
  .dropzone,
  #result,
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="number"],
  textarea,
  select,
  .named-link {
    border: 1px solid var(--text);
  }
}
@media (prefers-reduced-motion: reduce) {
  .dropzone.is-over,
  .dropzone:active,
  button:active:not(:disabled),
  .cta:active {
    transform: none;
  }
}

/* ── Second pass: details found in the screenshots ─────────────────────── */

button,
.cta,
.cta:hover {
  color: var(--on-accent);
}
.receipt-note {
  border-top: 0;
  padding-top: 0;
}
.share .meta li,
#team .meta li {
  max-width: none;
}
/* The settings' cards are .settings-card (below); the team section is only
   the group that holds its cards. */
#team h2,
#api-keys h2 {
  margin-top: 0;
}
#team-add-form label,
#key-form label {
  display: block;
  font-size: var(--type-label);
  font-weight: 500;
  color: var(--muted);
  margin-bottom: 0.35rem;
}
#team-add-form .hint,
#key-form .hint {
  font-size: var(--type-micro);
  color: var(--muted);
  margin: 0.35rem 0 0.75rem;
}
li.share {
  max-width: none;
}
#result h2 {
  margin-top: 0;
}

/* ── Sign-in buttons ───────────────────────────────────────────────────────
   One stack: every way in is a full-width button of the same height with its
   mark on the left. The link is the primary one, in the teal, because it is
   the only way to make an account and the way everybody else gets in; the
   rest are the second choices beside it.

   GOOGLE AND MICROSOFT LOOK THE WAY THEY ASK. Their marks are unaltered
   (signin-icons.ts) and the button around them is Google's light or dark
   style, never the teal: a "Continue with Google" in our colours is a
   button Google's branding guidelines do not allow. The passkey button wears
   the same style so the second choices read as one group. Last in the file
   so the button rules above, which set the teal and its hover, lose. */
.signin-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  /* The label is centred, so the usual 1.35rem sides only take room from it.
     Narrow, because "Log ind med adgangsnøgle" has to fit on one line on a
     320px phone, or one button in the stack is taller than the others. */
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}
/* The narrowest phones (320px) need more: "Log ind med adgangsnøgle" is
   still a few pixels too long there. A step down in type, narrower button
   sides, and a narrower inset for the form and the alternatives together,
   so their buttons keep one edge. */
@media (max-width: 22.5rem) {
  .signin-button {
    font-size: var(--type-small);
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  #signin.card.enclosed,
  #signin-alternatives {
    padding-left: 1rem;
    padding-right: 1rem;
  }
}
.signin-button svg {
  width: 20px;
  height: 20px;
  flex: none;
}
button.signin-brand,
button.signin-brand:hover:not(:disabled) {
  background: var(--idp-fill);
  color: var(--idp-text);
  box-shadow: inset 0 0 0 1px var(--idp-line);
  filter: none;
}
button.signin-brand:hover:not(:disabled) {
  background: var(--idp-hover);
}

/* THE ONE MULTI-LINE FIELD (the business inquiry on /bedrift). It shares every
   rule the single-line fields have, above; this only gives it room to write
   in and lets it grow downwards, never sideways out of the card. */
textarea {
  display: block;
  max-width: 36rem;
  min-height: 8rem;
  resize: vertical;
  line-height: 1.45;
}

/* ── The embeddable request form (/e/<id>, embed.ts) ────────────────────── */

/* INSIDE SOMEBODY ELSE'S PAGE, so it takes the frame it is given rather than
   the site's column and margins: no masthead, no footer, a little air. */
body.embed main.container {
  max-width: 40rem;
  padding: 1rem;
}
body.embed #request-upload {
  max-width: none;
}
body.embed h1 {
  margin-top: 0;
}

/* The embed controls on a request's row on /konto: set apart from the facts
   above them, with the same small label and hint the other forms use. */
.embed-settings {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}
.embed-settings .share-title {
  font-size: var(--type-label);
  font-weight: 500;
  color: var(--muted);
  margin: 0 0 0.35rem;
}
.embed-settings input {
  width: 100%;
}
.embed-settings .hint {
  font-size: var(--type-micro);
  color: var(--muted);
  margin: 0.35rem 0 0.75rem;
}

/* ── Lists and dialogs (DESIGN.md §3.3, §6) ─────────────────────────────────
   Delt, Mottatt and the team's shares are rows in one surface, not a card per
   share: a title, why there is no name or from whom, the facts, and at the
   end the ⋯ menu or "Åpne". Rows are parted by a hairline inset from the
   left, as the list-row component asks. */

.shares.rows {
  /* One radius for the list and its end rows: a hovered first or last row
     paints its corners, and square ones stood out from the list's round
     ones. Reported. Not overflow: hidden, which would clip a row's ⋯ menu. */
  --rows-radius: var(--radius-lg);
  background: var(--surface);
  border-radius: var(--rows-radius);
  box-shadow: var(--shadow);
}
.rows > .row:first-child {
  border-top-left-radius: var(--rows-radius);
  border-top-right-radius: var(--rows-radius);
}
.rows > .row:last-child {
  border-bottom-left-radius: var(--rows-radius);
  border-bottom-right-radius: var(--rows-radius);
}
.rows > .row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 56px;
  margin: 0;
  padding: var(--s-3) var(--s-4);
  background: none;
  border-radius: 0;
  box-shadow: none;
  position: relative;
}
.rows > .row + .row::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--s-4);
  right: 0;
  border-top: 0.5px solid var(--line);
}
.row-text {
  flex: 1;
  min-width: 0;
}
.row-text p {
  margin: 0;
}
.row-title {
  font-size: var(--type-body);
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}
.row-title .share-id,
.row-sub .share-id {
  margin: 0;
  font-weight: 600;
}
.row-sub .share-id {
  font-size: var(--type-small);
  font-weight: 400;
}
.row-sub,
.row-meta {
  font-size: var(--type-small);
  color: var(--muted);
}
.row-meta {
  font-variant-numeric: tabular-nums;
}
.row-meta span[title] {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
}
.row-end {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex: none;
}
.row-open {
  min-height: 44px;
  padding: 0 var(--s-4);
  border-radius: var(--radius-pill);
  font-size: var(--type-label);
}
.row-menu {
  position: relative;
}
.row-menu .row-more {
  width: 44px;
  min-height: 44px;
  padding: 0;
  border-radius: 50%;
  background: none;
  color: var(--muted);
  font-family: var(--body);
  font-size: var(--type-heading);
  line-height: 1;
  box-shadow: none;
}
.row-menu .row-more:hover:not(:disabled) {
  background: var(--fill);
  color: var(--text);
}
.row-menu .menu {
  top: calc(100% + var(--s-1));
}
.menu .revoke {
  color: var(--revoke);
  text-decoration: none;
  font-weight: 400;
}
.menu .revoke:hover:not(:disabled) {
  opacity: 1;
  background: color-mix(in srgb, var(--revoke) 10%, transparent);
}

/* ── Be om filer (DESIGN.md §3.4) ─────────────────────────────────────────────
   A row per request, as Delt has; "Ny forespørsel" above the list opens the
   short form; a request's link and embed settings open beneath its row; the
   closed ones are folded away under the list. */
.request-actions {
  margin: var(--s-4) 0;
}
.field-pair {
  display: grid;
  column-gap: var(--s-4);
}
@media (min-width: 40rem) {
  .field-pair {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}
.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: var(--s-4) 0 0;
}
/* EVERY ROW OPENS BENEATH ITSELF (app.ts, expandableRow). The detail takes a
   line of its own under the row; the text's zero basis keeps a long title
   from pushing the ⋯ down after it. */
.rows > .row {
  flex-wrap: wrap;
}
.rows > .row > .row-text {
  flex: 1 1 0;
}
/* The row's disclosure: a button that looks like the row's text, with a
   chevron that turns as it opens. The whole row reacts to the pointer. */
.rows > .row:has(> .row-toggle[aria-expanded="false"]) {
  cursor: pointer;
}
.rows > .row:has(> .row-toggle[aria-expanded="false"]):hover {
  background: var(--sunk-tint);
}
.row-toggle {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  box-shadow: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: left;
  cursor: pointer;
}
.row-toggle:hover:not(:disabled),
.row-toggle:active:not(:disabled) {
  background: none;
  box-shadow: none;
  transform: none;
}
.row-toggle:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}
.row-words {
  flex: 1;
  min-width: 0;
}
.row-words > .row-title,
.row-words > .row-sub,
.row-words > .row-meta {
  display: block;
}
/* On the title's line, however many lines follow it: centred on its 1.5em
   line box. */
.row-chevron {
  flex: none;
  align-self: flex-start;
  margin-top: 0.525em;
  width: 0.45em;
  height: 0.45em;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform var(--dur-quick) var(--ease-out);
}
.row-toggle[aria-expanded="true"] .row-chevron {
  transform: rotate(45deg);
}
@media (prefers-reduced-motion: reduce) {
  .row-chevron {
    transition: none;
  }
}
.row-detail {
  flex: 0 0 100%;
  min-width: 0;
  padding: var(--s-2) 0;
}
/* The facts in full, then whatever else the row has. */
.row-detail .meta {
  margin: 0;
}
.row-detail .meta + * {
  margin-top: var(--s-3);
}
.row-link + .meta {
  margin-top: var(--s-2);
}
.row-detail .hint {
  margin: 0 0 var(--s-2);
  font-size: var(--type-small);
  color: var(--muted);
}
.closed-requests {
  margin-top: var(--s-5);
}
/* The summary is "Flere valg"'s (.more-options): its triangle, its 44px. */
.closed-requests[open] > summary {
  margin-bottom: var(--s-2);
}

.empty {
  padding: var(--s-6) var(--s-4);
  text-align: center;
  color: var(--muted);
}
.empty a {
  display: inline-block;
  margin-top: var(--s-2);
}

.notice.locked .link-row {
  max-width: 28rem;
}

/* The confirmation: a native modal dialog, its question as the title and its
   consequence beneath, "Avbryt" first and focused, the destructive verb in
   --revoke. */
.dialog {
  width: min(28rem, calc(100vw - 2rem));
  padding: var(--s-5);
  border: 0;
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lift);
}
.dialog::backdrop {
  background: rgba(0, 0, 0, 0.4);
}
.dialog h2 {
  font-size: var(--type-heading);
  margin: 0 0 var(--s-2);
  overflow-wrap: anywhere;
}
.dialog p {
  margin: 0 0 var(--s-5);
  color: var(--muted);
}
.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.dialog-actions button {
  min-height: 44px;
  font-size: var(--type-body);
}
.dialog .dialog-confirm {
  background: var(--revoke);
  color: var(--on-accent);
}
.dialog .dialog-confirm:hover:not(:disabled) {
  background: color-mix(in srgb, var(--revoke) 85%, var(--text));
}

/* A status that needs no navigation ("Lenken er kopiert"): read out politely,
   shown at the foot of the screen above the tab bar, and gone after 4 s. */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--s-6) + env(safe-area-inset-bottom));
  z-index: 40;
  margin: 0;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--paper);
  font-size: var(--type-small);
  opacity: 0;
  transform: translate(-50%, var(--s-2));
  transition: opacity var(--dur-move) var(--ease-out), transform var(--dur-move) var(--ease-out);
  pointer-events: none;
}
.toast.is-shown {
  opacity: 1;
  transform: translate(-50%, 0);
}
@media (max-width: 47.999rem) {
  body.signed-in .toast {
    bottom: calc(3.25rem + var(--s-4) + env(safe-area-inset-bottom));
  }
}
@media (prefers-reduced-motion: reduce) {
  .toast {
    transition: none;
  }
}

/* ── The send form (DESIGN.md §3.2) ─────────────────────────────────────────
   "Flere valg" is a native disclosure whose summary carries the values behind
   it; the delivery choice is two radios, both consequences in view. */

.more-options > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-1) var(--s-2);
  min-height: 44px;
  box-sizing: border-box;
  padding: var(--s-2) 0;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  color: var(--text);
}
.more-options > summary::-webkit-details-marker {
  display: none;
}
/* The disclosure triangle, drawn, turning as it opens. */
.more-options > summary::before {
  content: "";
  flex: none;
  align-self: center;
  width: 0.45em;
  height: 0.45em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-quick) var(--ease-out);
}
.more-options[open] > summary::before {
  transform: rotate(45deg);
}
.summary-values {
  font-size: var(--type-small);
  font-weight: 400;
  color: var(--muted);
}
.more-options[open] .summary-values {
  display: none;
}
.more-options > .options {
  margin-top: var(--s-2);
}
#recipients-field {
  margin-bottom: var(--s-4);
}
#more-options {
  margin-bottom: var(--s-4);
}

.choice {
  grid-column: 1 / -1;
  min-width: 0;
  margin: 0;
  padding: var(--s-3) 0 0;
  border: 0;
  border-top: 0.5px solid var(--line);
}
.choice legend {
  float: left;
  width: 100%;
  margin: 0 0 var(--s-2);
  padding: 0;
  font-size: var(--type-label);
  font-weight: 500;
  color: var(--muted);
}
.choice-option {
  clear: both;
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  min-height: 44px;
  padding: var(--s-2) 0;
  cursor: pointer;
}
.choice-option input {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0.15em 0 0;
  accent-color: var(--accent-ink);
}
.choice-title {
  display: block;
  font-weight: 600;
  color: var(--text);
}
.choice-option .hint {
  display: block;
  margin: var(--s-1) 0 0;
  max-width: none;
  font-size: var(--type-small);
  color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
  .more-options > summary::before {
    transition: none;
  }
}

/* ── Settings (DESIGN.md §3.5) ──────────────────────────────────────────────
   A section list beside the page from 64rem, a row of links above it below
   that; each setting group one card, its heading, one sentence, its controls. */

.container:has(> .settings) {
  max-width: 72rem;
}
.settings-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin: var(--s-4) 0 var(--s-5);
}
.settings-nav[hidden] {
  display: none;
}
.settings-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--s-4);
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-size: var(--type-label);
  font-weight: 500;
  text-decoration: none;
}
.settings-nav a:hover {
  color: var(--text);
  background: var(--fill);
}
.settings-nav a[aria-current="page"] {
  color: var(--text);
  background: var(--fill);
}
.settings-main {
  min-width: 0;
}
@media (min-width: 64rem) {
  .settings {
    display: grid;
    grid-template-columns: 13rem minmax(0, 1fr);
    column-gap: var(--s-7);
    align-items: start;
  }
  .settings-nav {
    position: sticky;
    top: 5rem;
    flex-direction: column;
    margin: clamp(0.5rem, 4vh, 2rem) 0 0;
  }
  .settings-nav a {
    border-radius: var(--radius);
  }
  .settings-main > h1:first-child {
    margin-top: clamp(0.5rem, 4vh, 2rem);
  }
}

.settings-card {
  margin: 0 0 var(--s-5);
  padding: var(--s-5);
}
.settings-card > h2:first-child {
  margin-top: 0;
}
/* A list in a card is part of the card, not a second card stood on it: a
   hairline round it and no shadow of its own. */
.settings-card .shares.rows {
  --rows-radius: var(--radius);
  margin-top: var(--s-4);
  box-shadow: none;
  border: 0.5px solid var(--line);
}
#team > .settings-card:last-child {
  margin-bottom: 0;
}
.saved {
  display: inline-block;
  margin-left: var(--s-2);
  color: var(--ok);
}
#security-start {
  margin-bottom: var(--s-5);
}

/* ── Landing and receiving (DESIGN.md §3.1, §3.6) ───────────────────────────
   The landing under the tagline: one sentence, the way in, three points,
   three steps. A recipient's page: the narrow column, a heading, the file
   card, and for a delivered share its two steps. */

.landing {
  text-align: center;
}
.landing .lede {
  max-width: 34rem;
  margin: var(--s-4) auto 0;
  color: var(--muted);
  font-size: var(--type-lede);
}
.landing-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--s-3) var(--s-5);
  margin: var(--s-5) 0 var(--s-8);
}
.landing-actions .cta {
  min-height: 44px;
  padding: 0 var(--s-5);
}
.landing-secondary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 500;
}
.points {
  display: grid;
  gap: var(--s-5);
  margin: 0 0 var(--s-8);
  padding: 0;
  list-style: none;
  text-align: left;
}
@media (min-width: 48rem) {
  .points {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.points li {
  padding: var(--s-5);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.points svg {
  fill: none;
  stroke: var(--accent-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.points h2 {
  margin: var(--s-3) 0 var(--s-1);
  font-size: var(--type-body);
}
.points p {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-small);
}
.landing > h2 {
  font-size: var(--type-heading);
}
.how {
  display: inline-grid;
  gap: var(--s-3);
  margin: var(--s-2) 0 var(--s-7);
  padding: 0;
  list-style: none;
  counter-reset: step;
  text-align: left;
}
.how li {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  counter-increment: step;
}
.how li::before {
  content: counter(step);
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--fill);
  color: var(--text);
  font-size: var(--type-label);
  font-weight: 600;
}
.landing-recipients {
  color: var(--muted);
  font-size: var(--type-small);
}

.container.narrow {
  max-width: 30rem;
}
.file-card {
  padding: var(--s-5);
  margin-bottom: var(--s-4);
}
.file-name {
  margin: 0 0 var(--s-3);
  font-size: var(--type-heading);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.file-card .meta {
  margin-top: 0;
}
.steps {
  display: flex;
  gap: var(--s-2);
  margin: var(--s-4) 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}
.steps li {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding-top: var(--s-2);
  border-top: 2px solid var(--line);
  color: var(--muted);
  font-size: var(--type-label);
  counter-increment: step;
}
.steps li::before {
  content: counter(step);
  font-weight: 600;
}
.steps li[aria-current="step"] {
  border-top-color: var(--accent-ink);
  color: var(--text);
  font-weight: 600;
}
