/*
  OpenBSD Jumpstart slides, "Abyss" theme
  owner : Wesley Mouedine Assaby

  Where the colours come from
  They are sampled from the three logos in /images rather than chosen by hand.
  All three sit in the same blue range, hue 186° to 220°, and differ only in
  their accent:

    logo1  teal sea        #2b9aa6   h186 s59   (dominant)
    logo2  deep azure      #0065b3   h206 s100  (50% of the image)
           warm sand       #fbdda6   h39
           coral           #d66c5a   h9
    logo3  indigo night    #37496e   h220 s33   (dominant)
           cyan            #49c9d3   h184
           rose            #ffa1c3   h338

  So the background is a deep indigo, cyan is the interactive colour, sand is
  used for headings, and rose and coral are the accents. The title slide draws
  one of the three logos at random and its accent follows, so the badge and
  the logo always match.

  Every text colour is checked against its own background. The ratio is noted
  where it matters, and nothing sits below 4.5:1.
*/

/* Design tokens */

:root {
  /* Ground */
  --abyss:        #0b1626;   /* deepest, the page itself                     */
  --deep:         #101f36;   /* raised surfaces                              */
  --shelf:        #16293f;   /* code wells, callouts                         */
  --edge:         #23374f;   /* hairlines, table rules                       */

  /* Ink */
  --foam:         #eef4fb;   /* body copy            16.4:1 on --abyss       */
  --mist:         #9db4cc;   /* secondary, captions   8.7:1                  */

  /* Accents, straight from the logos */
  --cyan:         #49c9d3;   /* links, interaction    9.4:1                  */
  --cyan-bright:  #8ee7ee;   /* hover                                        */
  --azure:        #2f8fd8;   /* structure, progress                          */
  --sand:         #fbdda6;   /* headings             14.2:1                  */
  --rose:         #ffa1c3;   /* the "Updated!" accent 9.9:1                  */
  --coral:        #f0846a;   /* strong, warnings      7.6:1                  */

  /* Type */
  --font-display: "Space Grotesk", "Trebuchet MS", sans-serif;
  --font-body:    "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Consolas, monospace;

  /* Scale, in the 960×700 coordinate space reveal.js scales for us.
     Every breakpoint at the foot of this file just rewrites these seven
     numbers, so no selector is ever repeated. */
  --fs-h1:      46px;
  --fs-h2:      44px;
  --fs-h3:      28px;
  --fs-h4:      92px;
  --fs-h5:      27px;
  --fs-body:    30px;
  --fs-small:   19px;
  --fs-code:    19px;   /* sized so the worst block (18 rendered lines) never scrolls */
  --fs-quote:   21px;
  --fs-table:   25px;

  /* Rhythm */
  --content-w:  92%;   /* one column for pre, table and blockquote alike     */
  --gap:        24px;
  --radius:     10px;
}

/* Ground */

.reveal {
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--foam);
  background-color: var(--abyss);

  /* Two flat gradients give the background some depth: a lighter one at the
     top, a cooler one at the bottom. No image file is loaded. */
  background-image:
    radial-gradient(118% 76% at 50% -12%, rgba(47, 143, 216, 0.20), transparent 62%),
    radial-gradient(92% 58% at 50% 112%, rgba(73, 201, 211, 0.10), transparent 60%);
  background-attachment: fixed;
}

.reveal ::selection {
  background: rgba(73, 201, 211, 0.30);
  color: #fff;
}

/* Keyboard focus must stay visible, because reveal.js gives links no focus style */
.reveal a:focus-visible,
.reveal .controls button:focus-visible {
  outline: 2px solid var(--cyan-bright);
  outline-offset: 3px;
  border-radius: 3px;
}

/* Headings */

.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 0.6em;
  text-wrap: balance;
}

/* The title badge takes its accent from whichever logo js/logo.js drew, so a
   warm pink never lands on a cold blue logo. Each value is sampled from that
   logo's own artwork:
     logo1  cyan   #68c8d2  (h186, the logo is cyan through and through)
     logo2  coral  #ea7a66  (h9, its warmest accent, next to the sand)
     logo3  rose   #ffa1c3  (h338, its brightest accent)
   The default is logo1's, because logo1 is the src hard-coded in index.html
   and therefore what shows when JavaScript is off. */
:root {
  --hero-accent: #68c8d2;
  --hero-tint:   rgba(104, 200, 210, 0.12);
  --hero-edge:   rgba(104, 200, 210, 0.45);
}

