/* One sheet of the player's design system (tickets/T19-room-for-two.md).
   style.css keeps the fonts, the tokens and the reset; every area has its
   own file from there, linked in index.html in this order — the cascade is
   the order of the <link>s, not of a bundler. A ticket works in its sheet.
   No @import: it serialises the requests, which is the cost being avoided. */

/* ---------- The account drawer (tickets/T17-the-listener-comes-back.md) ------
   A panel in from the right on a desk, and on a phone a sheet that comes up
   under the deck and holds the rest of the screen (frames 1402:6679, 1402:6971,
   1402:7295, 1391:5959). The page behind is veiled and inert, not blurred: a
   radio one is listening to should stay readable while a name is being typed.

   THE CORNERS ARE APPLE'S, and they are two rules, not one:

   1. *Continuous*, not circular. A quarter-circle meets the straight edge with
      a sudden change of curvature, and the eye reads the seam. Apple's corner is
      a superellipse: the curve starts further along the edge and eases into the
      turn, so there is no seam to find. On the web that is `corner-shape`
      (`squircle` = `superellipse(2)`), and where it is not supported the plain
      `border-radius` underneath stays — a circular corner is the fallback, and
      nothing is polyfilled, masked or drawn in SVG for it.
   2. *Concentric*, once. It gave the keys inside the panel radius minus
      padding — 8 — and with it a second radius for the same key everywhere
      else is 4. The keys went back to radius/4 (tickets/T64-les-controles.md):
      a key is recognised by its corner before it is by its place.
   ------------------------------------------------------------------------- */
body.is-drawer { overflow: hidden; }
.drawer {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: flex;
  justify-content: flex-end;
  --pad-panel: 24px;   /* the card's and the Jam's measures: three panels, one setting (T64) */
  --r-panel: 24px;
}
.drawer[hidden] { display: none; }
.drawer::before { content: ""; position: absolute; inset: 0; background: var(--bg); opacity: 0.55; }
.drawer__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 24px;
  width: min(440px, calc(100vw - 32px));
  margin: 16px;
  padding: var(--pad-panel);
  border-radius: var(--r-panel);
  background: var(--bg);
  /* A hairline first, then the drop: on a dark page a shadow alone is nothing. */
  box-shadow: 0 0 0 1px var(--ink-muted), 0 24px 60px rgba(0, 0, 0, 0.16);
  overflow: hidden auto;
  scrollbar-width: none;
  /* No entrance of its own: it grows out of the key in the bar, the Jam's
     glass (lib/glass.js), and goes back into it. */
  --control-height: 48px;   /* every key in the panel is the small one, as in the column */
}
.drawer__panel::-webkit-scrollbar { display: none; }

/* The one place in the player with a corner big enough to read: the account's
   own surfaces. Everything else keeps radius/4 (DESIGN.md) — a 4 px corner is
   too small for the difference between a circle and a superellipse to exist. */
@supports (corner-shape: squircle) {
  .drawer__panel, .mine__art { corner-shape: squircle; }
}

/* The bar carries the head of the view at every width (frames 1391:5175,
   1402:6971): the title, and on the account the 16 face and the name — an
   address, when nobody has picked a name yet, so it is cut rather than
   allowed to push the close key off the end. */
.drawer__bar { display: flex; align-items: center; gap: 8px; min-height: 24px; }
/* The label is trimmed to its cap band (more.css), so cutting the overflow
   would cut the descenders with it: the padding hands the box back the room
   the trim took, the margin hands the row back the height. */
.drawer__bar .more__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  padding-block: 4px;
  margin-block: -4px;
}
.drawer__bar .face { width: 16px; height: 16px; }
.drawer__bar .face[hidden] { display: none; }
/* The way back: the chevron, and no box around it — a row of this drawer leads
   somewhere and comes back by the same glyph it goes out by (frame 1497:6074,
   which replaced the boxed arrow of 1391:5959). */
.drawer__back { position: relative; display: grid; place-items: center; flex: none; color: var(--ink); transition: color 160ms ease; }
/* The glyph is 20; the zone a finger or a hurried pointer gets is 44, as
   everywhere else on the page — the house rule of .more__close: the ZONE
   grows, the drawing does not. */
