/* ────────────────────────────────────────────────────────────────────────────
   site.css — interaction states for the Dossier components.

   In the design-system bundle these lived in React useState (hover / press /
   focus). Rendered as plain HTML the component styles are inline, so the
   states have to be reasserted here with !important.

   Loaded BEFORE the page's own <style> block on purpose: the page overrides
   specific buttons ([data-btn="goldFill"] and friends) and those must win.
   ──────────────────────────────────────────────────────────────────────────── */

[hidden] { display: none !important; }

/* ── Button ─────────────────────────────────────────────────────────────── */
.ds-btn[data-variant="primary"]:hover { background: var(--primary-hover) !important; }
.ds-btn[data-variant="primary"]:active { background: var(--primary-pressed) !important; }

.ds-btn[data-variant="secondary"]:hover { background: var(--surface-raised) !important; border-color: var(--primary) !important; }
.ds-btn[data-variant="secondary"]:active { background: var(--surface-sunken) !important; border-color: var(--primary-pressed) !important; color: var(--primary-pressed) !important; }

.ds-btn[data-variant="onSteel"]:hover { background: var(--secondary-hover) !important; }
.ds-btn[data-variant="onSteel"]:active { background: var(--secondary) !important; }


/* The two portfolio tabs are onSteel buttons, but the active one is repainted
   inline with its project's accent — LiberiOltre red, AI automations orange.
   The generic rule above would slam that to the gold on hover, so the tab you
   were already standing on flashed a colour belonging to no project at all.
   It now lifts inside its own hue. --accent is set on #work by renderPanel(),
   so each tab picks up the right one on its own.

   The fill only lifts a little: #C12033 carries its label at 5.43 contrast, so
   anything lighter than about 92% white-mix drops the label under 4.5 and
   fails AA. The visible half of the hover is therefore the ring, which no text
   sits on and can go as light as it likes. */
