/* The banner's right-hand controls — the theme switch and the kebab menu.
   ============================================================
   Loaded on every page by both systems: base.njk links it, and
   lib/legacy-chrome.mjs injects it beside keys.css. The markup is in
   _includes/partials/banner-tools.njk and, verbatim, in legacy-chrome's
   banner(); keep the three in step.

   Desktop only. Below 1280 the banner is 48px with the hamburger at one end,
   and the floating .theme-toggle sits in the top right already; two theme
   controls on one screen is one too many.

   Everything here has to read against the banner's #23004D, which is darker
   than either theme's paper — so the colours are written out rather than
   taken from the theme tokens, and they do not change when the theme does.
   The switch's state is what changes. */

/* ---- the banner's call to action ----
   Outside the desktop-only block below: the button is on every screen, and so
   is its drawn edge.

   The same hand as the switch beside it, and the same font as the switch's
   label — but where that label is a caption on a control, this is the one
   thing on the bar anybody is meant to press. So it takes the weight and the
   contrast the label deliberately does not: 700 against 400, and full white
   against 62%. The character is in the line, not in the type.

   The edge is baked geometry rather than generated, for the reason the
   switch's frame is: one button at one size on every page has nothing for a
   per-element seed to vary. It is hand-ink's own output for a 128x36 box —
   which is that module's judgement of how much licence a box this small can
   carry, and why it is a single pass rather than two (below 46px on the short
   side, two strokes a pixel apart read as one heavy one rather than as a line
   gone over twice). */
/* The question stays in the sans — a second mono line here would compete with
   the mono heading below it. What it does take from the button is a weight
   that can stand next to 700: at 300 it read as a caption that had drifted in
   from another design. Up to 400, down a point, and dimmed a little, so the
   two read as a sentence and its answer rather than as two things that happen
   to be adjacent. */
.gs-banner p {
  font-weight: 400;
  font-size: 15px;
  letter-spacing: 0.01em;
  color: rgba(255, 255, 255, 0.78);
}
@media (max-width: 600px) {
  .gs-banner p { font-size: 13.5px; }
}

.gs-banner .gs-btn-box {
  position: relative;
  border: 0;
  border-radius: 0;
  /* the strokes overshoot the corners, so the box cannot clip its own edge */
  overflow: visible;
}
.gs-btn-ink {
  position: absolute;
  left: -4px;
  top: -4px;
  width: calc(100% + 8px);
  height: calc(100% + 8px);
  overflow: visible;
  pointer-events: none;
  fill: none;
}
.gs-btn-ink path {
  /* Off full white, and a hair thinner. At 1.6px of pure white it was the
     brightest thing on the screen and pulled against the heading below it;
     the button should be the first thing you find when you look for it, not
     the first thing you see. Hover puts both back. */
  stroke: rgba(255, 255, 255, 0.72);
  stroke-width: 1.4;
  stroke-linecap: round;
  /* the viewBox is stretched to whatever the words measure; without this the
     stroke stretches with it and the verticals come out heavier than the
     horizontals */
  vector-effect: non-scaling-stroke;
  transition: stroke-width 0.18s ease, stroke 0.18s ease;
}
.gs-banner .gs-btn-box a {
  position: relative;
  font-family: "Roboto Mono", ui-monospace, Menlo, monospace;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.9);
}
/* No fill on hover: a straight-edged rectangle behind a wobbled line shows its
   corners through. The line thickens instead, which is what a hand does. */
