/* =============================================================================
   annotate.css — the look of a callout on the model.

   Pairs with annotate.js, which writes ONLY transform, opacity, z-index and
   display; everything a callout looks like is here, so the module carries its
   own appearance rather than borrowing a page stylesheet's.

   A PAGE ON kodo.css DOES NOT LINK THIS FILE. kodo.css @imports it, so every
   lesson and every generated app has callout styling whether or not anyone
   remembered — which matters because components are growing notes a generated
   page turns on, and an unstyled callout there lands on nothing. The six pages
   still on bench.css link it themselves; that is the whole of the direct-link
   list, and it shrinks as they migrate.


   IT HAS TO SIT RIGHT IN BOTH, and the two hosts do not agree about corners:
   the site sheet flattens everything to 4px, the lesson shell rounds to 12-14.
   So the shapes below read `--annot-radius`, which each host sets and this file
   only defaults. Everything else is a semantic token with a literal fallback,
   because the pages still on bench.css load this file too and bench.css has no
   --accent. A callout is the same object on every page; only its corners and
   its accent are the room's.
   ========================================================================== */

/* Declared on `body` and not on :root ON PURPOSE. lesson-shell.css sets its own
   --accent on `body.lshell-page`, and a token resolved at :root would have read
   the site's green while sitting on the shell's paper. */