:root[data-logo="2"] {
  --hero-accent: #ea7a66;
  --hero-tint:   rgba(234, 122, 102, 0.12);
  --hero-edge:   rgba(234, 122, 102, 0.45);
}

:root[data-logo="3"] {
  --hero-accent: #ffa1c3;
  --hero-tint:   rgba(255, 161, 195, 0.12);
  --hero-edge:   rgba(255, 161, 195, 0.45);
}

/* Title slide. A compact badge, not a banner. Kept close to the original deck's
   compact pill rather than the full-width banner. */
.reveal h1 {
  display: inline-block;
  font-size: var(--fs-h1);
  letter-spacing: -0.01em;
  color: var(--sand);
  padding: 0.22em 0.85em;
  margin: 0 auto var(--gap);
  border: 1px solid var(--hero-edge);
  border-radius: 999px;
  background: linear-gradient(180deg, var(--hero-tint), transparent);
}

.reveal h1 span {
  color: var(--hero-accent);
}

/* Section titles. The small rule underneath appears on 58 slides, so it is
   kept discreet: 3px high, fading out to the right.

   No text-transform on purpose. 56 of the 58 titles are already lowercase in
   the markup, so the lowercase voice is an authoring convention, not something
   the stylesheet enforces. Forcing it destroyed real information: slide 42
   writes "OpenBSD" correctly and was being rendered "openbsd". Case carries
   meaning in this deck. pf, tcpdump and ktrace are lowercase commands, and
   uppercasing them (as the original theme did) names programs that do not
   exist. The titles now render exactly as written. */
.reveal h2 {
  position: relative;
  font-size: var(--fs-h2);
  letter-spacing: 0.005em;
  color: var(--foam);
  padding-bottom: 0.34em;
  margin-bottom: 0.64em;
}

.reveal h2::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 2.4em;
  height: 3px;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--cyan), var(--azure) 70%, transparent);
}

.reveal h3 {
  font-size: var(--fs-h3);
  font-weight: 500;
  color: var(--cyan);
  letter-spacing: 0.01em;
  margin-bottom: 0.7em;
}

/* The closing "merci." */
.reveal h4 {
  font-size: var(--fs-h4);
  letter-spacing: -0.02em;
  color: var(--rose);
  margin-bottom: 0.3em;
}

.reveal h5 {
  font-size: var(--fs-h5);
  font-weight: 500;
  color: var(--mist);
  letter-spacing: 0.01em;
}

/* Body copy */

.reveal p {
  font-size: var(--fs-body);
  line-height: 1.5;
  margin: 0 0 0.7em;
}

.reveal p:last-child {
  margin-bottom: 0;
}

.reveal small {
  display: block;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--mist);
}

.reveal strong {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--sand);
}

.reveal br {
  line-height: inherit;
}

/* Links */

/* Underline drawn as a background so it sits below the baseline and thickens
   on hover. It is cleaner than text-decoration, and it survives line wraps. */
.reveal a {
  color: var(--cyan);
  text-decoration: none;
  background-image: linear-gradient(var(--cyan), var(--cyan));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
  padding-bottom: 1px;
  transition: color 0.18s ease, background-size 0.18s ease;
}

.reveal a:hover {
  color: var(--cyan-bright);
  background-image: linear-gradient(var(--cyan-bright), var(--cyan-bright));
  background-size: 100% 2px;
}

/* Lists */

.reveal ul {
  display: inline-block;
  font-size: var(--fs-body);
  line-height: 1.5;
  text-align: left;
  margin: 0 auto;
  padding-left: 1.1em;
  list-style: none;
}

.reveal li {
  position: relative;
  margin-bottom: 0.42em;
}

.reveal li::before {
  content: "";
  position: absolute;
  left: -1.1em;
  top: 0.58em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--cyan);
  transform: rotate(45deg);
}

/* The three release flavours, wherever they are named, whether in a list, in prose or in a
   heading. Coloured by temperature: shipped, patched, moving. Classes rather
   than :nth-child, so the colour follows the word and not its position. */
.reveal .flavor-release,
.reveal .flavor-stable,
.reveal .flavor-current {
  font-family: var(--font-mono);
  font-weight: 700;
}

/* …except inside a title, which keeps its display face */
.reveal h2 .flavor-release,
.reveal h2 .flavor-stable,
.reveal h2 .flavor-current {
  font-family: inherit;
}