.ds-btn[data-variant="onSteel"][aria-pressed="true"]:hover {
  background: color-mix(in oklch, var(--accent) 92%, #FFFFFF) !important;
  border-color: color-mix(in oklch, var(--accent) 55%, #FFFFFF) !important;
}
.ds-btn[data-variant="onSteel"][aria-pressed="true"]:active {
  background: color-mix(in oklch, var(--accent) 88%, #000000) !important;
  border-color: color-mix(in oklch, var(--accent) 70%, #FFFFFF) !important;
}

.ds-btn[data-variant="ghostOnSteel"]:hover { background: var(--steel-raised) !important; border-color: var(--on-steel) !important; }
.ds-btn[data-variant="ghostOnSteel"]:active { background: var(--steel-raised) !important; }

.ds-btn[disabled] { opacity: .55; cursor: not-allowed; }

/* ── TextLink ───────────────────────────────────────────────────────────── */
.ds-textlink:hover { color: var(--ink); }

/* ── Input ──────────────────────────────────────────────────────────────── */
.ds-input:focus {
  border-color: var(--primary) !important;
  outline: var(--focus-width) solid var(--focus-ring) !important;
}
.ds-input::placeholder { color: var(--paper-500); opacity: 1; }

/* ── keyboard focus, everywhere ─────────────────────────────────────────── */
:where(button, a, [data-act], [data-chip], [data-tabbtn], [data-catbtn]):focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* the nav items and the wordmark are real controls */
[data-nav], [data-cuenote] { cursor: pointer; }
[data-act] { cursor: pointer; }

/* ── skip link ──────────────────────────────────────────────────────────── */
.skip-link {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 100;
  background: var(--primary); color: var(--on-primary);
  padding: 12px 20px; font-weight: 700; text-decoration: none;
}
.skip-link:focus { inset-inline-start: 0; }

/* ── the lucide <i> placeholder must not collapse before the sprite draws ── */
.ds-icon i[data-lucide] { flex: none; }
.ds-icon svg { display: block; }

/* ══ small-screen behaviour ═══════════════════════════════════════════════

   The prototype was drawn on a desktop canvas. Everything below is about the
   same markup on a phone or tablet — it changes no desktop pixel.
   ════════════════════════════════════════════════════════════════════════ */

/* ── rows whose right-hand value cannot shrink ──────────────────────────────
   Experience, education and the LinkedIn row put a white-space:nowrap value
   opposite a title with justify-content:space-between. Neither side can give,
   so in any narrow column — a 360px phone, or the 320px sidebar on a 1180px
   tablet — the value pushed the whole page sideways. Letting the line wrap
   costs nothing where they already fit. */
[data-row] > div > div[style*="justify-content:space-between"] { flex-wrap: wrap; }

@media (max-width: 600px) {
  /* below this the two never share a line, so give the value its own row
     instead of leaving it stranded beside a three-line title */
  [data-row] > div > div[style*="justify-content:space-between"] { display: block !important; }
  [data-row] > div > div[style*="justify-content:space-between"] > *:last-child {
    display: block;
    margin-top: 2px;
  }

  /* the contact rows: label block over the "Open profile" link */
  div:has(> [data-linkgroup]) { display: block !important; }
  [data-linkgroup] { margin-top: 10px; }
}

/* ── the mobile menu ────────────────────────────────────────────────────────
   Built by buildMenu() in app.js. The wordmark plus four nav items need about
   560px; under 768px the row wrapped onto three or four lines and the sticky
   header ate a fifth of the screen. */
[data-burger] { display: none; }
[data-menupanel] { display: none; }

@media (max-width: 767px) {
  [data-head] nav { display: none !important; }

  [data-burger] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 48px;
    height: 48px;
    margin-inline-end: -12px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text-heading);
    cursor: pointer;
  }
  [data-register="steel"] [data-burger] { color: var(--on-steel); }

  [data-burger-box] { position: relative; display: block; width: 24px; height: 16px; }
  [data-burger-box] span {
    position: absolute;
    inset-inline: 0;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
    transition: transform 220ms var(--ease-out-strong), opacity 120ms linear;
  }
  [data-burger-box] span:nth-child(1) { top: 0; }
  [data-burger-box] span:nth-child(2) { top: 7px; }
  [data-burger-box] span:nth-child(3) { top: 14px; }
  [data-burger][aria-expanded="true"] [data-burger-box] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  [data-burger][aria-expanded="true"] [data-burger-box] span:nth-child(2) { opacity: 0; }
  [data-burger][aria-expanded="true"] [data-burger-box] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  [data-menupanel] {
    display: block;
    position: absolute;
    top: 100%;
    inset-inline: 0;
    padding: 6px 0 10px;
    background: var(--surface-page);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 18px 30px -22px rgba(0, 0, 0, .45);
  }
  [data-menupanel][hidden] { display: none; }
  [data-register="steel"] [data-menupanel] { background: var(--steel); border-color: var(--steel-border); }

  [data-menuitem] {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 52px;
    padding-inline: var(--space-lg, 24px);
    border: 0;
    background: transparent;
    color: #5C5C5C;
    font-size: 15px;
    font-weight: 700;
    text-align: start;
    cursor: pointer;
  }
  [data-menuitem][data-on] { color: #000000; }
  [data-register="steel"] [data-menuitem] { color: #B3B3B3; }
  [data-register="steel"] [data-menuitem][data-on] { color: var(--on-steel); }
}

@media (max-width: 767px) and (hover: hover) and (pointer: fine) {
  [data-menuitem]:hover { background: var(--surface-raised); color: #000000; }
}

/* ── touch targets ──────────────────────────────────────────────────────────
   44px is the Apple minimum and roughly a fingertip. The nav items and the
   two links carry an underline marker pinned to the text box, so they are
   grown with a transparent ::before overlay rather than padding, which would
   drag the marker down with it. */
@media (pointer: coarse) {
  [data-nav]::before,
  [data-wordmark]::before,
  [data-gotopost]::before,
  [data-linkgroup] .ds-textlink::before {
    content: "";
    position: absolute;
    inset-block: -14px;
    inset-inline: -8px;
  }
  [data-gotopost],
  [data-linkgroup] .ds-textlink { position: relative; }

  [data-tabbtn],
  [data-catbtn],
  [data-cuebtn],
  [data-chip] { min-height: 44px; }
}

/* ── the hero flag ──────────────────────────────────────────────────────────
   One flag, one file, no breakpoint anywhere. Everything here is a continuous
   function of the viewport, so dragging the window narrower shrinks the flag
   smoothly instead of swapping it for a different crop at 1024px — that swap
   was visible as a jump.

   The file is 100% flag: _build/optimise-assets.js crops the pale border off
   the clip once, at build time. That is what removes the margin that used to
   sit between the flag and the right edge of the screen — there is no longer
   any non-flag pixel that could land there.

   --flag-w is the straight line through the two widths that matter: 440px of
   flag at 1440 (what the desktop already had) down to 110px at 390 (a phone).
   Capped at 440 so a wide monitor does not turn the hero into a poster, and
   floored at 96 so it stays readable as a flag on the narrowest phone. */
#home [data-hero-grid] {
  --flag-w: clamp(72px, calc(33.8vw - 47px), 440px);
  grid-template-columns: minmax(0, 1fr) var(--flag-w) !important;
  align-items: stretch;
}

/* the cell carries inline padding and a 20px nudge, both sized for a hero
   that letterboxed the flag inside a smaller box; full-bleed wants neither */
#home [data-flag-cell] {
  display: block !important;
  padding: 0 !important;
  top: 0 !important;
}

/* The height is the whole trick. object-fit: cover scales by whichever axis
   is tighter, so a column that is merely tall makes the flag enormous and
   shows a sliver of it — three giant stars, no flag. Feeding it a height that
   tracks the WIDTH keeps the flag at a sane scale:

     calc(var(--flag-w) * 1.308)  is the flag box (1052:1376) drawn whole,
     55vh                         is the floor that lets it start cropping
                                  once the column gets too narrow to show the
                                  flag whole at a useful size,
     100%                         never taller than the hero row.

   At 1440 the first term wins and the desktop shows the entire flag, exactly
   as it did before, but flush to the screen edge. Below roughly 1100 the 55vh
   floor takes over and the flag crops in gradually. max() and min() of two
   continuous functions are continuous, so there is no step anywhere.

   Whatever height is left under the flag is a ~110px column of page
   background against page background — it reads as margin, not as a gap. */
#home [data-video-slot="eu-flag"] {
  width: 100% !important;
  height: min(100%, max(calc(var(--flag-w) * 1.308), 55vh)) !important;
}

/* 55% keeps the star arc in frame as the crop tightens. The inline transform
   is what the old fitFlag() drove; nothing sets those custom properties now,
   but neutralise it so nothing can. */
#home [data-video-slot="eu-flag"] video,
#home [data-video-slot="eu-flag"] img {
  object-position: 55% center !important;
  transform: none !important;
}

/* the copy loses width to the flag, so give it back the gutter it was
   spending on a margin that is now the flag itself */
@media (max-width: 1024px) {
  #home [data-hero-grid] > *:first-child { padding-right: 24px !important; }
}

/* ── the hero on a phone ────────────────────────────────────────────────────
   The hero is a two-column row at every width, so on a phone the copy is
   reading against a hard ceiling: whatever the flag does not take. At the
   prototype's inline 22px the lede came out at ~17 characters a line and ran
   15 lines, which pushed both call-to-action buttons below the fold on a
   360x780 and a 390x844 screen — nobody scrolling in sees a button.

   19px/1.6 is not a new size: it is `body-lg` from DESIGN.md, the token this
   paragraph already claims with class="type-body-lg" before an inline style
   overrides it. Putting it back is what buys the lines. The rest is trimmed
   off the vertical rhythm, which was scaled for a desktop hero.

   The measure is still tighter than the 68-character cap DESIGN.md sets for
   body copy — a phone next to a flag column cannot reach that — but ~22
   characters reads far better than 17. */
@media (max-width: 767px) {
  #home [data-lede] {
    font-size: 19px !important;
    line-height: 1.6 !important;
    margin-top: 16px !important;
  }

  /* the display size is set for a 1440 hero; 34px still clears the lede by a
     full step and saves a line of wrapping */
  #home [data-hero-grid] h1 { font-size: 34px !important; }

  /* both of these are desktop rhythm: 40px of air above the buttons and the
     cell's own top padding, on a screen that has none to spare */
  #home [data-hero-grid] > *:first-child { padding-block-start: 24px !important; }
}