.drawer__back::before { content: ""; position: absolute; inset: -12px; }
.drawer__back[hidden] { display: none; }
@media (hover: hover) { .drawer__back:hover { color: var(--primary); } }

.drawer__view { display: flex; flex-direction: column; gap: 16px; flex: 1; animation: surface 0.7s var(--ease-soft) both; }
.drawer__view[hidden] { display: none; }
/* A face this browser already knows does not arrive: a view flipping in and
   out of display would replay the drop of more.css on every page of the
   drawer. The one face actually arriving is the address's, as it is typed. */
.drawer .face.is-on:not(#in-face) { animation: none; }
/* The head of a section: `Body/Label` — 10/16 capitals, the system's ONE
   uppercase style (DESIGN.md), the suit of the schedule, MONO / STEREO, the
   scale, VOLUME — words that name a setting. *On the air you are* is one.
   It used to be 14 capitals at 40 %, which is a style the system does not
   have, and it left a section's label louder than the paragraph it announces
   and as loud as the only key on the screen (tickets/T44).
   No colour of its own: in this drawer the hierarchy is carried by SIZE and
   by case alone, and every word is --ink. 10 capitals is already quiet. */
.drawer__kicker { font-size: 10px; line-height: 16px; text-transform: uppercase; text-box: trim-both cap alphabetic; }
.drawer__foot { margin-top: auto; padding-top: 16px; }
.drawer .btn--primary { width: 100%; }
/* "New suggestion" over the tabs (T70): the size below, the small key's 32 —
   a way in, not the panel's answer, so it hugs its word (T73). */
.drawer .mine__new { width: auto; align-self: flex-end; }   /* to the right (asked 07/10) */

/* The size alone: `.hint` already carries line-height 20, which is a
   PARAGRAPH's leading — `Body/UI Small` is 12/16 for one line of interface,
   not for three lines of prose. The 18 it used to declare was on no grid this
   project has, and the 55 % it faded to is gone with every other soft grey:
   a line of help is 12, and it is black like the rest (tickets/T44). */
.hint--small { font-size: 12px; }


/* A row: the whole width, the name, and the glyph that says it leads somewhere. */
.rows { display: flex; flex-direction: column; }
.row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 0;
  text-align: left;
  color: var(--ink);
  transition: color 160ms ease;
}
/* Body/UI — 14/16, which is the body's own reading and therefore nothing at
   all to declare (frame 1402:6971). It used to override to 16/24 and the rows
   stood 48 apart where the frame stands them 36; with the glyph now setting
   the row's height at 20, the padding keeps a 44 target and the rhythm comes
   back to the frame's without a hand-held number anywhere. */
.row__name { flex: 1; }
.row__count { font-size: 10px; line-height: 16px; text-transform: uppercase; }
/* The glyph that opens the row (frame 1402:6971). Its 8px of air is written
   here rather than on the row's own gap: the chevron at the far end keeps the
   row's 12, and the two spacings are not the same measure. */
.row__glyph { margin-right: -4px; }
/* The same dot as the bar's, in the row's gutter (T39 §3). One value, one
   size: two dots of different sizes for the same news would be two pieces of
   news. No number beside it — a count says how many, a dot says go and look. */
.row__dot { flex: none; width: 8px; height: 8px; border-radius: 999px; background: var(--primary); }
.row__dot[hidden] { display: none; }
/* Full ink, like the words beside it: the glyph is the row's other half, not
   its shadow (frames 1402:7274, 1402:7284). */
.row > .icon { flex: none; }
/* The colour alone answers the pointer: the chevron no longer steps aside
   (asked 07/10). */
@media (hover: hover) {
  .row:hover { color: var(--primary); }
}
/* A row lays itself out, so it also has to know how to disappear: the UA's
   [hidden] is `display: none` at no specificity at all, and the `display: flex`
   above beats it. Spelled out here for EVERY row rather than for one kind of
   row — *Connect Last.fm* stayed on screen next to *Scrobbling as …* because
   `.row--static[hidden]` covered the second and nothing covered the first. */