.reveal .flavor-release { color: var(--cyan); }
.reveal .flavor-stable  { color: var(--sand); }
.reveal .flavor-current { color: var(--coral); }

/* Slide 4 carries emoji icons of its own, so it gets no marker */
.reveal li:has(> .em)::before {
  display: none;
}

.reveal .em {
  width: 1.15em;
  height: 1.15em;
  margin-right: 0.4em;
  vertical-align: -0.22em;
}

/* Code */

.reveal code {
  font-family: var(--font-mono);
  font-variant-ligatures: none;
}

/* Inline code, and the <span>s used as file paths inside tables */
.reveal p > code,
.reveal li > code,
.reveal td > span,
.reveal blockquote code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  color: var(--cyan);
  background: rgba(73, 201, 211, 0.10);
  border: 1px solid rgba(73, 201, 211, 0.18);
  border-radius: 5px;
  padding: 0.08em 0.4em;
  white-space: nowrap;
}

.reveal pre {
  width: var(--content-w);
  margin: 0 auto var(--gap);
  font-size: var(--fs-code);
  box-shadow: none;
}

/* A well, lit from its left edge.
   white-space MUST stay pre-line: the code in index.html is indented to match
   the surrounding markup, and pre-line is what discards that indentation. */
.reveal pre code {
  display: block;
  max-height: 600px;
  padding: 0.78em 1.1em;
  overflow: auto;
  font-size: 1em;
  line-height: 1.4;
  text-align: left;
  white-space: pre-line;
  color: var(--foam);
  background: var(--shelf);
  border: 1px solid var(--edge);
  border-left: 3px solid var(--cyan);
  border-radius: 0 var(--radius) var(--radius) 0;
}

/* A slide carrying a listing has no room to spare: the heading gives back some
   of its spacing and the callout sits closer. Without this the longest block
   (slide 23, 16 lines plus the two blank ones pre-line keeps from the HTML
   indentation) pushes the callout off the bottom of the 700px canvas. */
.reveal section:has(pre) h2 {
  padding-bottom: 0.26em;
  margin-bottom: 0.34em;
}

.reveal section:has(pre) h3 {
  margin-bottom: 0.32em;
}

.reveal section:has(pre) pre {
  margin-bottom: 12px;
}

.reveal section:has(pre) blockquote {
  margin-top: 10px;
}

/* Two listings stacked on one slide (slide 19, wireless) is the tightest
   layout in the deck, so the type is set one step smaller to keep the closing
   note on the canvas. */
.reveal section:has(pre + pre) pre {
  font-size: 17px;
  margin-bottom: 14px;
}

/* Long listings wrap instead of scrolling. Qualified to out-specify the
   pre-line above, because a bare .code-wrap would lose to `.reveal pre code`. */
.reveal pre code.code-wrap {
  white-space: pre-wrap;
  tab-size: 4;
}

/* Syntax tokens. highlight.js detects these listings as `pf` and emits exactly
   six token types across the whole deck: comment, keyword, number, literal,
   built_in, string. No point theming any others. */
.reveal .hljs-comment {
  color: #6f8aa6;
  font-style: italic;
}

.reveal .hljs-keyword {
  color: var(--rose);
  font-weight: 700;
}

.reveal .hljs-built_in {
  color: var(--sand);
}

.reveal .hljs-string {
  color: #a8e6a3;
}

.reveal .hljs-number,
.reveal .hljs-literal {
  color: var(--coral);
}

/* Callout */

/* 31 slides end on one of these "Read: man page" notes. It is the most
   repeated component in the deck, so it whispers. */
/* On its own under centred prose, the callout shrinks to its text and sits in
   the middle of the slide. A short note in a full-width box read as lopsided.
   When a listing or a table stands above it, the rule below puts it back on
   that column so their left edges line up. */
.reveal blockquote {
  display: block;
  box-sizing: border-box;
  width: fit-content;
  max-width: var(--content-w);
  margin: var(--gap) auto 0;
  padding: 0.6em 1em;
  font-size: var(--fs-quote);
  font-style: normal;
  line-height: 1.5;
  text-align: left;
  color: var(--mist);
  background: linear-gradient(90deg, rgba(73, 201, 211, 0.09), rgba(73, 201, 211, 0.02));
  border-left: 3px solid var(--cyan);
  border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: none;
}

.reveal blockquote a {
  color: var(--cyan-bright);
  background-image: linear-gradient(var(--cyan-bright), var(--cyan-bright));
}

