/* Frontier layer — the shared design system for the rebuilt pages.
 * ===========================================================================
 *
 * Built from values measured off the three references at 1440x900
 * (verify/refs.mjs, output in docs/reference-tokens.txt), not from memory:
 *
 *   harmattan.ai   bg #0C0C0C · Figtree + IBM Plex Mono · h1 72px/61.2px (0.85)
 *                  uppercase 600 · radius 3.6px · container 1440 · section
 *                  115.2/72px · muted #BAAE9B · panel rgba(186,174,155,.08)
 *                  accent #FCFF55
 *   anduril.com    bg #000 · Helvetica Now Display · radius 2px (21 of 21
 *                  rounded elements) · container 1440 · display tracking
 *                  -1.28px · eyebrow 12px/ls 0.48px/uppercase · accent #DFF140
 *   terraindustries.co  bg #fff · Rethink Sans · h1 54px/ls -2.16px (-0.04em)
 *                  container 1230 · radius 8-40px · muted #7D7D7D
 *
 * What was taken and what was not:
 *
 *  - Radius 2px. Two of the three are hard-cornered and so is this site's hero
 *    frame; Terra's 8-40px is the outlier and would fight it.
 *  - Dark surface, white text, hairline rules. Harmattan and Anduril both.
 *  - Uppercase display type, tracking pulled negative, leading under 1.
 *  - A monospace eyebrow. Harmattan uses IBM Plex Mono, Anduril a 12px/0.48px
 *    letterspaced caps label; both read "technical". This is the one typeface
 *    added to the site — see --frontier-mono.
 *  - NOT the accents. Harmattan's #FCFF55 and Anduril's #DFF140 are both neon;
 *    this site's #c4b798 is already the same warm sand as Harmattan's *muted*
 *    #BAAE9B, so the palette stays ours and only the structure is borrowed.
 *  - NOT Terra's light theme, rounded cards or 1230px container.
 *
 * Everything is scoped to .frontier so it cannot leak into the Webflow pages
 * that have not been rebuilt yet. Own file, so a re-scrape of dronivo.css
 * cannot overwrite it.
 */