body {
   --annot-live: var(--accent, #3d6fb0);
   --annot-radius: var(--radius-md, 4px);
   /* THE LINES A CALLOUT DRAWS, in one place, and TWO WEIGHTS. A leader only
      has to join a label to its point, so it stays the quieter line; a
      bracket's rule IS the measurement, and it is read as a drawing over the
      model rather than followed from one end. Both are darker than the
      hairline the leader used to borrow — a hairline is right for a rule
      between blocks of text on paper and disappears over a lit 3D scene. */
   --annot-line: var(--text-muted, #6d6f76);
   --annot-rule: var(--text-dim, #55585f);
}
@supports (color: color-mix(in srgb, red, blue)) {
   body { --annot-live-dark: color-mix(in srgb, var(--annot-live) 76%, #000) }
}

.annot-layer {
   position: absolute;
   inset: 0;
   overflow: hidden;
   pointer-events: none;
   z-index: 7
}

/* Positioned by transform at the anchor's projected point; the dot is
    centred ON that point and the label hangs off it. */
.annot {
   position: absolute;
   top: 0;
   left: 0;
   will-change: transform, opacity
}

.annot-dot {
   position: absolute;
   left: -5px;
   top: -5px;
   width: 10px;
   height: 10px;
   padding: 0;
   border-radius: 50%;
   border: 1px solid var(--text-strong);
   background: var(--surface-raised);
   box-shadow: 0 1px 3px rgba(20, 22, 26, .18);
   cursor: default
}

.annot-layer.is-click .annot-dot {
   cursor: pointer
}

.annot-layer.is-click .annot-dot:hover,
.annot-dot:focus-visible {
   background: var(--text-strong);
   outline: none
}

/* The leader. A drawn line rather than a gap, so a label reads as
    BELONGING to its dot even where several are close together — which on a
    single heme they always are. Length and angle are solved by annotate.js
    when the note is added and handed over as --alen/--aang. */
.annot-leader {
   position: absolute;
   left: 0;
   top: 0;
   height: 0;
   width: var(--alen, 18px);
   border-top: 1px solid var(--annot-line);
   transform-origin: 0 0;
   transform: rotate(var(--aang, 0deg));
   pointer-events: none
}

.annot-label {
   position: absolute;
   left: 0;
   top: 0;
   transform: translate(var(--adx, 18px), var(--ady, 0px)) translateY(-50%);
   white-space: nowrap;
   padding: 5px 11px;
   font-family: var(--font-ui);
   font-size: 13px;
   /* 500, not 600: system-ui's semibold at 13px on a translucent chip is a bar,
      and every other small label in the system is set at 500. */
   font-weight: 500;
   line-height: 1.2;
   color: var(--text-strong);
   background: rgba(255, 255, 255, .88);
   backdrop-filter: blur(6px);
   border: 1px solid var(--border-hair);
   /* A PILL, in both rooms. It is the one shape the site sheet and the lesson
      shell already agree on — .fact, .chip, .cta and .segmented are all capsules
      — so a label needs no --annot-radius to belong. */
   border-radius: 999px;
   box-shadow: 0 2px 8px -2px rgba(20, 22, 26, .16);
   opacity: 1;
   transition: opacity .18s ease
}

/* Left-hand callouts: the label hangs off the other side of its offset, so
    the text ends at the leader instead of starting on top of it. */
.annot-left .annot-label {
   transform: translate(var(--adx, -18px), var(--ady, 0px)) translate(-100%, -50%)
}

/* ---- measuring brackets --------------------------------------------------
   A dimension line drawn across a gap, with the measurement sitting on it.
   annotate.js writes the path, the transform and opacity; the weight and the
   type are here. The rule is HAIRLINE and the chip is the label's own shape at
   a size down, so a bracket reads as a measurement laid over the model rather
   than as another thing in it. */
.annot-spans {
   position: absolute;
   inset: 0;
   width: 100%;
   height: 100%;
   overflow: visible;
   pointer-events: none
}

.annot-span-ext {
   fill: none;
   stroke: var(--annot-rule);
   stroke-width: 1;
   stroke-dasharray: 2 3;
   opacity: .5;
   vector-effect: non-scaling-stroke
}

.annot-span-line {
   fill: none;
   stroke: var(--annot-rule);
   stroke-width: 1.25;
   stroke-linecap: round;
   vector-effect: non-scaling-stroke;
   /* A HALO, because the rule is drawn over the model and a hairline crossing a
      dark sphere disappears into it. Cheaper and steadier than an underlay
      path, which has to be kept in sync with the one it sits behind. */
   filter: drop-shadow(0 0 2px rgba(255, 255, 255, .95))
}

/* Centred ON the middle of the rule — annotate.js puts the point in the
   transform and the -50%,-50% that follows it is what centres the chip there,
   so it masks the line it sits on instead of being cut by it. */
.annot-span-label {
   position: absolute;
   top: 0;
   left: 0;
   white-space: nowrap;
   padding: 2px 8px;
   font-family: var(--font-ui);
   font-size: 11.5px;
   font-weight: 500;
   font-variant-numeric: tabular-nums;
   line-height: 1.2;
   color: var(--text-strong);
   background: rgba(255, 255, 255, .9);
   border: 1px solid var(--border-hair);
   border-radius: 999px;
   box-shadow: 0 1px 5px -2px rgba(20, 22, 26, .18);
   pointer-events: none
}

/* Turned away from the camera. The note is faded to nothing by the facing
    test in annotate.js; this only stops the invisible dot taking a click that
    belongs to the model behind it. */
.annot.is-away, .annot.is-away .annot-dot {
   pointer-events: none
}

/* Closed is the click mode's resting state: the dot stays, the label
    goes. Kept in the layout (not display:none) so opening it costs no
    reflow and the fade has something to fade. */
.annot:not(.is-open) .annot-label {
   opacity: 0;
   pointer-events: none
}

/* Tones. A callout naming the iron should carry the iron's ink, the way
    every other coloured thing on these pages does. */
.annot-iron .annot-dot {
   border-color: #a8321a
}

.annot-iron .annot-label {
   color: #8d2a16
}

/* Cobalt, off the palette token rather than typed: tokens-from-palette.js
    publishes --atom-Co at load, so this callout and the sphere it points at
    cannot drift. Teal is dark enough on the house cream to be label ink as
    well as dot, which is why there is no second, darkened number here. */
.annot-cobalt .annot-dot {
   border-color: var(--atom-Co)
}

.annot-cobalt .annot-label {
   color: var(--atom-Co)
}

/* Oxygen, the same way: a callout naming hydroxyls carries the ink of the
    atoms it is pointing at. */
.annot-oxygen .annot-dot {
   border-color: var(--atom-O)
}

.annot-oxygen .annot-label {
   color: var(--atom-O)
}

/* Cards. The label says what, the card says why, and the label has to say
    "there is a why" while nobody is pointing at it — a hover-only tell is
    invisible to the student who has not already found the label.

    So: a bead before the text, breathing until that card has been opened once.
    It is deliberately not an underline (a dashed one reads as an error squiggle
    under a two-word label) and not a button shape (that competes with the real
    controls in the chrome). With up to four callouts on a stage, a small mark
    and its pulse is as loud as this may get.

    The bead is in the LABEL, never on the leader: the dot on the line is the
    anchor saying which atom this names, and a dot that also meant "click me"
    would be saying two things at one point.

    `is-seen` comes from annotate.js — set the first time a card opens, never
    removed — and it is what stops the pulse asking for something already done.

    --annot-live IS THE ROOM'S ACCENT, not a blue of its own. It was #3d6fb0,
    which belonged to nothing: the deep green on a site page, the shell's
    brighter green on a lesson-shell one. A lesson can still move it in one
    line, and the pulse below follows whatever it is set to. */

.annot-has-card .annot-label {
   display: inline-flex;
   align-items: center;
   gap: 7px;
   cursor: pointer;
   transition: opacity .18s ease, background .15s ease, border-color .15s ease
}

.annot-has-card .annot-label::before {
   content: "";
   flex: none;
   width: 8px;
   height: 8px;
   border-radius: 50%;
   background: var(--annot-live)
}

.annot-has-card:not(.is-seen) .annot-label::before {
   --annot-ring: rgba(61, 111, 176, .55);
   animation: annotbead 2.1s ease-out infinite
}
@supports (color: color-mix(in srgb, red, blue)) {
   .annot-has-card:not(.is-seen) .annot-label::before {
      --annot-ring: color-mix(in srgb, var(--annot-live) 55%, transparent)
   }
}

/* The ring is drawn from the bead's own colour, so a room that moves the accent
   takes the pulse with it. currentColor cannot do this: the bead is a ::before
   with no text, and its `color` is the label's ink. */
@keyframes annotbead {
   0% { box-shadow: 0 0 0 0 var(--annot-ring) }
   70% { box-shadow: 0 0 0 8px transparent }
   100% { box-shadow: 0 0 0 0 transparent }
}

@media (prefers-reduced-motion: reduce) {
   .annot-has-card:not(.is-seen) .annot-label::before { animation: none }
}

.annot-has-card .annot-label:hover::before { background: var(--annot-live-dark, #2d5688) }

.annot-has-card .annot-label:hover,
.annot-has-card .annot-label:focus-visible {
   background: #fff;
   border-color: var(--text-strong);
   outline: none
}

/* The card grows out of the label and covers it, so the label underneath
    shows through the card's own translucency: its border, and whatever of the
    text is wider than the card's title. HIDDEN, NOT REMOVED — annotate.js
    places the card from this element's own box, and display:none would take
    that box away and drop the card on the origin. The matching pointer-events
    is set in annotate.js, which puts an inline `auto` on a carded label that
    no rule here can outrank. */
.annot-has-card.is-carded .annot-label {
   opacity: 0
}

.annot-has-card .annot-dot {
   cursor: pointer
}

.annot-has-card.is-carded .annot-dot {
   background: var(--text-strong)
}

/* Positioned by transform like a callout, but it is the one child of the
    layer that takes the mouse: it has a close button and text worth
    selecting. Sized so a third sentence has to be scrolled to — which is
    the point, not a limitation. */
.annot-card {
   position: absolute;
   top: 0;
   left: 0;
   width: 248px;
   padding: 13px 15px 14px;
   background: var(--panel, #fff);
   border: 1px solid var(--border-hair);
   /* The one shape that cannot be a pill, so it takes the room's corner. */
   border-radius: var(--annot-radius);
   box-shadow: var(--shadow-panel, 0 10px 26px -10px rgba(20, 22, 26, .22));
   opacity: 0;
   visibility: hidden;
   transform-origin: 0 0;
   transition: opacity .16s ease;
   z-index: 400;
   will-change: transform
}

.annot-card.is-open {
   opacity: 1;
   visibility: visible
}

.annot-card-t {
   margin: 0 18px 6px 0;
   /* THE MICRO-CAP, which is the system's only heading device outside prose:
      same face, tracking, weight and colour as every other label on the page.
      A callout that invented its own would be a third treatment for one job. */
   font-family: var(--font-display, var(--font-ui));
   font-size: var(--cap-sm, 10px);
   font-weight: var(--cap-weight, 600);
   letter-spacing: var(--cap-track, .22em);
   text-transform: uppercase;
   color: var(--text-muted)
}

.annot-card-b {
   margin: 0;
   /* Prose in a card is prose. --font-editorial is Literata on both hosts; the
      fallback is for a page still on a sheet that has no editorial face. */
   font-family: var(--font-editorial, var(--font-ui));
   font-size: 13.5px;
   line-height: 1.5;
   color: var(--text-body, var(--text-strong))
}

.annot-card-b b {
   font-weight: 600
}

.annot-card-x {
   position: absolute;
   top: 6px;
   right: 6px;
   width: 22px;
   height: 22px;
   padding: 0;
   border: 0;
   border-radius: 50%;
   background: none;
   font-size: 17px;
   line-height: 1;
   color: var(--text-muted);
   cursor: pointer
}

.annot-card-x:hover,
.annot-card-x:focus-visible {
   background: var(--border-hair);
   color: var(--text-strong);
   outline: none
}

@media (prefers-reduced-motion:reduce) {
   .annot-label {
     transition: none
   }

   .annot-card {
     transition: none
   }
}
