/* Mobile first. The only breakpoint is 40rem — beyond that the layout just gets
   a wider column and a slightly larger logo. */

/* Typography and colour follow ghostdiving.de so the two read as one
   organisation: Red Hat Text for headings and chrome, Montserrat for body copy.
   Measured off the live site, see PLAN.md 6.1b.

   The fonts are pulled in with a <link> in each <head>, not @import here --
   @import is discovered only after this file has been parsed, which delays the
   font request by a whole round trip. */
:root {
  --gdg-font-heading: 'Red Hat Text', system-ui, -apple-system, sans-serif;
  --gdg-font-body: Montserrat, system-ui, -apple-system, sans-serif;

  --gdg-blue-dark: #35718c; /* headings, links, buttons on ghostdiving.de */
  --gdg-blue-deep: #2b5a70; /* darker sections there; used for hover/pressed */
  --gdg-blue-light: #8bd3f6; /* light accent from the logo and nav */
  --gdg-blue-pale: #ebf8ff; /* the site's pale panel fill */
  --gdg-text: #424241; /* their heading grey, near-black but warmer */
  --gdg-body: #606e74; /* their body grey */
  --gdg-bg: #ffffff;
  --gdg-muted: #606e74;

  /* Two greys, because WCAG treats them differently. --gdg-border outlines
     things you operate -- inputs, buttons -- and 1.4.11 wants 3:1 against the
     page for those; this one measures 3.38. --gdg-rule is for lines that merely
     separate (the footer, the map frame), which carry no state and are exempt.
     Using the accessible grey everywhere would make the page look caged. */
  --gdg-border: #7a8f99;
  --gdg-rule: #d4dde1;

  --gdg-error: #a8321e;
  --gdg-radius: 6px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0 1rem 3rem;
  font-family: var(--gdg-font-body);
  font-size: 1rem;
  line-height: 1.6; /* ghostdiving.de runs 28.8/18 = 1.6 */
  color: var(--gdg-body);
  background: var(--gdg-bg);
}

header,
main,
footer {
  max-width: 42rem;
  margin: 0 auto;
}

/* A visible focus ring everywhere. The default outline disappears against the
   dark buttons, so it is redeclared rather than removed. */
:focus-visible {
  outline: 3px solid var(--gdg-blue-dark);
  outline-offset: 2px;
}

/* Header */

header {
  padding: 0.25rem 0 0.5rem;
  text-align: center;
}

header img {
  max-width: 220px;
  height: auto;
}

/* The logo links home on every page except the form itself -- there it would be
   a self-link, and a mistaken click would reload a filled-in form and empty it.
   inline-block because an inline box leaves a baseline gap under the image. */
.home-link {
  display: inline-block;
}

.subtitle {
  margin: 0.5rem 0 0;
  color: var(--gdg-muted);
  font-size: 0.9rem;
}

/* Language switch: two flag links top right, above the logo. Plain links rather
   than a toggle button, so the target language is visible before clicking and
   the page works without JavaScript.

   Deliberately quiet — this is chrome, not a call to action. No boxes, no fill;
   the tap target is padding, not something you can see. */
.lang-switch {
  display: flex;
  justify-content: flex-end;
  margin-right: -0.5rem; /* pulls the padding back to the content edge */
}

.lang-option {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 44px; /* thumb-sized tap target, invisible */
  padding: 0 0.5rem;
  color: var(--gdg-muted);
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  text-decoration: none;
}

.lang-option img {
  display: block;
  opacity: 0.55;
  border: 1px solid var(--gdg-rule); /* keeps the white in each flag visible */
}

/* Three cues for the active language, none of them colour alone: weight, the
   underline, and a flag at full strength. The flags cannot carry this by
   themselves — a flag is a country, not a language, and telling two small
   rectangles apart is exactly what colour blindness makes hard. */