.row[hidden] { display: none; }
/* A row that states rather than opens. Every word of it is --ink, sentence
   and value alike: no grey stands in for hierarchy anywhere in this drawer
   (tickets/T44). What separates the two halves of the row is the ACCENT, and
   the accent is on the half you can press — the .cmd__link at its end. It
   used to be the other way round: a blue *in this page* nobody could click,
   beside a key drawn in the colour of the sentence, and the eye picked the
   wrong one every time.
   `font-weight: inherit` stays and is the whole rule now: it cancels the UA's
   bold, which Inter would have to synthesise — the family is loaded at 500
   only, so a real bold does not exist here. */
.row--static { color: var(--ink); cursor: default; }
@media (hover: hover) { .row--static:hover { color: var(--ink); } }   /* a row that is not a door does not light */
.row--static b { font-weight: inherit; }
/* The key at its end is written as the capsule's own mark (Saved): 10, capitals,
   the primary — one voice for what the account says back (T64). */
.row--static .cmd__link { font-size: 10px; line-height: 16px; text-transform: uppercase; }
.lfm[hidden] { display: none; }
.lfm { display: flex; flex-direction: column; gap: 16px; margin-top: 16px; }   /* 16 from a label to its control, 32 between two groups (T64) */
/* The refusal's line keeps its place in the column (more.css); in the drawer
   it left 52 of nothing under the name, and a group's gap is enough. */
.drawer .err[hidden] { display: none; }

/* The two keys over the list: a led each, the lit one is the list underneath
   (frames 1402:7295, 1391:5959). The deck's own key, whole — plinth, hover
   lift and all — only smaller: .btn--s is the button family's 28, a
   control-grey pill three of which share the row equally rather than hugging
   their own label (Segment/false, Segment/true). The one showing wears the
   component's pressed state, held: stage.css says what that is, once, for
   every key that stays down. */