/* A listing or a table above: share their column, edge to edge */
.reveal section:has(pre) blockquote,
.reveal section:has(table) blockquote {
  width: var(--content-w);
}

/* Tables */

.reveal table {
  width: var(--content-w);
  margin: 0 auto;
  font-size: var(--fs-table);
  border-collapse: collapse;
  border-spacing: 0;
  text-align: left;
}

.reveal table th {
  font-family: var(--font-display);
  font-size: 0.92em;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--sand);
  padding: 0.5em 0.6em;
  border-bottom: 2px solid var(--edge);
}

.reveal table td {
  padding: 0.42em 0.6em;
  line-height: 1.4;
  border-bottom: 1px solid rgba(35, 55, 79, 0.75);
  vertical-align: top;
}

.reveal table tr:last-child td {
  border-bottom: 0;
}

/* First column carries the command or the path, so keep it on one line */
.reveal table td:first-child {
  color: var(--cyan);
  font-family: var(--font-mono);
  font-size: 0.92em;
  white-space: nowrap;
}

/* …except where the whole row is prose */
.reveal table td:only-child {
  color: inherit;
  font-family: inherit;
  white-space: normal;
}

/* Card */

.reveal .card {
  box-sizing: border-box;
  max-width: var(--content-w);
  margin: var(--gap) auto 0;
  padding: 0.7em 1.1em;
  background: var(--deep);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
}

/* Title slide */

.reveal .logo-link,
.reveal .logo-link:hover {
  display: block;
  text-decoration: none;
  background-image: none;
  padding: 0;
}

/* Fluid box holding the 600×200 logos. Square corners, deliberately. */
.logo-frame {
  position: relative;
  display: block;
  width: min(66%, 500px);
  max-width: 100%;
  aspect-ratio: 3 / 1;
  margin: 0 auto var(--gap);
  border-radius: 0;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.reveal .logo-link:hover .logo-frame {
  transform: translateY(-3px);
}

.logo-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}

@supports not (aspect-ratio: 3 / 1) {
  .logo-frame     { height: 0; padding-top: 33.333%; }
  .logo-frame img { position: absolute; top: 0; left: 0; }
}

/* Way back to the scrolling page.
   Same component as on the root page, in the colours of this deck:
   the root orange (#c44b16) only reaches 3.8:1 on this navy, so the badge
   uses --coral (7.1:1) and --cyan, exactly where the root uses orange and teal. */

/* Badge on the title slide, mirror of "Also available as slides" */
.reveal a.page-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  margin: 0 auto var(--gap);
  padding: 6px 18px;
  font-family: var(--font-body);
  /* A notch under the date line, and it follows the deck's phone sizes */
  font-size: calc(var(--fs-small) - 4px);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.4;
  color: var(--coral);
  background: linear-gradient(135deg, rgba(240, 132, 106, 0.10), rgba(73, 201, 211, 0.10));
  border: 1px solid rgba(240, 132, 106, 0.30);
  border-radius: 99px;
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
}

.reveal a.page-badge:hover {
  color: #ffa58f;
  border-color: rgba(240, 132, 106, 0.55);
  background: rgba(240, 132, 106, 0.14);
}

.reveal a.page-badge svg {
  flex-shrink: 0;
}

/* Sponsor slide */

/* The deck's only light slide. White, not a tint: obsd-ams.png is an opaque
   white PNG, and any tint would show a rectangle behind it. */
.reveal section[data-background-color="#ffffff"] h2 {
  color: #8a4d03;             /* --sand deepened, 5.5:1 on white     */
}