.lang-option[aria-current="true"] {
  color: var(--gdg-blue-dark);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.lang-option[aria-current="true"] img {
  opacity: 1;
}

/* Main */

/* ghostdiving.de sets its headings in Red Hat Text at regular weight, not bold.
   Copying that keeps the pages recognisably theirs; size carries the hierarchy
   instead of weight. */
h1,
h2,
legend {
  font-family: var(--gdg-font-heading);
  font-weight: 400;
  color: var(--gdg-text);
}

h1 {
  margin: 1.5rem 0 0.75rem;
  font-size: 1.75rem;
  line-height: 1.2;
}

h2 {
  font-size: 1.3rem;
}

.trust {
  margin: 0 0 1.5rem;
  padding: 0.9rem 1rem;
  border-left: 4px solid var(--gdg-blue-light);
  background: var(--gdg-blue-pale);
  border-radius: 0 var(--gdg-radius) var(--gdg-radius) 0;
  font-size: 0.95rem;
}

/* The two promise paragraphs sit on separate lines rather than running together:
   the second is the one people actually weigh before filling anything in, and
   buried mid-paragraph it reads as boilerplate. */
.trust p {
  margin: 0;
}

.trust p + p {
  margin-top: 0.4rem;
}

/* The promise gets a heading rather than a bold run-in. It is the paragraph
   people weigh before entering anything, and a heading is what a screen reader
   can jump to -- a <strong> is only loud, not navigable.

   Body font, bold, body grey -- not the heading font and heading colour the h2
   rule would otherwise give it. Inside a box of running text those would read as
   a second voice; matching the box's own text makes the title look like emphasis
   that grew, which is what it is.

   A size or two up from the box's 0.95rem, and no more. At full h2 size it would
   outrank "Position" below it, which titles a whole section rather than one
   paragraph. */
.trust-title {
  margin: 0.9rem 0 0.2rem;
  font-family: var(--gdg-font-body);
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--gdg-body);
}

/* Whatever leads the box sits directly under its top padding, so the gap the
   heading otherwise carries above it is dropped there. */
.trust > :first-child {
  margin-top: 0;
}

/* Progress and rejections for the metadata strip, under the file input. Quieter
   than the map's status line and without its reserved height: that one holds a
   line open so the fields below cannot jump, this one is hidden until there is
   something to say and is the last thing in its field either way.

   Rejections are the same red as a form error, because that is what they are --
   a file the reporter chose and is not getting. Not a warning colour for the
   progress line above them, though: preparing images is the normal case. */
.images-status {
  margin: 0.3rem 0 0;
  color: var(--gdg-muted);
  font-size: 0.85rem;
}

.images-errors {
  margin: 0.3rem 0 0;
  padding-left: 1.1rem;
  color: var(--gdg-error);
  font-size: 0.85rem;
}

/* Form */

fieldset {
  margin: 0 0 1.75rem;
  padding: 0;
  border: none;
}

legend {
  padding: 0;
  font-size: 1.3rem;
}

.field {
  margin: 1rem 0 0;
}

.field label {
  display: block;
  margin-bottom: 0.3rem;
  font-weight: 500;
  color: var(--gdg-text);
}

.hint {
  margin: 0.3rem 0 0;
  color: var(--gdg-muted);
  font-size: 0.85rem;
}

input[type="text"],
input[type="number"],
input[type="file"],
textarea {
  width: 100%;
  padding: 0.6rem;
  border: 1px solid var(--gdg-border);
  border-radius: var(--gdg-radius);
  font: inherit;
  color: inherit;
  background: var(--gdg-bg);
}

textarea {
  min-height: 6rem;
  resize: vertical;
}

/* Map */

/* Point, circle, rectangle -- ordered most precise to least. A point is one
   coordinate, a circle adds a radius, a rectangle covers the largest area for
   the same effort. Reading left to right therefore means giving up precision,
   which is the tradeoff the reporter is actually making.

   The bar sits on top of the map, not above it. As page-level buttons these were
   three full-width blue blocks competing with the submit button, and with the
   clear button below the map they cost roughly 120px before the map even began.
   Here they cost 44px of map, along its top edge rather than over the middle,
   and the clear button costs nothing until there is something to clear.

   Leaflet moves these nodes into the map once it loads; the margin below is what
   they look like in the fraction of a second before that, and with JavaScript
   off. */
.map-modes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0 0.75rem;
}

.map-modes button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  flex: 1 1 auto;
  min-height: 2.75rem; /* comfortable touch target */
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--gdg-blue-dark);
  border-radius: var(--gdg-radius);
  background: var(--gdg-bg);
  color: var(--gdg-blue-dark);
  font: inherit;
  cursor: pointer;
}

.map-modes button:hover {
  border-color: var(--gdg-blue-deep);
  color: var(--gdg-blue-deep);
}

.map-modes button[aria-pressed="true"] {
  /* The pale accent needs a darker outline: on its own it measures 1.65 against
     the page, so the pressed button would have no discernible edge. The border
     carries the 3:1 that WCAG 1.4.11 asks of a control, and the text on top
     measures 8.5. */
  background: var(--gdg-blue-light);
  border-color: var(--gdg-blue-deep);
  color: #04303f;
  font-weight: 600;
}

/* Once Leaflet has adopted the bar it becomes one object floating on the map,
   so the per-button borders give way to hairlines between segments. Same idea as
   Leaflet's own zoom control, which is why it can sit in the opposite corner
   without looking like a different site's widget. */