.tabs { display: flex; gap: 4px; }
.tabs .action { display: flex; flex: 1; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
/* One sign for the one showing: filled with the ink, as the mood badge is. The
   led over it said the same thing as the held key, and the held key — darker,
   sunk — read as the one NOT chosen beside its raised neighbour (T64). */
.tabs .action > .led { display: none; }
.tabs .action[hidden] { display: none; }
.btn--s {
  --plinth-ink: rgba(0, 0, 0, 0.16);   /* a control-grey pill's plinth, as on .btn--secondary */
  height: 32px;   /* the small key's (T71) */
  padding-inline: 12px;
  width: 100%;
  background: var(--control);
}
/* Under a finger: 32 drawn, 48 reached — the small key's rule (stage.css, T71). */
.btn--s[aria-selected="true"], .btn--s[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
/* The held tab sinks its word 2, not the key's 3: filled with the ink it reads
   as chosen already, and the full sink looked dropped rather than pressed (T64). */
.btn--s[aria-selected="true"] > *, .btn--s[aria-pressed="true"] > * { transform: translateY(2px); }

/* Their own suggestions (frames 1454:1766 and 1402:7861). The sleeve is square
   — the only square thing on this surface, because a sleeve is a photograph and
   photographs are not rounded — 48 beside a stack of 48, and what the desk
   knows of the track sits at the far end of the title's own line, not in a
   column of its own beside both. The 12px gap between rows is the only
   separation — no rule. */
.mine { display: flex; flex-direction: column; gap: 12px; padding: 0; }   /* the <ol> default 40px indent was never reset here */
.mine__row {
  display: grid;
  grid-template-columns: 48px 1fr;
  align-items: center;
  /* 16 between the sleeve and the credits — and nothing between the credits and
     the word below: a shorthand `gap` here also spaced the two rows, and the
     word landed 28 under the artist (16 of row gap, 6 of margin, and the 6 the
     sleeve leaves under a two-line stack). The word carries its own 6. */
  column-gap: 16px;
  row-gap: 0;
}
.mine__art { width: 48px; height: 48px; object-fit: cover; background: var(--control); }
/* Your liked songs (T49): the same card, and the stage's small heart at its end
   in a third column — 32 square, like it is under the title (stage.css, T71). */
.liked__row { grid-template-columns: 48px 1fr auto; }
.liked__key { width: 32px; height: 32px; padding: 0; }
/* The stage's own .track, narrowed: its 220px is a stage width, and its 24px
   rows are a stage's air. Here the two lines are 16 apart with 4 between them
   — 20 from cap to cap, which is what the frame measures — and the column
   takes what the sleeve leaves. */
.mine__track { width: auto; min-width: 0; gap: 4px; }
.mine__track .track__row { height: 16px; }
/* The figures at the end of the line (T24, T31). The frame gives 4 between a
   glyph and its number *and* 4 between two chips — and at equal gaps the row
   reads as one run, where the number after a heart could belong to either
   side of it. The inner gap is the frame's; the outer one is three times it,
   so proximity says what belongs together. Three chips make it plain. */
/* A column each (T64): the chips are absent rather than zero, and a row with
   a third one slid the heart 35 px left of the rows without it. Each figure
   has its place, whether its neighbours are there or not. */
.mine__stats { display: grid; flex: none; grid-template-columns: repeat(3, 36px); column-gap: 8px; align-items: center; }
.mine__stat { display: flex; align-items: center; justify-content: flex-end; gap: 4px; text-box: trim-both cap alphabetic; }
.mine__stat[data-k="i-chart"] { grid-column: 1; }
.mine__stat[data-k="i-heart"] { grid-column: 2; }
.mine__stat[data-k="i-user"] { grid-column: 3; }

/* ---------- Updates (tickets/T39-la-nouvelle-arrive-dans-la-page.md) -------
   The frame's measures, left to right: the witness at 8, 12, the sleeve at 32,
   12, and the column of words — the label and the hour on one line, the desk's
   word under it. 16 between two rows, and no rule: the same separation the
   suggestions use. */
.feed { display: flex; flex-direction: column; gap: 16px; padding: 0; padding-right: 8px; }
/* Top, not centre — and the column below carries the 32 instead. A short row
   then centres itself against the sleeve; a long word overruns 32, starts at
   the top, and the sleeve and the witness stay on its first line. Two cases,
   one declaration, and nothing measuring the length of anything. */
.feed__row { position: relative; display: flex; align-items: flex-start; gap: 12px; }
/* Read, it does not turn grey: it goes to nothing, and keeps its 8 in the row
   — the frame's own measures, so every sleeve of the list stands on the same
   edge, read or not. It hung in the panel's margin for a while, to line the
   sleeves up with the other views; that put it 4 px off the panel's edge and
   the sleeves left of the way back. A grey would be a third value to read. */
.feed__dot {
  flex: none;
  margin-top: 12px;   /* onto the first line's middle: (32 − 8) / 2 */
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--primary);
  transition: opacity 240ms ease;
}
.feed__row:not(.is-fresh) .feed__dot { opacity: 0; }
/* A sleeve is a photograph, and photographs are not rounded — .mine__art's own
   rule at 32 instead of 48. Gone missing, the square stays and no glyph breaks. */
.feed__art { flex: none; width: 32px; height: 32px; object-fit: cover; background: var(--control); }
.feed__body { display: flex; flex: 1; flex-direction: column; justify-content: center; gap: 8px; min-width: 0; min-height: 32px; }
/* Trimmed boxes, both of them: the frame's 8 between the label and the word is
   cap to cap, and untrimmed 12/16 boxes would put 8 on top of their own
   leading. Same reading as .drawer__kicker and .mine__stat. */
.feed__line { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 12px; line-height: 16px; letter-spacing: -0.035em; text-box: trim-both cap alphabetic; }
.feed__kind { min-width: 0; }
.feed__at { flex: none; white-space: nowrap; }
/* The word the desk left, wrapped whole (the frame of 23/09 shows four lines
   of it). No clamp, no ellipsis, no marquee: a word somebody took the time to
   write is read in full, and here only — Your suggestions no longer quotes it.
   The italic against the label above is enough to tell it apart. */
.feed__word { font-size: 12px; line-height: 16px; letter-spacing: -0.035em; font-style: italic; text-box: trim-both cap alphabetic; }

/* The key in the bar: a user glyph until somebody is signed in, their own face
   after — 16, like every other glyph up there. */
.hit--me .face { width: 16px; height: 16px; }
.hit--me .face[hidden] { display: none; }
.hit--me .face:not([hidden]) + .icon { display: none; }

/* …and once in, the name they go by (tickets/T25-the-bar-knows-you.md). The
   key stops being square and becomes a capsule: face, then name. Never the
   address — the bar is on screen all day, the drawer is opened on purpose.
   `width: auto` because .hit is a 16 x 16 box by default.
   And full ink, against the bar's default: .hit is muted because a key up
   there is OFF — no stop to stop, mono when it is stereo. Signed out is not
   off, it is this key at rest, the one state it is in for a listener who has
   never signed in. Dimming it says the radio is unavailable (style.css, on
   --ink-muted). It is linked after page.css and responsive.css, so this wins. */
.hit--me { position: relative; flex: none; width: auto; grid-auto-flow: column; gap: 4px; color: var(--ink); }
/* Whole, never cut: a name is 24 characters at most as a pseudonym (the
   desk's limit) and 25 as a guest's ("Periwinkle Graduation Cap", T41), so
   the room is made in the bar — the place and the temperature go first, under
   1200 — and not by clipping the end of somebody. It was 14ch, which cut
   « Periwinkle Paint Brush » to « …Brus ». */
.me__name {
  white-space: nowrap;
  /* Body/Meta — 12/16, normal case: the very thing the clock and the place next
     to it are (frame 1495:2905, tickets/T40-la-rangee-de-droite.md). It was
     10px UPPERCASE with positive tracking, which is the suit of a LABEL (MONO,
     STEREO, VOLUME — words that name a setting). A pseudonym is not a label,
     it is somebody. The tracking is written here and not inherited: a <button>
     does not take the body's letter-spacing from the UA sheet, so the name sat
     at 0 while the clock beside it was tracked. −0.035em is Body/Meta's −3.5 %,
     the frame's −0.42 at this size. */
  font-size: 12px;
  line-height: 16px;
  letter-spacing: -0.035em;
  /* Text in this row reads at full ink — the clock and the place do, and in
     dark mode the muted one the key inherits for its glyph is 18 % white,
     which is a shape you can make out and not a word you can read. */
  color: var(--ink);
}
.me__name[hidden] { display: none; }

/* The desk answered something since the list was last read. A dot, not a
   figure: it says "go and look", and a number would have to be right.
   It used to hang on the corner of the face; the frame makes it a MEMBER of
   the row — 8px, after the name, 8 clear of it (`témoin — rangée`, 1495:2905,
   tickets/T40-la-rangee-de-droite.md). Beyond the frame, that corner was the
   one place in the bar where something sat ON something else: a dot lapping a
   16px face eats a quarter of it. Beside it, it eats nothing and reads better —
   and when the name goes under 900 (responsive.css, T25) the dot stays in the
   row behind the face instead of needing a corner to exist on.
   The 4 is the row's own gap: 4 + 4 = the frame's 8. */
.me__dot {
  margin-left: 4px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--primary);
}
.me__dot[hidden] { display: none; }