.reveal section[data-background-color="#ffffff"] h2::after {
  background: linear-gradient(90deg, #11607a, #2f8fd8 70%, transparent);
}

.reveal section[data-background-color="#ffffff"] p {
  color: #122a44;             /* 13.6:1                                      */
}

.reveal section[data-background-color="#ffffff"] a {
  color: #11607a;             /* --cyan deepened, 6.6:1              */
  background-image: linear-gradient(#11607a, #11607a);
}

.reveal section[data-background-color="#ffffff"] a:hover {
  color: #8a4d03;
  background-image: linear-gradient(#8a4d03, #8a4d03);
}

/* …but a sponsor logo is not a text link: the light-slide rule above out-ranks
   the sponsor rule, so the underline gradient has to be cancelled again here or
   it fills the whole anchor. */
.reveal section[data-background-color="#ffffff"] .sponsors a {
  background-image: none;
}

/* Sponsor row. The two marks are balanced on the height of their *ink*, not of
   their canvas: arp.png is a one-line wordmark whose ink fills 76% of its box,
   obsd-ams.png a two-line mark filling only 54% of a square box. Matching the
   boxes would make the second read half the size of the first. */
.sponsors {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px 72px;
  margin-top: 1.4em;
}

.reveal .sponsors a,
.reveal .sponsors a:hover {
  background-image: none;
  padding: 0;
  opacity: 0.86;
  transition: opacity 0.2s ease;
}

.reveal .sponsors a:hover {
  opacity: 1;
}

/* max-height, so each raster mark renders at its native size instead of being
   resampled, and anything taller added later is still reined in */
.sponsors img {
  display: block;
  width: auto;
  max-height: 34px;
}

.sponsors img.is-stacked {
  max-height: 69px;
}

/* Slide-specific rhythm */

/* Slide 4, the emoji list is centred as a block */
.reveal section:nth-child(4) div {
  display: inline-block;
  text-align: left;
  margin: 0 auto;
}

/* Command tables whose first column would otherwise crowd the description */
.reveal section:nth-child(54) table td:first-child,
.reveal section:nth-child(55) table td:first-child,
.reveal section:nth-child(56) table td:first-child { width: 34%; }
.reveal section:nth-child(57) table td:first-child { width: 40%; }

/* Reveal UI */

.reveal .controls {
  color: var(--cyan);
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  right: calc(18px + env(safe-area-inset-right, 0px));
}

.reveal .progress {
  height: 4px;
  color: var(--cyan);
  background: rgba(35, 55, 79, 0.65);
}

/* Centred along the bottom edge. Not a corner: reveal.js keeps its controls in
   the bottom right, and the corners are the first thing a case, a rounded
   screen or a notch takes away. The middle is the only stretch that stays
   clear on every device. */
.reveal .slide-number {
  right: auto;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  padding: 5px 11px;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--mist);
  background: rgba(11, 22, 38, 0.72);
  border: 1px solid var(--edge);
  border-radius: 999px;
}

/* Responsive */

/* reveal.js scales the 960×700 canvas down to fit the viewport, so on a phone
   everything shrinks with it. These breakpoints push the type back up, and
   because every rule above reads from a token, each breakpoint is one block,
   not a second copy of the stylesheet. */

@media screen and (max-width: 1024px) {
  :root {
    --fs-h2:    46px;
    --fs-body:  31px;
  }
}

/* A tablet is wide enough that reveal.js barely scales the canvas down, so the
   desktop type sizes already read well. Only the content column widens.
   Enlarging the type here used to overflow five slides: the canvas is a fixed
   700px tall, so every extra point of font size has to come out of the
   content. */
@media screen and (max-width: 768px) {
  :root {
    --content-w: 96%;
  }
}

@media screen and (max-width: 480px) {
  :root {
    --fs-h1:    50px;
    --fs-h2:    46px;
    --fs-h3:    29px;
    --fs-h4:    84px;
    --fs-h5:    28px;
    --fs-body:  32px;
    --fs-small: 21px;
    --fs-code:  19px;   /* le code ne grossit pas : il fait deborder les slides */
    --fs-quote: 21px;
    --fs-table: 26px;
    --content-w: 100%;
  }

  .logo-frame { width: min(94%, 420px); }

  /* fixed column widths stop helping once the table is this narrow */
  .reveal section:nth-child(54) table td:first-child,
  .reveal section:nth-child(55) table td:first-child,
  .reveal section:nth-child(56) table td:first-child,
  .reveal section:nth-child(57) table td:first-child { width: auto; }

  .reveal table td:first-child { white-space: normal; }
}

/* Phone held sideways: plenty of width, almost no height */
@media screen and (orientation: landscape) and (max-height: 500px) {
  :root {
    --fs-h1:    34px;
    --fs-h2:    34px;
    --fs-h3:    24px;
    --fs-h4:    62px;
    --fs-h5:    22px;
    --fs-body:  25px;
    --fs-small: 17px;
    --fs-code:  18px;
    --fs-quote: 18px;
    --fs-table: 22px;
    --gap:      12px;
  }

  .logo-frame { width: min(52%, 330px); }
}

/* Motion */

@media (prefers-reduced-motion: reduce) {
  .reveal a,
  .logo-frame,
  .sponsors a {
    transition: none;
  }

  .reveal .logo-link:hover .logo-frame {
    transform: none;
  }
}