.leaflet-control.map-modes {
  margin: 0.6rem;
  gap: 0;
  border: 1px solid var(--gdg-border);
  border-radius: var(--gdg-radius);
  /* Not fully opaque: the map stays faintly readable underneath, which makes the
     bar feel like part of the map instead of a lid on it. */
  background: rgb(255 255 255 / 0.94);
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.2);
  overflow: hidden;
}

.leaflet-control.map-modes button {
  flex: 0 0 auto;
  border: none;
  border-radius: 0;
  background: transparent;
  padding: 0.5rem 0.7rem;
  font-size: 0.9rem;
}

.leaflet-control.map-modes button + button {
  border-left: 1px solid var(--gdg-rule);
}

.leaflet-control.map-modes button:hover {
  background: var(--gdg-blue-pale);
}

/* Repeated for the in-map bar, because the transparent background above has the
   same specificity as the pressed rule further up and would otherwise win on
   source order -- leaving the active mode marked by text colour alone, which is
   exactly what WCAG 1.4.1 rules out. The pale fill needs no border here: the
   hairlines between segments already draw the edge. */
.leaflet-control.map-modes button[aria-pressed="true"] {
  background: var(--gdg-blue-light);
  color: #04303f;
  font-weight: 600;
}

/* Clear is an action, not a mode -- it undoes work rather than selecting how to
   do it. In the map it goes to the far corner from the modes, diagonally
   opposite, so it cannot read as a fourth mode. Bottom left rather than bottom
   right: the attribution owns that corner, and the two would overlap. Muted
   grey, not red: the step is repeatable and harmless, and a warning colour would
   overstate it. */
.map-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  min-height: 2.75rem;
  margin-top: 0.5rem;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--gdg-border);
  border-radius: var(--gdg-radius);
  background: var(--gdg-bg);
  color: var(--gdg-muted);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}

.leaflet-control.map-clear {
  width: auto;
  margin: 0.6rem;
  background: rgb(255 255 255 / 0.94);
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.2);
}

.map-clear:hover {
  border-color: var(--gdg-muted);
  color: var(--gdg-text);
}

/* Leaflet sets its own colours and sizes on controls. Its zoom buttons are 30px,
   or 30px again under .leaflet-touch, which is below the 44px this project
   committed to in 6.1a -- and zoom is the one map control someone will reach for
   repeatedly on a moving boat. The .leaflet-touch prefix is needed to outweigh
   Leaflet's own rule of the same shape. */
.leaflet-control-zoom a,
.leaflet-touch .leaflet-control-zoom a {
  width: 44px;
  height: 44px;
  line-height: 44px;
  color: var(--gdg-blue-dark);
}

.leaflet-control-zoom a:hover {
  color: var(--gdg-blue-deep);
}

/* The shape itself can be moved. touch-action: none is the load-bearing part:
   without it the browser claims the first vertical movement as a page scroll and
   the shape never moves at all. Leaflet sets pan-x pan-y on the map container,
   so this has to be stated on the path. */
.map-draggable {
  cursor: move;
  touch-action: none;
}

/* Drag handles: a 44px hit area with a 22px arrow drawn in the middle of it.

   The handle sits outside the shape, on the north-east diagonal, joined to the
   edge by a short line. Not on the edge, where it used to be: Leaflet's marker
   pane is above the path pane, so a block lying half over the shape took every
   press meant for the shape body -- and shrinking the block to stop that left
   three pixels of margin around the dot, so a press that looked dead-centre
   missed. Beside the shape, the block can stay 44px and always live.

   Off the shape, position no longer says what the handle does, so the icon has
   to. The double-headed diagonal arrow is what every desktop shows as the resize
   cursor; here it is drawn rather than hovered, because a phone has no hover. */
.map-handle {
  /* Leaflet gives every divIcon a white background and a border. */
  background: none;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  /* nesw, not nwse: the handle sits north-east of the shape, so its axis runs
     south-west to north-east -- the same slash the drawn arrow points along. */
  cursor: nesw-resize;
}

/* The arrow is stroked twice from the same path: a wide white line underneath,
   the dark one on top. Sea, coastline and place names are all under this at some
   point, and a single-colour arrow disappears against at least one of them. */
.map-handle-halo {
  stroke: #fff;
  stroke-width: 4.5;
  opacity: 0.9;
}

.map-handle-arrow {
  stroke: var(--gdg-blue-deep);
}

/* Coordinates of the marking, typed or echoed back. Tabular figures so the two
   numbers line up under each other the way they do on a chart, and a slightly
   smaller size because a full DDM pair is long and must not wrap on a phone. */
.coords {
  font-variant-numeric: tabular-nums;
  font-size: 0.95rem;
}