.gs-banner .gs-btn-box:hover { background: none; }
.gs-banner .gs-btn-box:hover .gs-btn-ink path {
  stroke: #ffffff;
  stroke-width: 2;
}
.gs-banner .gs-btn-box:hover a { color: #ffffff; }
.gs-banner .gs-btn-box a:focus-visible { outline: 2px solid #ffffff; outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .gs-btn-ink path { transition: none; }
}

.gs-tools { display: none; }
.gs-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (min-width: 1280px) {
  /* The banner centres its message; these sit at the end of the bar rather
     than in the flow of it, so the message stays centred on the screen and
     not on what is left of it.
     Both rules wait for js/banner-tools.js to set data-gs-tools: without it
     the switch and the menu would render and do nothing, and the floating
     button they replace would already be hidden. An attribute rather than a
     class because the exported instructor reports assign <html>'s className
     outright when the theme changes — see the note in banner-tools.js. */
  html[data-gs-tools] .gs-tools {
    display: flex;
    align-items: center;
    gap: 4px;
    position: absolute;
    top: 50%;
    right: 18px;
    transform: translateY(-50%);
  }

  /* ---- the switch ----
     The walkthroughs' toggle, drawn: a wobbled frame with a dot in it. Off is
     light mode, on is dark, and the dot crosses when it flips. */
  .gs-switch {
    display: flex;
    align-items: center;
    gap: 0.5em;
    padding: 4px 6px;
    border: 0;
    border-radius: 6px;
    background: none;
    cursor: pointer;
    line-height: 0;
  }
  .gs-switch svg { display: block; overflow: visible; }

  /* What it is, not what it does — the reading a physical switch gets. Set in
     the mono the rest of the site labels in, and quiet enough to be a caption
     on the control rather than a second button beside it.

     Both words are in the markup and the theme class picks one, so the label
     is right in the first frame: the class is resolved in <head> (see
     lib/theme-bootstrap.mjs), long before js/banner-tools.js runs, and a
     label that flickered from "dark" to "light" on every load would be worse
     than none. */
  .gs-switch-label {
    font-family: "Roboto Mono", ui-monospace, Menlo, monospace;
    font-size: 0.68rem;
    line-height: 1;
    letter-spacing: 0.1em;
    color: rgba(255, 255, 255, 0.55);
    transition: color 0.2s ease;
  }
  .gs-switch-label i { font-style: normal; }
  .gs-switch-label .gs-d,
  html.dark-mode .gs-switch-label .gs-l { display: none; }
  html.dark-mode .gs-switch-label .gs-d { display: inline; }
  .gs-switch:hover .gs-switch-label { color: rgba(255, 255, 255, 0.85); }
  .gs-switch-frame {
    fill: none;
    stroke: rgba(255, 255, 255, 0.62);
    stroke-width: 1.6;
    stroke-linecap: round;
    transition: stroke 0.25s ease;
  }
  .gs-switch-dot {
    fill: #ffffff;
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), fill 0.25s ease;
  }
  .gs-switch[aria-checked="true"] .gs-switch-frame { stroke: rgba(255, 255, 255, 0.92); }
  .gs-switch[aria-checked="true"] .gs-switch-dot {
    transform: translateX(18px);
    fill: #b9bcff;
  }
  .gs-switch:hover .gs-switch-frame { stroke: #ffffff; }

  /* ---- the kebab ---- */
  .gs-more { position: relative; }
  .gs-kebab {
    display: block;
    padding: 4px 8px;
    border: 0;
    border-radius: 6px;
    background: none;
    cursor: pointer;
    line-height: 0;
  }
  .gs-kebab svg { display: block; }
  .gs-kebab circle { fill: rgba(255, 255, 255, 0.62); transition: fill 0.2s ease; }
  .gs-kebab:hover circle,
  .gs-kebab[aria-expanded="true"] circle { fill: #ffffff; }

  .gs-switch:focus-visible,
  .gs-kebab:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 1px;
  }

  /* ---- the menu ----
     Hangs off the bar rather than sitting in it, so it takes the page's own
     paper rather than the banner's purple.

     Which means asking two page systems for the same colour under two sets of
     names: the templated pages have --text-strong and --surface-raised, the
     legacy ones --text-color and --card-bg, and neither knows the other's.
     Hence the chains — the first name that resolves wins, and the literal at
     the end is for a page that carries neither. */
  .gs-more-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 1310;
    min-width: 13.5rem;
    margin: 0;
    padding: 0.3rem;
    list-style: none;
    background: var(--surface-raised, var(--card-bg, #ffffff));
    border: 1px solid var(--border-subtle, var(--border-color, #dedcd7));
    border-radius: 8px;
    box-shadow: 0 10px 28px -12px rgba(0, 0, 0, 0.45);
  }
  .gs-more-menu[hidden] { display: none; }
  /* Guide, peering over the edge of the panel. Decorative and aria-hidden —
     it is not a control and does not go anywhere; it is there for whoever
     opens the menu. */
  .gs-guide {
    position: absolute;
    /* At the far end of the panel, where there is nothing above it but empty
       bar: the controls are all at the other end, and a mortarboard through
       the switch frame reads as a rendering fault rather than as a joke.
       High enough, too, that the hat stays inside the banner rather than
       being cut by its bottom edge. */
    top: -25px;
    left: 14px;
    pointer-events: none;
  }
  .gs-more-menu button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.8rem;
    width: 100%;
    padding: 0.5rem 0.65rem;
    border: 0;
    border-radius: 5px;
    background: none;
    color: var(--text-strong, var(--text-color, #111118));
    font: inherit;
    font-size: 0.88rem;
    text-align: left;
    cursor: pointer;
  }
  /* A tint rather than a token: --button-hover-bg exists on the legacy pages
     and not the templated ones, and this reads on either paper.

     So does the ring, which is here because opening the menu moves focus to
     its first item and the browser's own ring is a blue that belongs to
     neither theme. Keyed to :focus rather than :focus-visible: focus arrives
     here programmatically, so after a mouse press on the kebab the item is
     focused and does not match :focus-visible — the rule was written that way
     first and never applied. */
  .gs-more-menu button:hover,
  .gs-more-menu button:focus { background: rgba(128, 128, 160, 0.18); }
  .gs-more-menu button:focus {
    outline: 2px solid #7a7ae0;
    outline-offset: -2px;
  }
  .gs-more-menu kbd {
    font-family: "Roboto Mono", ui-monospace, Menlo, monospace;
    font-size: 0.74em;
    padding: 0.1em 0.42em;
    border: 1px solid currentColor;
    border-radius: 3px;
    opacity: 0.7;
  }

  /* The floating button this replaces. Hidden rather than dropped: the page's
     own theme handler is bound to it, and the switch above presses it. */
  html[data-gs-tools] .theme-toggle { display: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .gs-switch-frame,
  .gs-switch-dot { transition: none; }
}