/* Their own track just went on the air (T39 §5). One breath of the key, and
   back to rest: this is a moment, not a debt — so no dot, no sound, and
   nothing to dismiss. */
.hit--me.is-air { animation: air-breath 900ms var(--ease-soft) 1; }
@keyframes air-breath {
  0%, 100% { color: var(--ink); }
  30% { color: var(--primary); }
}

@media (prefers-reduced-motion: reduce) {
  .hit--me.is-air { animation: none; }
}

/* ---------- The phone: a sheet, not a card ---------------------------------
   It comes up under the deck and keeps the rest of the screen, edge to edge,
   with only its top corners turned (frames 1402:*). The deck stays above it:
   the radio goes on playing, and its keys are still there behind the veil. */
@media (max-width: 640px) {
  .drawer { --r-panel: 32px; }   /* the card's sheet: 32 on the top corners (about.css) */
  .drawer__panel {
    width: 100%;
    margin: 0;
    margin-top: auto;   /* anchored to the bottom edge: the sheet grows from it */
    /* It starts under the deck and keeps everything below: the radio's own
       keys stay on screen, the sheet is the rest (frames 1402:*). */
    height: calc(100dvh - 72px);
    padding-bottom: max(var(--pad-panel), env(safe-area-inset-bottom));
    border-radius: var(--r-panel) var(--r-panel) 0 0;
    box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.12), 0 0 0 1px var(--ink-muted);
  }
}

@media (prefers-reduced-motion: reduce) {
  .drawer__view { animation: none; }
  .row, .row > .icon, .drawer__back { transition: none; }
}