/* An input the parser could not read. Same red as the form-level error, but a
   plain line rather than a boxed block: it belongs to the field above it, not
   to the form. */
.field-error {
  margin: 0.3rem 0 0;
  color: var(--gdg-error);
  font-size: 0.85rem;
}

/* A size: a box you can type into, and a slider next to it. The box is narrow
   and fixed, the slider takes what is left -- the number is four digits at most,
   and every pixel past that comes out of the slider's travel. */
.size-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.size-number {
  flex: 0 0 5.5rem;
  width: 5.5rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.size-range {
  flex: 1 1 auto;
  min-width: 0; /* without this the slider refuses to shrink below its default */
}

#radius,
#rect-width,
#rect-height {
  /* The default range track is a few pixels tall. The padding turns the whole
     strip into a 44px grab area without making the track itself look heavy;
     box-sizing: border-box is set globally, so the height has to account for it
     rather than being added to it. */
  height: 44px;
  padding: 0.75rem 0;
  accent-color: var(--gdg-blue-dark);
}

#map {
  height: 22rem;
  border: 1px solid var(--gdg-rule);
  border-radius: var(--gdg-radius);
  background: #eef4f6;
}

/* Honeypot. Off-canvas rather than display:none — some bots skip hidden fields
   but happily fill one that is merely out of sight. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Text for screen readers only: the map's announcements, which are shown to
   everyone else as the coordinate field under the map.

   Clipped in place rather than moved off-canvas like the honeypot above. The two
   look interchangeable and are not: a left: -9999px element that receives focus
   scrolls the page sideways to reach it, and some browsers skip content that far
   outside the viewport when reading. The honeypot wants to look like an ordinary
   field to a bot; this wants to be read and not seen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Submit */

.submit {
  width: 100%;
  min-height: 3rem;
  margin-top: 0.5rem;
  padding: 0.75rem 1.25rem;
  border: none;
  border-radius: var(--gdg-radius);
  background: var(--gdg-blue-dark);
  color: #fff;
  font: inherit;
  font-size: 1.05rem;
  font-weight: 600;
  cursor: pointer;
}

.submit:hover {
  background: var(--gdg-blue-deep);
}

.submit:disabled {
  background: var(--gdg-muted);
  cursor: default;
}

/* Ein Link im Gewand des Absende-Knopfes, für den Weg zurück zum Formular auf
   der Dankeseite. Er teilt sich das Aussehen mit .submit, weil er dieselbe Rolle
   spielt -- die eine Handlung, die die Seite anbietet -- aber nicht dessen
   volle Breite: der Absende-Knopf schließt ein Formular ab, dieser hier steht
   allein unter zwei Zeilen Text und über die ganze Breite gezogen sähe er aus,
   als sei etwas auszufüllen gewesen.

   inline-block, weil ein <a> sonst keine Höhe annimmt und die 3rem
   Mindesthöhe -- die Touch-Zielgröße des Projekts -- wirkungslos bliebe. */
.button-link {
  display: inline-block;
  min-height: 3rem;
  padding: 0.75rem 1.5rem;
  border-radius: var(--gdg-radius);
  background: var(--gdg-blue-dark);
  color: #fff;
  font-weight: 600;
  text-decoration: none;
}

.button-link:hover {
  background: var(--gdg-blue-deep);
}

/* Progress under the submit button. Muted, not a warning colour: uploading is
   the normal case, and this line only exists so the wait does not read as a
   stall. Left-aligned like every other line of text on the page -- centring it
   under the button made it read as a caption on the button rather than as the
   form talking back. */
.form-status {
  margin: 0.5rem 0 0;
  color: var(--gdg-muted);
  font-size: 0.9rem;
}

.form-error {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  border-left: 4px solid var(--gdg-error);
  background: #fdf1ef;
  color: var(--gdg-error);
}

[hidden] {
  display: none !important;
}

/* Footer */

footer {
  margin-top: 3rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--gdg-rule);
  text-align: center;
  font-size: 0.85rem;
  color: var(--gdg-muted);
}

footer nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 0.4rem;
}

footer a {
  /* Padded to a 44px tap target. As bare text these links are 16px tall, which
     is below even the 24px WCAG asks for. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0.75rem;
  color: var(--gdg-blue-dark);
}

/* Legal pages */

.legal h2 {
  margin-top: 2rem;
}

.legal .draft {
  padding: 0.9rem 1rem;
  border-left: 4px solid var(--gdg-error);
  background: #fdf1ef;
  font-size: 0.9rem;
}

@media (min-width: 40rem) {
  header img {
    max-width: 260px;
  }

  h1 {
    font-size: 2rem;
  }

  #map {
    height: 26rem;
  }

  .submit {
    width: auto;
    min-width: 16rem;
  }
}