.frontier {
  /* Surfaces. #0b0b0b sits between Anduril's #000 and Harmattan's #0C0C0C;
     #151515 is this site's own dark, kept for raised panels. */
  --fr-bg: #0b0b0b;
  --fr-panel: #151515;
  /* Harmattan's tinted panel, in whichever accent the site runs. */
  --fr-panel-2: color-mix(in srgb, var(--fr-accent) 6%, transparent);
  --fr-line: rgba(255, 255, 255, 0.14);
  --fr-line-strong: rgba(255, 255, 255, 0.28);

  --fr-fg: #ffffff;
  /* 0.72 statt 0.62. Auf #0b0b0b ergab 62% ein Kontrastverhaeltnis von 8.2:1 —
     formal in Ordnung, aber in Verbindung mit 16px Schrift der Grund, warum der
     Fliesstext "sehr klein" wirkte. Bei 72% sind es 11.1:1. */
  --fr-muted: rgba(255, 255, 255, 0.72);
  /* Set per site in navbar.css / on the page wrapper — see --site-accent. */
  --fr-accent: var(--site-accent, var(--_primitives---colors--brand-yellow, #c4b798));

  --fr-radius: 2px;

  /* Harmattan runs 1440; the site's own container is narrower, so the content
     measure is capped separately from the full-bleed rails. */
  --fr-container: 1440px;
  --fr-gutter: 2rem;
  /* 68ch statt 62: der Fliesstext ist gewachsen (siehe .fr-body), und bei
     gleicher Zeichenzahl wuerde die Spalte sonst breiter statt laenger. */
  --fr-measure: 68ch;

  /* 115.2px / 72px from Harmattan, expressed in rem and allowed to shrink. */
  /* Von 7.2rem auf 5.5rem heruntergenommen: "Luecken zwischen den Texten sind
     zu gross / zu viele schwarze Flaechen". 115px oben und unten summierten
     sich bei sechs Abschnitten auf 1380px reines Polster — mehr als ein voller
     Bildschirm, nur Abstand. */
  --fr-section: clamp(3.25rem, 6vw, 5.5rem);
  --fr-section-tight: clamp(2.5rem, 4vw, 3.5rem);

  --fr-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --fr-display: var(--_typography---font-styles--heading, "Neue Haas Grotesk Display Pro", Arial, sans-serif);

  background-color: var(--fr-bg);
  color: var(--fr-fg);
}

/* --- Shell ---------------------------------------------------------------- */

.fr-section {
  padding-top: var(--fr-section);
  padding-bottom: var(--fr-section);
  border-top: 1px solid var(--fr-line);
}

.fr-section.is-tight {
  padding-top: var(--fr-section-tight);
  padding-bottom: var(--fr-section-tight);
}

/* The first section after the hero owns the hero's bottom edge instead of
   drawing a second line under it. */
.fr-section.is-first {
  border-top: 0;
}

.fr-container {
  width: 100%;
  max-width: var(--fr-container);
  margin: 0 auto;
  padding-left: var(--fr-gutter);
  padding-right: var(--fr-gutter);
}

/* Webflows eigener Listenstil greift in jede Liste dieser Ebene hinein.
 *
 *   li { margin-top: .25rem; margin-bottom: .25rem; padding-left: .5rem }
 *
 * `margin: 0` steht in dieser Datei jeweils auf dem <ul>/<ol>, nicht auf den
 * Kindern — deshalb wirkte es nie. Gemessen: 229 Listenpunkte auf 18 Seiten
 * trugen die 4px oben und unten.
 *
 * Sichtbar wurde es dort, wo eine Liste ihre Trennlinien aus dem Spalt zieht:
 * .fr-cards zeichnet 1px Haarlinie, indem der Rasterspalt den hellen Grund
 * durchscheinen laesst. Aus 1px wurden 1 + 4 + 4 = 9px, und die Haarlinie
 * zwischen den Kartenreihen war ein hellgrauer Balken. Der Kunde meldet ihn
 * auf /red-teaming als "freie hellgraue Flaeche".
 *
 * .fr-spec-list setzt seinen Abstand selbst (`li + li`) und gewinnt hier
 * ueber die hoehere Spezifitaet — der bewusste Wert bleibt stehen. */
.fr-tiles > li,
.fr-cards > li,
.fr-pillars > li,
.fr-steps > li,
.fr-timeline > li,
.fr-roles > li,
.fr-chips > li,
.fr-spec-list > li,
.fr-list > li {
  margin-top: 0;
  margin-bottom: 0;
}

/* --- Type ----------------------------------------------------------------- */

/* Anduril's 12px / 0.48px / uppercase label, set in Harmattan's mono. */
.fr-eyebrow {
  display: flex;
  align-items: baseline;
  margin: 0 0 1.5rem;
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  /* 13px. It was 12px, which at mono's narrow cut and 4% tracking read as fine
     print rather than as a label — these are the section headings a scanner
     uses to find their way down the page. 14px was tried and is too close to
     the 15px body: the eyebrow has to stay clearly the smaller of the two, or
     the hierarchy inverts. */
  /* 15px / 600 statt 13px / 500.
   *
   * Der Kunde: "goldene Schrift ueber Ueberschrift groesser/dicker machen, fuer
   * bessere Lesbarkeit". Mono in Versalien mit 4 % Sperrung traegt bei 13px
   * wenig Farbe auf den dunklen Grund — es ist die Zeile, an der ein Leser
   * sich beim Ueberfliegen orientiert, und sie war die schwaechste auf der
   * Seite.
   *
   * 15px bleibt unter der Fliesstextgroesse (16px) und damit unter der
   * Ueberschrift: die Rangfolge kippt nicht. 600 statt 500, weil IBM Plex Mono
   * bei Medium auf Schwarz noch immer duenn wirkt. */
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.2;
  text-transform: uppercase;
}

/* The site's own "//" motif, kept as the marker rather than a square or dot. */
.fr-eyebrow::before {
  content: "//";
  margin-right: 0.75rem;
  letter-spacing: 0;
}

/* Measured off this site's own hero h1, not invented: 60.48px / lh 57.456
   (0.95) / weight 400 / ls -0.9072px (-0.015em). Weight 600 was tried first —
   Neue Haas Display's Medium cut at display size reads as a slab and fought the
   references, all three of which set their display type light. The size is
   expressed as 4.2vw so it lands on 60.48px at 1440 exactly.
 *
 * Set in sentence case. It was uppercase, matching the Webflow original and
 * Anduril, but the headings here are full sentences — "Unmanned systems
 * tailored to operational requirements" — and a sentence of that length in caps
 * loses the word shapes a reader navigates by. Caps still carry the label
 * system: the mono eyebrows, chips and captions below are all uppercase, so the
 * two levels stay visibly different without the display line shouting.
 *
 * Two things it is not enough to simply delete `text-transform: uppercase` for.
 * The compiled Webflow sheet carries `h1 { text-transform: uppercase }`, and
 * with no declaration here that bare element selector wins — the headings
 * stayed in caps while every other change landed. So it is overridden, not
 * removed. And at line-height 0.95 the ascenders and descenders that caps do
 * not have nearly touch between lines, hence 1.02. */
.fr-display {
  margin: 0;
  color: var(--fr-fg);
  font-family: var(--fr-display);
  font-size: clamp(2.25rem, 4.2vw, 3.78rem);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.015em;
  text-transform: none;
  text-wrap: balance;
}

/* The site's own h2: 43.2px / lh 43.2 (1.0) / weight 500 / ls -0.015em and
   *not* uppercase. Section headings stay sentence case so the page has one
   voice of shouting — the hero — instead of three. */
.fr-h2 {
  margin: 0;
  font-family: var(--fr-display);
  font-size: clamp(1.5rem, 2.65vw, 2.375rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.fr-h3 {
  margin: 0;
  font-size: 1.1875rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.fr-lead {
  max-width: var(--fr-measure);
  margin: 1.5rem 0 0;
  color: var(--fr-muted);
  font-size: clamp(1.0625rem, 1.3vw, 1.25rem);
  line-height: 1.55;
}

.fr-body {
  max-width: var(--fr-measure);
  margin: 0;
  /* 17px statt 16, und heller. Der Kunde: "die Texte sind sehr klein
     geschrieben, vor allem im Verhaeltnis zu den Ueberschriften". Beides traf
     zu — 16px gegen eine 43px-Ueberschrift ist ein Sprung von 2.7, und bei
     62% Deckkraft auf Schwarz kommt zu klein und zu blass zusammen. Die
     Ueberschrift geht im Gegenzug auf 38px zurueck, der Abstand liegt damit
     bei 2.2 statt 2.7. */
  color: var(--fr-muted);
  font-size: 1.0625rem;
  line-height: 1.6;
}

/* --- Section head --------------------------------------------------------- */

/* Label left, content right — the two-column head Anduril uses throughout. It
   collapses to one column before the label column gets too narrow to read. */
/* Kicker ueber der Ueberschrift, der ganze Block mittig.
 *
 * Vorher lag der Kicker in einer eigenen Spalte links (3fr) und der Inhalt
 * begann erst bei 412 von 1440 — gemessen auf /about-us, in jedem Abschnitt.
 * Links blieben 380px leer, rechts nichts, und genau das meinte der Kunde mit
 * "durch die Platzierung links wirkt der Haupttext nicht mehr zentriert".
 *
 * Die goldenen Label bleiben, sie wurden ausdruecklich gelobt — sie stehen nur
 * nicht mehr neben dem Text, sondern darueber. Damit hat die Seite eine
 * Spalte statt zweier ungleicher, und der Textblock sitzt mittig im Container.
 *
 * 62rem, nicht die volle Containerbreite: eine Ueberschrift ueber 1376px
 * laeuft auseinander, und der Fliesstext darunter haette ein Lesemass von weit
 * ueber 100 Zeichen. Raster wie Kacheln und Schritte behalten die volle
 * Breite — ein zentrierter Einstieg ueber einem breiten Raster ist gewollt. */
.fr-head {
  display: block;
  max-width: 62rem;
  margin-inline: auto;
}

.fr-head .fr-eyebrow {
  /* Als .fr-head noch ein 3fr/9fr-Raster war, stand die Eyebrow in einer
     eigenen Spalte neben der Ueberschrift und brauchte keinen Abstand nach
     unten — dafuer gab es weiter unten ein `margin-bottom: 0`. Seit der Kopf
     ein zentrierter Block ist, stehen beide untereinander, und diese alte
     Regel hat die neue ueberschrieben: gleiche Spezifitaet, spaeter im
     Dokument. Die goldene Zeile klebte dadurch auf jeder Ueberschrift der
     Seite. Sie ist entfernt; verify/eyebrow-gap.mjs misst den Abstand. */
  margin-bottom: 1.125rem;
}

.fr-head-body {
  max-width: none;
}

.fr-head-body > * + * {
  margin-top: 1.5rem;
}

/* --- Numbered steps ------------------------------------------------------- */

/* "01 / 02 / 03" with a rule over each column. The deck already writes its
   process this way, and so do both dark references. */
.fr-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0;
  margin: 4rem 0 0;
  padding: 0;
  /* It is an <ol> for the semantics; the counters are drawn as "01" in
     .fr-step-num, so the browser's own markers have to go. */
  list-style: none;
}

/* Untereinander statt vierspaltig.
 *
 * Auf /r-d tragen die Schritte laengere Beschreibungen als die Kurzformen der
 * anderen Seiten; in einer 344px-Spalte bricht dort jeder zweite Satz nach drei
 * Woertern um. Gestapelt bekommt jeder Schritt die Nummer links und den Text
 * daneben — dasselbe Muster wie die Spezifikationszeilen der Kursseiten, also
 * nichts Neues im Formenvorrat. */
.fr-steps.is-stacked {
  display: block;
  margin-top: 3rem;
}

/* Die Schritte tragen `.fr-step-num`, `.fr-h3` und ein blankes <p> — nicht die
   Klassennamen, die eine gestapelte Fassung nahelegen wuerde. Der erste Anlauf
   zielte auf `.fr-step-title` und `.fr-step-text`, traf nichts, und der
   Beschreibungstext blieb in der 5rem-Nummernspalte stehen: ein Wort je Zeile.
   Deshalb hier die tatsaechlichen Selektoren. */
.fr-steps.is-stacked .fr-step {
  display: grid;
  grid-template-columns: 5rem minmax(0, 1fr);
  column-gap: 2rem;
  align-items: baseline;
  padding: 1.75rem 0;
  border-top: 1px solid var(--fr-line);
  border-left: 0;
}

.fr-steps.is-stacked .fr-step:last-child {
  border-bottom: 1px solid var(--fr-line);
}

.fr-steps.is-stacked .fr-step-num {
  grid-column: 1;
  grid-row: 1 / span 2;
  margin: 0;
}

.fr-steps.is-stacked .fr-h3 {
  grid-column: 2;
  grid-row: 1;
}

.fr-steps.is-stacked .fr-step > p {
  grid-column: 2;
  grid-row: 2;
  max-width: 68ch;
  margin: 0.5rem 0 0;
}

@media (max-width: 767px) {
  .fr-steps.is-stacked .fr-step {
    grid-template-columns: 1fr;
    row-gap: 0.5rem;
  }
  .fr-steps.is-stacked .fr-step-num,
  .fr-steps.is-stacked .fr-h3,
  .fr-steps.is-stacked .fr-step > p {
    grid-column: 1;
    grid-row: auto;
  }
}

.fr-step {
  padding: 1.5rem 1.5rem 0 0;
  border-top: 1px solid var(--fr-line-strong);
}

.fr-step-num {
  display: block;
  margin-bottom: 1.25rem;
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
}

.fr-step .fr-h3 {
  margin-bottom: 0.625rem;
}

.fr-step p {
  max-width: 34ch;
  margin: 0;
  color: var(--fr-muted);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* --- Capability cards ----------------------------------------------------- */

.fr-cards {
  display: grid;
  /* Fixed three, not auto-fit: the card counts are multiples of three, and
     auto-fit left a half-empty last row showing the grid's line colour as a
     grey slab. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  margin: 4rem 0 0;
  padding: 0;
  list-style: none;
  /* One shared hairline grid: the gap is the line, the cards sit on top of it. */
  background-color: var(--fr-line);
  border: 1px solid var(--fr-line);
  border-radius: var(--fr-radius);
  overflow: hidden;
}

.fr-card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 2rem;
  background-color: var(--fr-bg);
  transition: background-color 0.24s ease;
}

.fr-card:hover {
  background-color: var(--fr-panel);
}

.fr-card p {
  margin: 0;
  color: var(--fr-muted);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.fr-card-label {
  margin: 0.5rem 0 0;
  color: rgba(255, 255, 255, 0.42);
  font-family: var(--fr-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.fr-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.fr-list li {
  padding: 0.625rem 0;
  border-top: 1px solid var(--fr-line);
  color: var(--fr-fg);
  font-size: 0.9375rem;
  line-height: 1.35;
}

/* --- Actions -------------------------------------------------------------- */

/* No button of its own: the rebuilt pages use the site's existing
   `.button.w-inline-block` component, markup and all, so there is one button
   style on the site rather than two. Only the row it sits in is defined here. */
.fr-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 2.5rem;
}

/* Vier Karten sind kein Vielfaches von drei.
 *
 * Der Kommentar an .fr-cards oben stimmte, als er geschrieben wurde: alle
 * Kartenbloecke hatten drei oder sechs Eintraege. /red-teaming hat seit dem
 * Aufbau aus dem Canva-Board vier — und damit genau den Zustand, vor dem der
 * Kommentar warnt: die vierte Karte steht allein in der zweiten Reihe, und die
 * beiden leeren Zellen daneben zeigen die Linienfarbe als graue Platte.
 *
 * Statt den Inhalt auf drei zu kuerzen oder zwei zu erfinden, richtet sich das
 * Raster nach der Anzahl: genau vier Karten stehen 2x2. Sechs, drei und neun
 * bleiben dreispaltig.
 *
 * Nur oberhalb von 1200px noetig — darunter sind es ohnehin schon zwei Spalten
 * und ab 991px eine. Ohne diese Klammer wuerde die Regel die beiden
 * Media-Queries darunter ueberstimmen: `:has()` erbt die Spezifitaet seines
 * Arguments, `.fr-cards:has(> .fr-card…)` waegt also schwerer als `.fr-cards`
 * und haette auf dem Telefon zwei Spalten erzwungen.
 */
@media (min-width: 1201px) {
  .fr-cards:has(> .fr-card:nth-child(4):last-child) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* --- Small screens -------------------------------------------------------- */

@media (max-width: 1200px) {
  .fr-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 991px) {
  .frontier {
    --fr-gutter: 1.5rem;
  }
  .fr-cards {
    grid-template-columns: minmax(0, 1fr);
  }
  .fr-hero-inner {
    padding-left: calc(var(--fr-gutter) + 1.5rem);
    padding-right: calc(var(--fr-gutter) + 1.5rem);
  }
  .fr-steps,
  .fr-cards {
    margin-top: 2.5rem;
  }
  .fr-card {
    padding: 1.5rem;
  }
}

/* --- Subpage hero --------------------------------------------------------- */

/* The framed geometry of the home hero, at two thirds the height: a subpage
   that opens on a full screen of photography buries its own content, which is
   exactly what Anduril does on its capability pages and Harmattan on its
   inner ones. */
.fr-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* Hoeher, damit vom Foto mehr uebrig bleibt.
   *
   * Gemessen: bei min(66svh, 40rem) stand der Bildrahmen auf 1376x468 — ein
   * Verhaeltnis von 2.94:1, waehrend die Aufnahmen 2400x1600 (3:2) sind. Damit
   * fielen 49% des Bildes weg, oben und unten. Der Kunde: "die Bilder muessen
   * ganz zu erkennen sein, aktuell ist viel abgeschnitten".
   *
   * min(86svh, 52rem) ergibt einen Rahmen von etwa 1376x700, also 1.97:1 —
   * der Verlust faellt auf rund 31%. Ganz ohne Beschnitt ginge nur mit einem
   * 3:2-Rahmen von 917px Hoehe; dann faengt die Seite mit einem Bild an, das
   * fast den ganzen Bildschirm fuellt und die Ueberschrift darunter schiebt.
   * 86svh ist die Grenze, bei der Ueberschrift und Vorspann noch im ersten
   * Blickfeld liegen. */
  min-height: min(86svh, 52rem);
  padding: calc(var(--site-header-bottom, 111px) + 3rem) 0 var(--fr-section-tight);
  isolation: isolate;
  background-color: #000;
}

.fr-hero-media,
.fr-hero-scrim {
  position: absolute;
  inset: var(--site-header-bottom, 111px) var(--fr-gutter) var(--fr-gutter);
  border-radius: var(--fr-radius);
}

.fr-hero-media {
  z-index: -2;
  width: calc(100% - 2 * var(--fr-gutter));
  height: calc(100% - var(--site-header-bottom, 111px) - var(--fr-gutter));
  object-fit: cover;
  /* The photography across the site is monochrome; the colour ones are pulled
     into line rather than left as the one warm frame on a cold page. */
  filter: grayscale(1) contrast(1.05);
}

.fr-hero-scrim {
  z-index: -1;
  /* Weighted low: the copy sits on the bottom third, the rest stays open. */
  background-image: linear-gradient(
    180deg,
    rgba(6, 6, 6, 0.25) 0%,
    rgba(6, 6, 6, 0.3) 45%,
    rgba(6, 6, 6, 0.72) 82%,
    rgba(6, 6, 6, 0.88) 100%
  );
}

/* Held off the frame edge by the same 2.25rem the home hero uses, so the copy
   never sits flush against the photograph's border. */
.fr-hero-inner {
  padding-bottom: 2.25rem;
  padding-left: calc(var(--fr-gutter) + 2.25rem);
  padding-right: calc(var(--fr-gutter) + 2.25rem);
}

/* Der Kicker im Hero, groesser und gegen helle Bilder abgesichert.
 *
 * Der Kunde: "die goldene Schrift im Header ueber der Ueberschrift ist zu klein
 * und bei manchen Bildern schwer lesbar". Beides stimmt, und die zweite Haelfte
 * ist die wichtigere: 13px Sand auf einem Foto hat keinen garantierten
 * Kontrast — auf dem hellen Himmel der UXS-Aufnahme faellt er fast weg.
 *
 * 15px statt 13, und ein Schatten statt eines weiteren Verlaufs. Ein Schatten
 * wirkt nur dort, wo die Schrift steht, waehrend ein staerkerer Scrim das ganze
 * Bild abdunkeln wuerde — und das Bild ist auf diesen Seiten das Argument. */
.fr-hero-inner .fr-eyebrow {
  font-size: 0.9375rem;
  letter-spacing: 0.06em;
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.85),
    0 0 14px rgba(0, 0, 0, 0.6);
}

.fr-hero-inner .fr-display,
.fr-hero-inner .fr-lead {
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}

.fr-hero-inner .fr-display {
  max-width: 18ch;
}

/* --- Closing CTA ---------------------------------------------------------- */

/* The closing block. A wash of the brand colour at 6% marks the end of the
   page without adding a second surface, and the heading in display size gives
   it the weight the section had lost when it was just a line and a button. */
.fr-cta {
  background-color: var(--fr-panel-2);
}

.fr-cta .fr-h2 {
  max-width: 20ch;
  font-size: clamp(1.75rem, 3.4vw, 3rem);
}

.fr-cta .fr-body {
  max-width: 52ch;
}

/* --- The closing block's drone ------------------------------------------- */

/* Webflow's own closing section floats this line drawing to the right of the
   text (`.img_cta`, inset 25% 0 0 auto). Reproduced here so the rebuilt pages
   close the same way the scraped ones do.
 *
 * Anchored to the container rather than to the section, so it lines up with the
 * text's gutter instead of the viewport edge — on a wide screen the section is
 * full-bleed and the drawing would otherwise drift far from the content it
 * belongs to. */
/* A column of its own, not an absolute overlay.
 *
 * The first attempt floated the drawing at `right: 0; bottom: 0` the way
 * Webflow does. Webflow gets away with it because its closing block is a
 * fixed-height panel with the text capped at 27rem; this section is fluid, so
 * the heading grew straight into the rotors. Measured across all eleven rebuilt
 * pages: the text overlapped the drawing on seven of them at 1440px and on
 * every single one at 1280 and 1024.
 *
 * Two columns make the overlap impossible rather than unlikely — no cap on the
 * heading to maintain, and nothing to re-measure when someone writes a longer
 * call to action. `align-items: end` keeps the drawing sitting on the baseline
 * of the block, which is where Webflow's version reads from. */
@media (min-width: 992px) {
  .fr-cta__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
    align-items: end;
    column-gap: 3rem;
  }

  .fr-cta__sketch {
    width: 100%;
    height: auto;
    /* Optical: the drawing's own margins leave it floating above the text
       baseline otherwise. */
    margin-bottom: -0.5rem;
  }
}

/* Below the breakpoint the text runs full width and the drawing follows it as a
   normal block — the same switch Webflow makes at 991px, and the reason the
   illustration survives on a phone instead of being hidden. */
@media (max-width: 991px) {
  .fr-cta__sketch {
    display: block;
    width: 100%;
    max-width: 26rem;
    height: auto;
    margin-top: 3rem;
  }
}

@media (max-width: 991px) {
  .fr-hero {
    min-height: 32rem;
  }
}

/* --- Statement ------------------------------------------------------------ */

/* Harmattan opens on one centred paragraph under a mono eyebrow — no heading,
   no columns. It is the only centred thing on the page, which is what gives it
   weight. Set at h2 size but in the body face, so it reads as a spoken
   sentence rather than a headline. */
/* Set left, in the shared two-column head, rather than centred.
 *
 * Centring is what Harmattan does with the ONE statement it puts on a page —
 * it is a pause, and the whitespace is the point. These pages carry two or
 * three each, so the pause became the rhythm: 538px of section for 307px of
 * content on /uxs, and a 26ch measure that wraps a sentence into four short
 * lines where the column fits it in two.
 *
 * The type keeps its size. What goes is the centring, the eyebrow's own line,
 * and the narrow measure. */
.fr-statement-line {
  /* 46ch statt 34: das schmale Mass stammte aus der zweispaltigen Fassung, in
     der die Textspalte nur 9 von 12 Einheiten breit war. Im mittigen Block
     liess es rechts die halbe Flaeche leer — der Satz sah dadurch wieder nicht
     mittig aus, nur an anderer Stelle. */
  max-width: 46ch;
  color: #fff;
  font-size: clamp(1.375rem, 2.4vw, 2.125rem);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.fr-statement-line + .fr-statement-line {
  margin-top: 1.25rem;
  color: var(--fr-muted);
  font-size: clamp(1rem, 1.2vw, 1.125rem);
  line-height: 1.5;
  max-width: 66ch;
  /* `balance` belongs to the display line above, where evening out two or three
     words matters. On running copy it does the opposite of what it looks like
     it should: the browser shortens every line to equalise them, so a paragraph
     that would fill 56ch wrapped at about 40 and the block grew taller than
     necessary — the exact thing this change set out to fix. `pretty` keeps the
     full measure and only guards the last line against an orphan. */
  text-wrap: pretty;
}

/* --- Image tiles ---------------------------------------------------------- */

/* Anduril's product mosaic. Six tiles on a four-column grid with two of them
   spanning two columns, so the rhythm breaks instead of reading as a table.
   The copy sits inside the tile over a scrim rather than under it — that is
   what makes the photograph the section instead of decoration beside it. */
.fr-tiles {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
  margin: 4rem 0 0;
  padding: 0;
  list-style: none;
}

.fr-tile {
  position: relative;
  display: flex;
  align-items: flex-end;
  grid-column: span 2;
  /* 30rem statt 26. Die Kacheln zeigen teils Hochformate (bis 2496x3744), die
     in einem 1.65:1-Feld mehr als die Haelfte verlieren — gemessen 54 bis 59%.
     Eine hoehere Kachel holt einen Teil zurueck; den Rest loesen erst die
     Querformat-Varianten, die der Kunde ohnehin liefern will. */
  min-height: 30rem;
  padding: 2rem;
  overflow: hidden;
  border-radius: var(--fr-radius);
  isolation: isolate;
  background-color: var(--fr-panel);
}

/* The two wide ones carry the anchor products; the rest sit two-up. */

.fr-tile-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Every photograph on the site is monochrome; the colour ones are pulled
     into line rather than left as the one warm tile on a cold page. */
  filter: grayscale(1) contrast(1.04);
  transform: scale(1.02);
  transition: transform 0.7s cubic-bezier(0.625, 0.05, 0, 1);
}

.fr-tile:hover .fr-tile-media {
  transform: scale(1.06);
}

/* Weighted to the bottom two thirds, where the copy is. */
.fr-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: linear-gradient(
    180deg,
    rgba(6, 6, 6, 0.15) 0%,
    rgba(6, 6, 6, 0.35) 42%,
    rgba(6, 6, 6, 0.82) 78%,
    rgba(6, 6, 6, 0.94) 100%
  );
}

.fr-tile-body {
  max-width: 44ch;
}

/* --- Kachel: Stichpunkte beim Darueberfahren ------------------------------- */

/* Der Kunde: "auf Bildern nur Ueberschrift mit Kurzbeschreibung ... und die
 * Stichpunkte einblenden". Gewaehlt wurde: Maus darueber blendet ein, Klick
 * fuehrt weiter — der Weg auf die Unterseite bleibt damit ein einzelner Klick.
 *
 * Die Hoehe laeuft ueber ein Raster von 0fr auf 1fr. `max-height` waere die
 * naheliegende Alternative, verlangt aber einen geratenen Hoechstwert: zu
 * klein schneidet ab, zu gross macht die zweite Haelfte der Animation zu
 * einem Warten auf nichts. 0fr kennt die noetige Hoehe selbst.
 *
 * Das Kind dazwischen traegt `overflow: hidden` — ohne das ragen die Chips
 * waehrend des Zusammenfahrens aus der Kachel heraus. */
.fr-tile-reveal {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.55s cubic-bezier(0.625, 0.05, 0, 1);
}

.fr-tile-reveal > * {
  overflow: hidden;
}

.fr-tile-reveal .fr-chips {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.fr-tile:hover .fr-tile-reveal,
.fr-tile:focus-within .fr-tile-reveal {
  grid-template-rows: 1fr;
}

.fr-tile:hover .fr-tile-reveal .fr-chips,
.fr-tile:focus-within .fr-tile-reveal .fr-chips {
  opacity: 1;
  /* Erst aufziehen, dann einblenden — sonst schweben die Chips ueber einem
     Feld, das noch waechst. */
  transition: opacity 0.35s ease 0.18s;
}

/* Das Bild dunkelt ab, damit die Stichpunkte darauf lesbar sind. Nur bei
   Kacheln, die ueberhaupt etwas zu zeigen haben — sonst waere es ein Effekt
   ohne Inhalt. */
.fr-tile::after {
  transition: background-color 0.55s cubic-bezier(0.625, 0.05, 0, 1);
}

.fr-tile:has(.fr-tile-reveal):hover::after,
.fr-tile:has(.fr-tile-reveal):focus-within::after {
  background-color: rgba(6, 6, 6, 0.55);
}

/* Ohne Maus gibt es kein Darueberfahren. Auf Telefon und Tablet stehen die
   Stichpunkte deshalb von Anfang an da — sonst waeren sie unerreichbar. */
@media (hover: none) {
  .fr-tile-reveal {
    grid-template-rows: 1fr;
  }
  .fr-tile-reveal .fr-chips {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fr-tile-reveal,
  .fr-tile-reveal .fr-chips,
  .fr-tile::after {
    transition: none;
  }
}

.fr-tile-title {
  margin: 0;
  font-size: clamp(1.25rem, 1.7vw, 1.5rem);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.fr-tile-text {
  margin: 0.625rem 0 0;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.9375rem;
  line-height: 1.45;
}

/* Anduril and Harmattan both label things with small mono chips. */
.fr-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.fr-chips li {
  padding: 0.3125rem 0.5rem;
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background-color: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--fr-radius);
  backdrop-filter: blur(6px);
}

/* --- Feature block -------------------------------------------------------- */

/* Anduril's Arsenal-1: heading, one full-width photograph, then a row of mono
   captions under it. */
/* Eyebrow ueber der Ueberschrift, wie jeder andere Abschnittskopf.
   Vorher stand das Label links und die Ueberschrift am rechten Rand
   (`space-between`) — derselbe zweispaltige Kopf, der auf allen Seiten schon
   zurueckgebaut ist. Gemessen auf /software: Label bei 64, Ueberschrift bei
   570 von 1440. */
.fr-feature-head {
  display: block;
  padding-bottom: 1.5rem;
}

.fr-feature-head .fr-h2 {
  margin-top: 1.125rem;
}

.fr-feature-head .fr-eyebrow {
  margin-bottom: 0;
}

.fr-feature-media {
  display: block;
  width: 100%;
  height: clamp(18rem, 42vw, 34rem);
  /* `contain`, nicht `cover`.
   *
   * Der Kunde: "bei C-UAS unten Bild ist abgeschnitten". Der Feature-Platz ist
   * der einzige, an dem keine Reportageaufnahme steht, sondern ein
   * freigestelltes Geraet — auf /cuav ein Sensormast, auf /software ein
   * Bildschirmaufbau. Bei `cover` schneidet der Rahmen einem solchen Objekt die
   * Spitze oder den Sockel ab, und ein halbes Geraet zeigt man nicht.
   *
   * Bei einer Reportageaufnahme waere `contain` falsch — sie bekaeme
   * Balken. Der Platz traegt aber ausschliesslich Produktbilder, und dort ist
   * Vollstaendigkeit wichtiger als ein gefuellter Rahmen. */
  object-fit: contain;
  object-position: center;
  border-radius: var(--fr-radius);
  filter: grayscale(1) contrast(1.04);
}

.fr-captions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 2rem;
  margin-top: 1.5rem;
}

.fr-caption-label {
  margin: 0 0 0.5rem;
  /* Gold, nicht grau.
   *
   * Der Kunde meldet die Punkte unter dem Bild auf /cuav als "grau und nicht
   * gold". Er hat recht, und zwar systematisch: jede andere Beschriftung
   * dieser Ebene — .fr-eyebrow, der Titel einer Saeule, der Schluessel einer
   * Kursangabe — steht im Akzent. Diese eine stand auf 45 % Weiss und fiel
   * damit aus der Reihe. */
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.fr-caption-text {
  margin: 0;
  color: #fff;
  font-size: 0.9375rem;
  line-height: 1.45;
}

@media (max-width: 991px) {
  .fr-tiles {
    grid-template-columns: minmax(0, 1fr);
    margin-top: 2.5rem;
  }
  .fr-tile {
    grid-column: span 1;
    min-height: 20rem;
    padding: 1.5rem;
  }
}

/* --- Pillars -------------------------------------------------------------- */

/* Three claims side by side, each under a rule. Same device as the numbered
   steps but without the counters — used where the deck lists qualities rather
   than a sequence. */
.fr-pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0;
  margin: 4rem 0 0;
  padding: 0;
  list-style: none;
}

.fr-pillar {
  padding: 1.5rem 1.5rem 0 0;
  border-top: 1px solid var(--fr-line-strong);
}

.fr-pillar-title {
  margin: 0 0 0.75rem;
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  line-height: 1.3;
  text-transform: uppercase;
}

.fr-pillar-text {
  max-width: 34ch;
  margin: 0;
  color: var(--fr-muted);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* --- Courses -------------------------------------------------------------- */

/* One course at a time, picked from a list on the left — the shape Harmattan
 * uses for its mission capabilities. Two spec sheets side by side put roughly
 * twenty label/value pairs on one screen; this gives the selected one the full
 * width, which is what the content needs.
 *
 * The panels share one grid cell, so the block keeps the height of the tallest
 * course and switching cannot make the page jump.
 */
.fr-courses {
  display: grid;
  gap: 1px;
  margin-top: 4rem;
  background-color: var(--fr-line);
  border: 1px solid var(--fr-line);
  border-radius: var(--fr-radius);
  overflow: hidden;
}

.fr-courses.has-tabs {
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
}

/* --- The selector --------------------------------------------------------- */

.fr-course-tabs {
  display: flex;
  flex-direction: column;
  background-color: var(--fr-bg);
}

.fr-course-tab {
  display: flex;
  align-items: baseline;
  gap: 0.875rem;
  padding: 1.5rem;
  color: rgba(255, 255, 255, 0.62);
  font-family: inherit;
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.25;
  text-align: left;
  letter-spacing: -0.01em;
  background: none;
  border: 0;
  /* A hairline between entries, and a rail on the left that the selected one
     lights up — the same device as the numbered process rows. */
  border-top: 1px solid var(--fr-line);
  border-left: 2px solid transparent;
  cursor: pointer;
  transition: color 0.24s ease, background-color 0.24s ease, border-color 0.24s ease;
}

.fr-course-tab:first-child {
  border-top: 0;
}

.fr-course-tab:hover {
  color: #fff;
  background-color: rgba(255, 255, 255, 0.04);
}

.fr-course-tab[aria-selected="true"] {
  color: #fff;
  background-color: var(--fr-panel);
  border-left-color: var(--fr-accent);
}

.fr-course-tab-num {
  flex: 0 0 auto;
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
}

/* --- The panel ------------------------------------------------------------ */

/* Every panel in one cell: the block is as tall as the longest course and
   switching does not move the page under the reader. */
.fr-course-panels {
  display: grid;
  background-color: var(--fr-bg);
}

.fr-course {
  grid-area: 1 / 1;
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  /* stretch, so the photograph fills its column instead of sitting as a strip
     in a field of black */
  align-items: stretch;
  gap: 2.5rem;
  padding: 2rem;
  /* Hidden with visibility rather than display, so every panel keeps its cell
     and the block stays as tall as the longest course — switching must not
     move the page under the reader. */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s;
}

.fr-course[data-current="true"] {
  opacity: 1;
  visibility: visible;
}

.fr-course-media {
  width: 100%;
  height: 100%;
  min-height: 18rem;
  object-fit: cover;
  border-radius: var(--fr-radius);
  filter: grayscale(1) contrast(1.04);
}

.fr-course-title {
  margin: 0 0 1.5rem;
  font-family: var(--fr-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fr-accent);
}

/* A single course needs no selector, and reads better as image over spec. */
.fr-courses:not(.has-tabs) .fr-course {
  grid-template-columns: minmax(0, 1fr);
}

.fr-courses:not(.has-tabs) .fr-course-media {
  max-height: 20rem;
}

.fr-spec {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: 0;
}

.fr-spec dt {
  padding: 1rem 1rem 1rem 0;
  border-top: 1px solid var(--fr-line);
  color: rgba(255, 255, 255, 0.45);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.fr-spec dd {
  margin: 0;
  padding: 1rem 0;
  border-top: 1px solid var(--fr-line);
}

.fr-spec dd p {
  margin: 0;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.9375rem;
  line-height: 1.45;
}

/* Counters rather than list markers, to match the "01" of the process rows. */
.fr-spec-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: spec;
}

.fr-spec-list li {
  counter-increment: spec;
  position: relative;
  padding-left: 2rem;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.9375rem;
  line-height: 1.45;
}

.fr-spec-list li + li {
  margin-top: 0.625rem;
}

.fr-spec-list li::before {
  content: counter(spec, decimal-leading-zero);
  position: absolute;
  left: 0;
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  line-height: 1.9;
}

@media (max-width: 991px) {
  /* The selector becomes a scrolling strip above the panel. */
  .fr-courses.has-tabs {
    grid-template-columns: minmax(0, 1fr);
  }
  .fr-course-tabs {
    flex-direction: row;
    overflow-x: auto;
  }
  .fr-course-tab {
    flex: 1 0 auto;
    padding: 1rem 1.25rem;
    font-size: 0.9375rem;
    border-top: 0;
    border-left: 0;
    border-bottom: 2px solid transparent;
  }
  .fr-course-tab[aria-selected="true"] {
    border-left-color: transparent;
    border-bottom-color: var(--fr-accent);
  }
  .fr-course {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
  }
}

@media (max-width: 767px) {
  /* Back to a stack. The scrolling strip above is right on a tablet, where
     three tabs nearly fit; on a phone it clipped the second one mid-word at
     325px of room for 450px of tabs and put the third off-screen with nothing
     to say it was there. A course selector nobody can see past the first entry
     is worse than a list, and every other block on a phone is a list. */
  .fr-course-tabs {
    flex-direction: column;
    overflow-x: visible;
  }
  .fr-course-tab {
    flex: 0 0 auto;
    border-bottom: 0;
    border-left: 2px solid transparent;
  }
  .fr-course-tab[aria-selected="true"] {
    border-bottom-color: transparent;
    border-left-color: var(--fr-accent);
  }

  .fr-spec {
    grid-template-columns: minmax(0, 1fr);
  }
  .fr-spec dd {
    padding-top: 0;
    border-top: 0;
  }
  .fr-spec dt {
    padding-bottom: 0.375rem;
  }
  .fr-course-body {
    padding: 1.5rem;
  }
  .fr-pillars {
    margin-top: 2.5rem;
  }
}

/* A linked tile: the anchor is stretched over the whole tile, so the target is
   the photograph rather than three words of heading. */
.fr-tile-link {
  color: inherit;
  text-decoration: none;
}

.fr-tile-link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.fr-tile.is-link {
  cursor: pointer;
}

.fr-tile.is-link:hover .fr-tile-title,
.fr-tile.is-link:focus-within .fr-tile-title {
  color: var(--fr-accent);
}

.fr-tile-title {
  transition: color 0.24s ease;
}

/* A spec list entry that keeps the deck's own part name. */
.fr-spec-part {
  display: block;
  margin-bottom: 0.25rem;
  color: #fff;
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* --- Tag buttons ---------------------------------------------------------- */

/* Built from the capability chips on the tiles: mono, uppercase, 0.04em
   tracking, 2px corners, hairline border. The chips are the most distinctive
   small element on the rebuilt pages, so the buttons are the same object one
   size up rather than a second visual language.
   Live specimens: /#testbed. */
.fr-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.75rem 1.125rem;
  color: rgba(255, 255, 255, 0.88);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  background-color: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--fr-radius);
  cursor: pointer;
  transition: color 0.24s ease, background-color 0.24s ease, border-color 0.24s ease;
}

.fr-tag:hover,
.fr-tag:focus-visible {
  color: #fff;
  background-color: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.32);
}

/* Filled with the brand sand. The one button on a page that should be taken. */
.fr-tag.is-solid {
  color: #0b0b0b;
  background-color: var(--fr-accent);
  border-color: var(--fr-accent);
}

.fr-tag.is-solid:hover,
.fr-tag.is-solid:focus-visible {
  color: #0b0b0b;
  background-color: #fff;
  border-color: #fff;
}

/* Nothing behind it — for a row of equal options, where a filled button would
   make one of them look preselected. */
.fr-tag.is-outline {
  background-color: transparent;
  border-color: var(--fr-line-strong);
}

.fr-tag.is-outline:hover,
.fr-tag.is-outline:focus-visible {
  background-color: rgba(255, 255, 255, 0.08);
  border-color: #fff;
}

/* Border and label in the brand sand: a secondary action that still carries
   the brand, e.g. next to a solid one. */
.fr-tag.is-accent {
  color: var(--fr-accent);
  background-color: transparent;
  border-color: rgba(196, 183, 152, 0.5);
}

.fr-tag.is-accent:hover,
.fr-tag.is-accent:focus-visible {
  color: #0b0b0b;
  background-color: var(--fr-accent);
  border-color: var(--fr-accent);
}

/* No border at all — inline links inside running text or under a card. */
.fr-tag.is-quiet {
  padding-left: 0;
  padding-right: 0;
  color: var(--fr-muted);
  background-color: transparent;
  border-color: transparent;
}

.fr-tag.is-quiet:hover,
.fr-tag.is-quiet:focus-visible {
  color: var(--fr-accent);
  background-color: transparent;
  border-color: transparent;
}

.fr-tag.is-sm {
  padding: 0.5rem 0.75rem;
  font-size: 0.6875rem;
}

.fr-tag.is-lg {
  padding: 1rem 1.5rem;
  font-size: 0.8125rem;
}

.fr-tag[aria-disabled="true"] {
  opacity: 0.4;
  pointer-events: none;
}

.fr-tag svg {
  width: 0.75rem;
  height: 0.75rem;
  flex: 0 0 auto;
  transition: transform 0.35s cubic-bezier(0.625, 0.05, 0, 1);
}

.fr-tag.is-lg svg {
  width: 0.8125rem;
  height: 0.8125rem;
}

/* Right-pointing arrows travel right; the up-right one travels up-right. */
.fr-tag:hover svg { transform: translateX(3px); }
.fr-tag.is-external svg { transform: rotate(-45deg); }
.fr-tag.is-external:hover svg { transform: rotate(-45deg) translateX(3px); }

/* --- Testbed -------------------------------------------------------------- */

/* The specimen sheet at the bottom of the home page. Everything here is a live
   instance of a real class, so a change to the design system shows up on this
   page immediately. Delete lib/testbed.ts and its call to remove it. */
.fr-testbed {
  border-top: 1px solid var(--fr-line-strong);
}

.fr-specimen + .fr-specimen {
  margin-top: 3.5rem;
  padding-top: 3.5rem;
  border-top: 1px solid var(--fr-line);
}

.fr-specimen-label {
  margin: 0 0 1.5rem;
  color: rgba(255, 255, 255, 0.45);
  font-family: var(--fr-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.fr-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.fr-row + .fr-row {
  margin-top: 1rem;
}

/* Keeps a specimen row readable: what the thing is, then the thing. */
.fr-specimen-note {
  width: 100%;
  margin: 0 0 0.5rem;
  color: rgba(255, 255, 255, 0.38);
  font-family: var(--fr-mono);
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* --- Split tag button ------------------------------------------------------ */

/* The solid tag, rebuilt with the site's own two-part choreography.
 *
 * The mechanic is Webflow's `.btn-bubble-arrow`, lifted verbatim: two arrow
 * boxes, one collapsed on the left and one showing on the right. On hover the
 * left one scales in, the label slides right into the space, and the right one
 * scales out — so the arrow appears to jump sides while the label follows.
 * Same 0.735s cubic-bezier(0.625, 0.05, 0, 1) as every other motion here, and
 * the glyph turns to point up-right on the way.
 *
 * What is this file's rather than Webflow's: 2px corners instead of a pill,
 * mono uppercase at tag size, brand sand, and the tight padding the chips use.
 *
 * The geometry is driven by --fr-split-h, so label and arrow stay square-ish
 * and the slide distance stays correct at any size. Live at /#testbed.
 */
.fr-tag-split {
  --fr-split-h: 2.375rem;
  --fr-split-gap: 0.375rem;
  --fr-split-shift: calc(var(--fr-split-h) + var(--fr-split-gap));

  position: relative;
  display: inline-flex;
  align-items: stretch;
  height: var(--fr-split-h);
  color: #0b0b0b;
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.fr-tag-split__label,
.fr-tag-split__arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--fr-accent);
  border: 1px solid var(--fr-accent);
  border-radius: var(--fr-radius);
  transition: transform 0.735s cubic-bezier(0.625, 0.05, 0, 1),
    background-color 0.24s ease, border-color 0.24s ease;
}

.fr-tag-split__label {
  padding: 0 0.875rem;
  /* Pulled left over the collapsed arrow so the button reads as one object at
     rest; the hover slide is this distance, released. */
  transform: translateX(calc(-1 * var(--fr-split-shift)));
}

.fr-tag-split__arrow {
  width: var(--fr-split-h);
  flex: 0 0 auto;
  margin-right: var(--fr-split-gap);
  /* Collapsed from its left edge, so it grows out of the button's start. */
  transform: scale(0);
  transform-origin: left center;
}

/* The one on show at rest. Absolute, so it does not add to the layout width —
   the width is arrow + gap + label, which is exactly what the label's shift
   gives back. */
.fr-tag-split__arrow.is--duplicate {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 2;
  margin-right: 0;
  margin-left: var(--fr-split-gap);
  transform: scale(1);
  transform-origin: right center;
}

.fr-tag-split svg {
  width: 0.8125rem;
  height: 0.8125rem;
  transition: transform 0.735s cubic-bezier(0.625, 0.05, 0, 1);
}

.fr-tag-split:hover .fr-tag-split__label,
.fr-tag-split:focus-visible .fr-tag-split__label {
  transform: translateX(0);
}

.fr-tag-split:hover .fr-tag-split__arrow,
.fr-tag-split:focus-visible .fr-tag-split__arrow {
  transform: scale(1);
}

.fr-tag-split:hover .fr-tag-split__arrow.is--duplicate,
.fr-tag-split:focus-visible .fr-tag-split__arrow.is--duplicate {
  transform: scale(0);
}

/* Points up-right once it has jumped sides — the same "leaves this page"
   gesture the navbar button makes. */
.fr-tag-split:hover svg,
.fr-tag-split:focus-visible svg {
  transform: rotate(-45deg);
}

/* Outline reading of the same button, for a secondary action. */
.fr-tag-split.is-outline {
  color: #fff;
}

.fr-tag-split.is-outline .fr-tag-split__label,
.fr-tag-split.is-outline .fr-tag-split__arrow {
  background-color: transparent;
  border-color: var(--fr-line-strong);
}

.fr-tag-split.is-outline:hover .fr-tag-split__label,
.fr-tag-split.is-outline:hover .fr-tag-split__arrow {
  border-color: #fff;
}

.fr-tag-split.is-lg {
  --fr-split-h: 2.875rem;
  font-size: 0.8125rem;
}

.fr-tag-split.is-sm {
  --fr-split-h: 2rem;
  font-size: 0.6875rem;
}

@media (prefers-reduced-motion: reduce) {
  .fr-tag-split__label,
  .fr-tag-split__arrow,
  .fr-tag-split svg {
    transition-duration: 0.01ms;
  }
}

/* The navbar instance.
 *
 * Identical to the specimen at /#testbed — same brand sand, same 2.375rem
 * height, same padding, same animation. The only reason this block exists is
 * that the navbar sits outside `.frontier`, so the custom properties the
 * button reads have to be declared on the element itself. Nothing here
 * overrides colour or size; earlier versions did, and that is exactly what
 * made it look like a different button. */
.fr-tag-split.is-nav {
  --fr-radius: 2px;
  --fr-accent: var(--site-accent, #c4b798);
  --fr-line-strong: rgba(255, 255, 255, 0.28);
  --fr-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}


/* --- Verbatim mode -------------------------------------------------------- */

/* A site in `mode: "verbatim"` (lib/sites.ts) is served exactly as scraped, so
   the design-system layer has to be held off it. Two things reach it
   otherwise, both because they are scoped to <html> or to a bare Webflow
   class rather than to a site:
 *
 *   the framed hero  — `data-hero="framed"` lives on <html> (the switch script
 *                      runs before the body exists) and crops the hero by 126px
 *   the header       — navbar.css restyles `.nav_link` and `.navbar_logo`
 *
 * Undone here rather than by rescoping those files, which belong to the hero
 * and header work and are edited alongside this. Flipping the site's mode to
 * "frontier" turns the whole block off in one step. */
[data-mode="verbatim"] .nav_link {
  font-family: var(--_typography---font-styles--body) !important;
  font-size: 18px !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  line-height: 1.2 !important;
  padding: 0 0 0.25rem 0 !important;
}

[data-mode="verbatim"] .navbar_logo {
  height: auto;
  transform: none;
}


/* --- Timeline ------------------------------------------------------------- */

/* A dated history, one row per year. The numbered steps are the wrong shape
   for this: four entries of running prose in 15rem columns break every second
   word, and the year is a real label, not a counter. So it is set as rows —
   the same left-label geometry as the course spec sheet. */
.fr-timeline {
  margin: 4rem 0 0;
  padding: 0;
  list-style: none;
}

.fr-milestone {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
  gap: 0;
  padding: 1.25rem 0;
  border-top: 1px solid var(--fr-line);
}

/* The head rule is the heavier one, as on the steps and pillars rows. */
.fr-milestone:first-child {
  border-top-color: var(--fr-line-strong);
}

.fr-milestone-year {
  color: var(--fr-accent);
  font-family: var(--fr-mono);
  font-size: 0.875rem;
  letter-spacing: 0.04em;
  line-height: 1.5;
}

.fr-milestone-text {
  max-width: 62ch;
  margin: 0;
  color: var(--fr-muted);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* --- Open positions ------------------------------------------------------- */

/* A careers list is a table of three fields, so it is set as one: title left,
   contract and location right, one hairline per row. */
.fr-roles {
  margin: 4rem 0 0;
  padding: 0;
  list-style: none;
}

.fr-role {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.25rem 0;
  border-top: 1px solid var(--fr-line);
}

.fr-role:first-child {
  border-top-color: var(--fr-line-strong);
}

.fr-role-title {
  margin: 0;
  color: rgba(255, 255, 255, 0.92);
  font-size: 1.0625rem;
  line-height: 1.4;
}

.fr-role-meta {
  display: flex;
  flex-shrink: 0;
  gap: 1.5rem;
  margin: 0;
  color: rgba(255, 255, 255, 0.45);
  font-family: var(--fr-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

@media (max-width: 767px) {
  .fr-timeline,
  .fr-roles {
    margin-top: 2.5rem;
  }
  .fr-milestone {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
  }
  .fr-role {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.625rem;
  }
}


/* --- Angebrochene Rasterzeilen -------------------------------------------- */

/* Die Linie, die auf halber Breite aufhoert.
 *
 * .fr-steps, .fr-pillars und .fr-captions setzen `auto-fit, minmax(…, 1fr)`: die
 * Spaltenzahl richtet sich nach dem Platz. Geht die Elementzahl nicht auf,
 * steht die letzte Reihe angebrochen da — und weil jedes Element seine
 * Trennlinie als eigenen `border-top` traegt, endet diese Linie dort, wo das
 * letzte Element endet. Auf /cuav bei 768px laeuft sie ueber die halbe Breite
 * und bricht ab. Das liest sich nicht als Absatz, sondern als Fehler.
 *
 * Gemessen, an welcher Breite auto-fit auf wie viele Spalten schaltet:
 *
 *      < 600px   1 Spalte    (nie angebrochen)
 *   600-833px    2 Spalten
 *   834-1279px   3 Spalten
 *  1280-1439px   4 Spalten
 *     >= 1440px  5 Spalten   (auto-fit laesst leere Spuren einfallen, drei
 *                             Elemente stehen dort also wieder zu dritt)
 *
 * Das letzte Element fuellt die Restspalten seiner Reihe. Damit spannt seine
 * Linie ueber die volle Breite und die Reihe sieht gewollt aus statt
 * uebriggeblieben. `:nth-child(Nn+1)` trifft das Element, das in einer Reihe
 * mit N Spalten allein anfaengt, `Nn+2` das zweite von N.
 *
 * Warum nicht stattdessen die Spaltenzahl erzwingen, bis sie aufgeht: drei
 * Elemente untereinander kosten auf einem Tablet drei Bildschirmhoehen, und zu
 * viel Leerraum ist genau die Meldung, die vom Kunden schon kam.
 *
 * Die Breiten hier haengen an --fr-container und --fr-gutter. Aendert sich
 * eines von beiden, verschieben sie sich — verify/responsive.mjs meldet das
 * als "gestrandet", und zwar mit Seite und Breite.
 */

@media (min-width: 600px) and (max-width: 833px) {
  .fr-steps > :nth-child(2n + 1):last-child,
  .fr-pillars > :nth-child(2n + 1):last-child,
  .fr-captions > :nth-child(2n + 1):last-child {
    grid-column: span 2;
  }
}

@media (min-width: 834px) and (max-width: 1279px) {
  .fr-steps > :nth-child(3n + 1):last-child,
  .fr-pillars > :nth-child(3n + 1):last-child,
  .fr-captions > :nth-child(3n + 1):last-child {
    grid-column: span 3;
  }
  .fr-steps > :nth-child(3n + 2):last-child,
  .fr-pillars > :nth-child(3n + 2):last-child,
  .fr-captions > :nth-child(3n + 2):last-child {
    grid-column: span 2;
  }
}

@media (min-width: 1280px) and (max-width: 1439px) {
  .fr-steps > :nth-child(4n + 1):last-child,
  .fr-pillars > :nth-child(4n + 1):last-child {
    grid-column: span 4;
  }
  .fr-steps > :nth-child(4n + 2):last-child,
  .fr-pillars > :nth-child(4n + 2):last-child {
    grid-column: span 3;
  }
  .fr-steps > :nth-child(4n + 3):last-child,
  .fr-pillars > :nth-child(4n + 3):last-child {
    grid-column: span 2;
  }
}

/* --- Zeilenlaenge in Kursangaben ------------------------------------------ */

/* 111 Zeichen pro Zeile auf /kinetic-counter-uas.
 *
 * Die Kursangaben stehen in einer .fr-spec-Liste, deren <dd> acht von zwoelf
 * Spalten bekommt. Bei zwei Kursen teilen sich Reiter und Panel die Breite und
 * es faellt nicht auf; bei EINEM Kurs gibt es keine Reiter, das Panel nimmt die
 * volle Breite und der Absatz laeuft auf 831px aus. Ab etwa neunzig Zeichen
 * verliert das Auge beim Zeilenwechsel die Zeile — der Fehler faellt nur
 * niemandem auf, weil nichts "kaputt" aussieht.
 *
 * --fr-measure ist dieselbe Obergrenze, die .fr-lead und .fr-body schon
 * tragen. Damit liest sich der Kurstext wie der Rest der Seite. */
.fr-spec dd p,
.fr-spec-list li {
  max-width: var(--fr-measure);
}
